-
Notifications
You must be signed in to change notification settings - Fork 857
FreeSql实现了强大功能的同时,性能没有受到影响,项目中使用反射或耗时的操作都经过了缓存处理。读取数据部分采用了ExpressionTree,使得FreeSql解析实体数据的速度与Dapper非常接近。
| | 18W+52C | 1W+52C | 5K+52C | 2K+52C | 1K+52C | 500+52C | 100+52C | 50+52C | | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | | MySql 5.5 ExecuteAffrows | 55,497ms | 4,953ms | 2,304ms | 2,554ms | 1,516ms | 1,572ms | 265ms | 184ms | | SqlServer Express ExecuteAffrows | 402,355ms | 24,847ms | 11,465ms | 4,971ms | 2,437ms | 915ms | 138ms | 88ms | | SqlServer Express ExecuteSqlBulkCopy | 21,065ms | 578ms | 326ms | 139ms | 105ms | 79ms | 60ms | 48ms | | PostgreSQL 10 ExecuteAffrows | 46,756ms | 3,294ms | 2,269ms | 1,019ms | 374ms | 209ms | 51ms | 37ms | | PostgreSQL 10 ExecutePgCopy | 10,090ms | 583ms | 337ms | 136ms | 88ms | 61ms | 30ms | 25ms | | Oracle XE ExecuteAffrows | - | - | - | - | 24,528 | 10,648ms | 571ms | 200ms | | Sqlite ExecuteAffrows | 28,554ms | 1,149ms | 701ms | 327ms | 155ms | 91ms | 44ms | 35ms |
18W+52C 解释:插入18万行记录,表字段有52个
Oracle 插入性能不用怀疑,可能安装学生版限制较大
提醒:开源数据库测试结果比较有意义,商业数据库版本之间性能可能有较大差距
18W+10C | 1W+10C | 5K+10C | 2K+10C | 1K+10C | 500+10C | 100+10C | 50+10C | |
---|---|---|---|---|---|---|---|---|
MySql 5.5 ExecuteAffrows | 15,380ms | 1,813ms | 1,457ms | 1,254ms | 563ms | 246ms | 55ms | 21ms |
SqlServer Express ExecuteAffrows | 47,204ms | 2,275ms | 1,108ms | 488ms | 279ms | 123ms | 35ms | 16ms |
SqlServer Express ExecuteSqlBulkCopy | 4,248ms | 127ms | 71ms | 30ms | 48ms | 14ms | 11ms | 10ms |
PostgreSQL 10 ExecuteAffrows | 9,786ms | 568ms | 336ms | 157ms | 102ms | 34ms | 9ms | 6ms |
PostgreSQL 10 ExecutePgCopy | 4,081ms | 167ms | 93ms | 39ms | 21ms | 12ms | 4ms | 2ms |
Oracle XE ExecuteAffrows | - | - | - | - | 2,394 | 731ms | 67ms | 33ms |
Sqlite ExecuteAffrows | 4,524ms | 246ms | 137ms | 94ms | 35ms | 19ms | 14ms | 11ms |
测试结果,是在相同操作系统下进行的,并且都有预热
public class TestInsert10c
{
[Column(MapType = typeof(string))]
public Guid Id { get; set; }
public string UserName0 { get; set; }
public string PassWord0 { get; set; }
public DateTime CreateTime0 { get; set; }
public string UserName1 { get; set; }
public string PassWord1 { get; set; }
public DateTime CreateTime1 { get; set; }
public string UserName2 { get; set; }
public string PassWord2 { get; set; }
public DateTime CreateTime2 { get; set; }
}
IFreeSql mysql = new FreeSql.FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=100")
//由于null会默认输出日志到控制台,影响测试结果。这里传入一个空的日志输出对象
.UseAutoSyncStructure(false)
//关闭自动迁移功能
.Build();
class Song {
public int Id { get; set; }
public string Title { get; set; }
public string Url { get; set; }
public DateTime Create_time { get; set; }
public bool Is_deleted { get; set; }
}
测试方法:运行两次,以第二次性能报告,避免了首个运行慢不公平的情况。
数量 | Query<Class> | Query<Tuple> | Query<dynamic> | |
---|---|---|---|---|
Dapper.Query(sql) | 131072 | 623.4959ms | 424.2411ms | 644.8897ms |
FreeSql.Query(sql) | 131072 | 647.0552ms | 577.3532ms | 944.7454ms |
FreeSql.ToList | 131072 | 622.8980ms | 435.3532ms | - |
FreeSql以微小的性能差距输了,原因是支持了更多的类型,某些类型解析需要Parse、递归或循环处理。
由于Dapper没有批量插入/更新/删除的功能,并且都是执行一条SQL命令,测试结果没有意义。
FreeSql批量插入使用的命令:INSERT INTO Song (...) VALUES(...),VALUES(...),VALUES(...)...
[Fact]
public void QueryEntity() {
var sb = new StringBuilder();
var time = new Stopwatch();
time.Restart();
List<Song> dplist1 = null;
using (var conn = g.mysql.Ado.MasterPool.Get()) {
dplist1 = Dapper.SqlMapper.Query<Song>(conn.Value, "select * from song").ToList();
}
time.Stop();
sb.AppendLine($"Elapsed: {time.Elapsed}; Query Entity Counts: {dplist1.Count}; ORM: Dapper");
time.Restart();
var t3 = g.mysql.Ado.Query<Song>("select * from song");
time.Stop();
sb.AppendLine($"Elapsed: {time.Elapsed}; Query Entity Counts: {t3.Count}; ORM: FreeSql*");
}
[Fact]
public void QueryTuple() {
var sb = new StringBuilder();
var time = new Stopwatch();
time.Restart();
List<(int, string, string)> dplist2 = null;
using (var conn = g.mysql.Ado.MasterPool.Get()) {
dplist2 = Dapper.SqlMapper.Query<(int, string, string)>(conn.Value, "select * from song").ToList();
}
time.Stop();
sb.AppendLine($"Elapsed: {time.Elapsed}; Query Tuple Counts: {dplist2.Count}; ORM: Dapper");
time.Restart();
var t4 = g.mysql.Ado.Query<(int, string, string)>("select * from song");
time.Stop();
sb.AppendLine($"Elapsed: {time.Elapsed}; Query Tuple Counts: {t4.Count}; ORM: FreeSql*");
}
[Fact]
public void QueryDynamic() {
var sb = new StringBuilder();
var time = new Stopwatch();
time.Restart();
List<dynamic> dplist3 = null;
using (var conn = g.mysql.Ado.MasterPool.Get()) {
dplist3 = Dapper.SqlMapper.Query<dynamic>(conn.Value, "select * from song").ToList();
}
time.Stop();
sb.AppendLine($"Elapsed: {time.Elapsed}; Query Dynamic Counts: {dplist3.Count}; ORM: Dapper");
time.Restart();
var t5 = g.mysql.Ado.Query<dynamic>("select * from song");
time.Stop();
sb.AppendLine($"Elapsed: {time.Elapsed}; Query Dynamic Counts: {t3.Count}; ORM: FreeSql*");
}
[Fact]
public void QueryList() {
var sb = new StringBuilder();
var time = new Stopwatch();
time.Restart();
var t3 = g.mysql.Select<Song>().ToList();
time.Stop();
sb.AppendLine($"Elapsed: {time.Elapsed}; ToList Entity Counts: {t3.Count}; ORM: FreeSql*");
time.Restart();
List<Song> dplist1 = null;
using (var conn = g.mysql.Ado.MasterPool.Get()) {
dplist1 = Dapper.SqlMapper.Query<Song>(conn.Value, "select * from song").ToList();
}
time.Stop();
sb.AppendLine($"Elapsed: {time.Elapsed}; Query Entity Counts: {dplist1.Count}; ORM: Dapper");
}
更多测试源码:FreeSql/FreeSql.Tests.PerformanceTests/MySqlAdoTest.cs