From 105947c2ed69a2a7162b53db069656b1fb6f6734 Mon Sep 17 00:00:00 2001 From: 2881099 <2881099@qq.com> Date: Wed, 1 Jun 2022 14:21:53 +0800 Subject: [PATCH] Optimize single table read performance --- Examples/orm_vs/Program.cs | 123 ++++++++++-- FreeSql.DbContext/FreeSql.DbContext.xml | 9 - FreeSql/FreeSql.xml | 183 ------------------ .../SelectProvider/Select0Provider.cs | 14 ++ .../SelectProvider/Select0ProviderReader.cs | 12 -- .../FreeSql.Provider.MySql/MySqlProvider.cs | 2 + .../PostgreSQLProvider.cs | 5 +- .../SqlServerProvider.cs | 5 + .../FreeSql.Provider.Sqlite/SqliteProvider.cs | 5 + 9 files changed, 139 insertions(+), 219 deletions(-) diff --git a/Examples/orm_vs/Program.cs b/Examples/orm_vs/Program.cs index f1259d36..10facd16 100644 --- a/Examples/orm_vs/Program.cs +++ b/Examples/orm_vs/Program.cs @@ -1,4 +1,6 @@ -using FreeSql.Internal; +using Dapper; +using FreeSql.Internal; +using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using SqlSugar; using System; @@ -12,14 +14,15 @@ using System.Linq.Expressions; using System.Text; using System.Threading; using System.Threading.Tasks; +using FreeSql; namespace orm_vs { class Program { static IFreeSql fsql = new FreeSql.FreeSqlBuilder() - //.UseConnectionString(FreeSql.DataType.SqlServer, "Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Max Pool Size=20") - .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=20") + .UseConnectionString(FreeSql.DataType.SqlServer, "Data Source=.;Integrated Security=True;Initial Catalog=tedb;Pooling=true;Max Pool Size=20") + //.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=20") //.UseConnectionString(FreeSql.DataType.PostgreSQL, "Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=tedb;Pooling=true;Maximum Pool Size=20") .UseAutoSyncStructure(false) .UseNoneCommandParameter(true) @@ -32,19 +35,19 @@ namespace orm_vs { var db = new SqlSugarClient(new ConnectionConfig() { - //ConnectionString = "Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Min Pool Size=20;Max Pool Size=20", - //DbType = DbType.SqlServer, - ConnectionString = "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Min Pool Size=20;Max Pool Size=20", - DbType = DbType.MySql, + ConnectionString = "Data Source=.;Integrated Security=True;Initial Catalog=tedb;Pooling=true;Min Pool Size=20;Max Pool Size=20", + DbType = DbType.SqlServer, + //ConnectionString = "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Min Pool Size=20;Max Pool Size=20", + //DbType = DbType.MySql, //ConnectionString = "Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=tedb;Pooling=true;Maximum Pool Size=21", //DbType = DbType.PostgreSQL, IsAutoCloseConnection = true, InitKeyType = InitKeyType.Attribute }); - db.Aop.OnLogExecuting = (sql, pars) => - { - Console.WriteLine(sql);//输出sql,查看执行sql - }; + //db.Aop.OnLogExecuting = (sql, pars) => + //{ + // Console.WriteLine(sql);//输出sql,查看执行sql + //}; return db; } } @@ -52,10 +55,11 @@ namespace orm_vs class SongContext : DbContext { public DbSet Songs { get; set; } + public DbSet PatientExamination_2022s { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - //optionsBuilder.UseSqlServer(@"Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Min Pool Size=21;Max Pool Size=21"); - optionsBuilder.UseMySql("Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Min Pool Size=21;Max Pool Size=21"); + optionsBuilder.UseSqlServer(@"Data Source=.;Integrated Security=True;Initial Catalog=tedb;Pooling=true;Min Pool Size=21;Max Pool Size=21"); + //optionsBuilder.UseMySql("Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Min Pool Size=21;Max Pool Size=21"); //optionsBuilder.UseNpgsql("Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=tedb;Pooling=true;Maximum Pool Size=21"); } @@ -69,8 +73,101 @@ namespace orm_vs } } + //CREATE TABLE [dbo].[PatientExamination_2022] ( + // [Id] uniqueidentifier NOT NULL, + // [CreateTime] datetime NOT NULL, + // [ExamKindId] uniqueidentifier NOT NULL, + // [ExamKindName] nvarchar(255) COLLATE Chinese_PRC_CI_AS NULL, + // [PatientGuid] uniqueidentifier NOT NULL, + // [PatientName] nvarchar(255) COLLATE Chinese_PRC_CI_AS NULL, + // [AnesthesiaType] int NOT NULL, + // [DiaRoomId] uniqueidentifier NULL, + // [DiaRoomName] nvarchar(255) COLLATE Chinese_PRC_CI_AS NULL, + // [QueueIndex] int NOT NULL, + // [QueueNum] int NOT NULL, + // [OrderDateTime] datetime NOT NULL, + // [TimeType] int NOT NULL, + // [SignInTime] datetime NULL, + // [StartCheckTime] datetime NULL, + // [EndCheckTime] datetime NULL, + // [VerifyTime] datetime NULL, + // [ReportTime] datetime NULL, + // [ExaminationState] int NOT NULL + //) + [Table("PatientExamination_2022")] + class PatientExamination_2022 + { + public Guid Id { get; set; } + public DateTime CreateTime { get; set; } + public Guid ExamKindId { get; set; } + public string ExamKindName { get; set; } + public Guid PatientGuid { get; set; } + public string PatientName { get; set; } + public int AnesthesiaType { get; set; } + public Guid? DiaRoomId { get; set; } + public string DiaRoomName { get; set; } + public int QueueIndex { get; set; } + public int QueueNum { get; set; } + public DateTime OrderDateTime { get; set; } + public int TimeType { get; set; } + public DateTime? SignInTime { get; set; } + public DateTime? StartCheckTime { get; set; } + public DateTime? EndCheckTime { get; set; } + public DateTime? VerifyTime { get; set; } + public DateTime? ReportTime { get; set; } + public int ExaminationState { get; set; } + } + + static void TestFreeSqlSelectPatientExamination_2022() + { + var list = fsql.Select().Limit(40000).ToList(); + //var list = fsql.Ado.Query("select top 40000 * from PatientExamination_2022"); + } + static void TestEfSelectPatientExamination_2022() + { + using (var ctx = new SongContext()) + { + var list = ctx.PatientExamination_2022s.Take(40000).AsNoTracking().ToList(); + } + } + static void TestSqlSugarSelectPatientExamination_2022() + { + var list = sugar.Queryable().Take(40000).ToList(); + } + static void TestDapperSelectPatientExamination_2022() + { + using (var conn = new SqlConnection("Data Source=.;Integrated Security=True;Initial Catalog=tedb;Pooling=true;Min Pool Size=21;Max Pool Size=22")) + { + var list = conn.Query("select top 40000 * from PatientExamination_2022"); + } + } + + static DbConnection fsqlConn = null; static void Main(string[] args) { + var count = 0; + var sws = new List(); + Console.WriteLine("观察查询4万条记录内存,按 Enter 进入下一次,按任易键即出程序。。。"); + //while(Console.ReadKey().Key == ConsoleKey.Enter) + //using (var fcon = fsql.Ado.MasterPool.Get()) + //{ + //fsqlConn = fcon.Value; + for (var a = 0; a < 80; a++) + { + Stopwatch sw = Stopwatch.StartNew(); + TestFreeSqlSelectPatientExamination_2022(); + //TestEfSelectPatientExamination_2022(); + //TestSqlSugarSelectPatientExamination_2022(); + //TestDapperSelectPatientExamination_2022(); + sw.Stop(); + sws.Add(sw.ElapsedMilliseconds); + Console.WriteLine($"第 {++count} 次,查询4万条记录, {sw.ElapsedMilliseconds}ms,平均 {(long)sws.Average()}ms"); + } + //} + Console.ReadKey(); + fsql.Dispose(); + return; + //fsql.CodeFirst.SyncStructure(typeof(Song), typeof(Song_tag), typeof(Tag)); //sugar.CodeFirst.InitTables(typeof(Song), typeof(Song_tag), typeof(Tag)); //sugar创建表失败:SqlSugar.SqlSugarException: Sequence contains no elements diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index 1ab5bf1c..6b638cad 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -795,14 +795,5 @@ - - - 批量注入 Repository,可以参考代码自行调整 - - - - - - diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index 2db205b7..3866a367 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -3303,177 +3303,6 @@ - - - 测试数据库是否连接正确,本方法执行如下命令: - MySql/SqlServer/PostgreSQL/达梦/人大金仓/神通: SELECT 1 - Oracle: SELECT 1 FROM dual - - 命令超时设置(秒) - - true: 成功, false: 失败 - - - - 查询,若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】 - - - - - - - - - - 查询,ExecuteReaderAsync(dr => {}, "select * from user where age > @age", new { age = 25 }) - 提示:parms 参数还可以传 Dictionary<string, object> - - - - - - - - - 查询 - - - - - - - - - 查询,ExecuteArrayAsync("select * from user where age > @age", new { age = 25 }) - 提示:parms 参数还可以传 Dictionary<string, object> - - - - - - - - - 查询 - - - - - - - - - 查询,ExecuteDataSetAsync("select * from user where age > @age; select 2", new { age = 25 }) - 提示:parms 参数还可以传 Dictionary<string, object> - - - - - - - - - 查询 - - - - - - - - - 查询,ExecuteDataTableAsync("select * from user where age > @age", new { age = 25 }) - 提示:parms 参数还可以传 Dictionary<string, object> - - - - - - - - - 在【主库】执行 - - - - - - - - - 在【主库】执行,ExecuteNonQueryAsync("delete from user where age > @age", new { age = 25 }) - 提示:parms 参数还可以传 Dictionary<string, object> - - - - - - - - - 在【主库】执行 - - - - - - - - - 在【主库】执行,ExecuteScalarAsync("select 1 from user where age > @age", new { age = 25 }) - 提示:parms 参数还可以传 Dictionary<string, object> - - - - - - - - - 执行SQL返回对象集合,QueryAsync<User>("select * from user where age > @age", new SqlParameter { ParameterName = "age", Value = 25 }) - - - - - - - - - - - 执行SQL返回对象集合,QueryAsync<User>("select * from user where age > @age", new { age = 25 }) - 提示:parms 参数还可以传 Dictionary<string, object> - - - - - - - - - - 执行SQL返回对象集合,Query<User>("select * from user where age > @age; select * from address", new SqlParameter { ParameterName = "age", Value = 25 }) - - - - - - - - - - - - 执行SQL返回对象集合,Query<User, Address>("select * from user where age > @age; select * from address", new { age = 25 }) - 提示:parms 参数还可以传 Dictionary<string, object> - - - - - - - - 可自定义解析表达式 @@ -4480,12 +4309,6 @@ 超时 - - - 获取资源 - - - 使用完毕后,归还资源 @@ -4561,12 +4384,6 @@ 资源对象 - - - 从对象池获取对象成功的时候触发,通过该方法统计或初始化对象 - - 资源对象 - 归还对象给对象池的时候触发 diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs index 6f7a0fea..d262f0c7 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs @@ -174,6 +174,20 @@ namespace FreeSql.Internal.CommonProvider return exp; } + public static MethodInfo _MethodDataReaderIsDBNull = typeof(DbDataReader).GetMethod("IsDBNull", new Type[] { typeof(int) }); + public static Dictionary _dicMethodDataReaderGetValue = new Dictionary + { + [typeof(bool)] = typeof(DbDataReader).GetMethod("GetBoolean", new Type[] { typeof(int) }), + [typeof(int)] = typeof(DbDataReader).GetMethod("GetInt32", new Type[] { typeof(int) }), + [typeof(long)] = typeof(DbDataReader).GetMethod("GetInt64", new Type[] { typeof(int) }), + [typeof(double)] = typeof(DbDataReader).GetMethod("GetDouble", new Type[] { typeof(int) }), + [typeof(float)] = typeof(DbDataReader).GetMethod("GetFloat", new Type[] { typeof(int) }), + [typeof(decimal)] = typeof(DbDataReader).GetMethod("GetDecimal", new Type[] { typeof(int) }), + [typeof(DateTime)] = typeof(DbDataReader).GetMethod("GetDateTime", new Type[] { typeof(int) }), + [typeof(string)] = typeof(DbDataReader).GetMethod("GetString", new Type[] { typeof(int) }), + //[typeof(Guid)] = typeof(DbDataReader).GetMethod("GetGuid", new Type[] { typeof(int) }) 有些驱动不兼容 + }; + public static MethodInfo MethodStringContains = typeof(string).GetMethod("Contains", new[] { typeof(string) }); public static MethodInfo MethodStringStartsWith = typeof(string).GetMethod("StartsWith", new[] { typeof(string) }); public static MethodInfo MethodStringEndsWith = typeof(string).GetMethod("EndsWith", new[] { typeof(string) }); diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select0ProviderReader.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select0ProviderReader.cs index c3140924..370525bd 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select0ProviderReader.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select0ProviderReader.cs @@ -748,18 +748,6 @@ namespace FreeSql.Internal.CommonProvider }; }); } - static MethodInfo _MethodDataReaderIsDBNull = typeof(DbDataReader).GetMethod("IsDBNull", new Type[] { typeof(int) }); - static Dictionary _dicMethodDataReaderGetValue = new Dictionary - { - [typeof(bool)] = typeof(DbDataReader).GetMethod("GetBoolean", new Type[] { typeof(int) }), - [typeof(int)] = typeof(DbDataReader).GetMethod("GetInt32", new Type[] { typeof(int) }), - [typeof(long)] = typeof(DbDataReader).GetMethod("GetInt64", new Type[] { typeof(int) }), - [typeof(double)] = typeof(DbDataReader).GetMethod("GetDouble", new Type[] { typeof(int) }), - [typeof(float)] = typeof(DbDataReader).GetMethod("GetFloat", new Type[] { typeof(int) }), - [typeof(decimal)] = typeof(DbDataReader).GetMethod("GetDecimal", new Type[] { typeof(int) }), - [typeof(DateTime)] = typeof(DbDataReader).GetMethod("GetDateTime", new Type[] { typeof(int) }), - [typeof(string)] = typeof(DbDataReader).GetMethod("GetString", new Type[] { typeof(int) }), - }; protected double InternalAvg(Expression exp) { diff --git a/Providers/FreeSql.Provider.MySql/MySqlProvider.cs b/Providers/FreeSql.Provider.MySql/MySqlProvider.cs index 8002e559..f1ed6f12 100644 --- a/Providers/FreeSql.Provider.MySql/MySqlProvider.cs +++ b/Providers/FreeSql.Provider.MySql/MySqlProvider.cs @@ -34,6 +34,8 @@ namespace FreeSql.MySql } return null; }); + + Select0Provider._dicMethodDataReaderGetValue[typeof(Guid)] = typeof(DbDataReader).GetMethod("GetGuid", new Type[] { typeof(int) }); } public override ISelect CreateSelectProvider(object dywhere) => new MySqlSelect(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere); diff --git a/Providers/FreeSql.Provider.PostgreSQL/PostgreSQLProvider.cs b/Providers/FreeSql.Provider.PostgreSQL/PostgreSQLProvider.cs index fe845f8b..3ee230ca 100644 --- a/Providers/FreeSql.Provider.PostgreSQL/PostgreSQLProvider.cs +++ b/Providers/FreeSql.Provider.PostgreSQL/PostgreSQLProvider.cs @@ -21,7 +21,6 @@ namespace FreeSql.PostgreSQL public class PostgreSQLProvider : BaseDbProvider, IFreeSql { - static PostgreSQLProvider() { Utils.dicExecuteArrayRowReadClassOrTuple[typeof(BigInteger)] = true; @@ -104,7 +103,9 @@ namespace FreeSql.PostgreSQL Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJsonConvertDeserializeObject, Expression.Convert(valueExp, typeof(string)), Expression.Constant(type, typeof(Type))), type)), Expression.Return(returnTarget, Expression.TypeAs(Expression.Call(MethodJsonConvertDeserializeObject, Expression.Convert(Expression.Call(MethodToString, valueExp), typeof(string)), Expression.Constant(type, typeof(Type))), type))); return null; - }); + }); + + Select0Provider._dicMethodDataReaderGetValue[typeof(Guid)] = typeof(DbDataReader).GetMethod("GetGuid", new Type[] { typeof(int) }); } public override ISelect CreateSelectProvider(object dywhere) => new PostgreSQLSelect(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere); diff --git a/Providers/FreeSql.Provider.SqlServer/SqlServerProvider.cs b/Providers/FreeSql.Provider.SqlServer/SqlServerProvider.cs index 3e7e6667..bb26187b 100644 --- a/Providers/FreeSql.Provider.SqlServer/SqlServerProvider.cs +++ b/Providers/FreeSql.Provider.SqlServer/SqlServerProvider.cs @@ -9,6 +9,11 @@ namespace FreeSql.SqlServer public class SqlServerProvider : BaseDbProvider, IFreeSql { + static SqlServerProvider() + { + Select0Provider._dicMethodDataReaderGetValue[typeof(Guid)] = typeof(DbDataReader).GetMethod("GetGuid", new Type[] { typeof(int) }); + } + public override ISelect CreateSelectProvider(object dywhere) => new SqlServerSelect(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere); public override IInsert CreateInsertProvider() => new SqlServerInsert(this, this.InternalCommonUtils, this.InternalCommonExpression); public override IUpdate CreateUpdateProvider(object dywhere) => new SqlServerUpdate(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere); diff --git a/Providers/FreeSql.Provider.Sqlite/SqliteProvider.cs b/Providers/FreeSql.Provider.Sqlite/SqliteProvider.cs index 24a82779..b28631fc 100644 --- a/Providers/FreeSql.Provider.Sqlite/SqliteProvider.cs +++ b/Providers/FreeSql.Provider.Sqlite/SqliteProvider.cs @@ -9,6 +9,11 @@ namespace FreeSql.Sqlite public class SqliteProvider : BaseDbProvider, IFreeSql { + static SqliteProvider() + { + Select0Provider._dicMethodDataReaderGetValue[typeof(Guid)] = typeof(DbDataReader).GetMethod("GetGuid", new Type[] { typeof(int) }); + } + public override ISelect CreateSelectProvider(object dywhere) => new SqliteSelect(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere); public override IInsert CreateInsertProvider() => new SqliteInsert(this, this.InternalCommonUtils, this.InternalCommonExpression); public override IUpdate CreateUpdateProvider(object dywhere) => new SqliteUpdate(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);