Ron*_*dau 1 c# sql-server entity-framework entity-framework-core
我正在将数据从旧数据库导入到新项目,我对 EF Core 生成的一些 SQL 有点困惑(我在输出视图中查看了它,因为它的性能与我的预期相比非常差)。
我的目标是 SQL Server,并且正在创建具有 Image 类型的子属性(poco)的对象,这是如何在具有此类属性的对象上使用它的示例:
MyObject.Thumbnail = new Image()
{
Name = Thumbnail.GetValue("Name"),
OriginalData = ImageData,
Data = ImageData,
Width = bmp.Width,
Height = bmp.Height,
Format = ImageFormat.Jpg
};
Run Code Online (Sandbox Code Playgroud)
我对生成的 SQL 感到困惑(说实话我不明白,它是声明一个临时表然后合并吗?为什么?)及其性能(插入 10 个元素和 2 个图像需要 17 秒)每个属性,我在与运行查询的 .net core 进程相同的机器上本地运行 SQL Server,因此不存在网络延迟和无限带宽以及字节数组,并且一开始就相当小,大部分在 300kb 范围内) 。
预期性能将删除一到两个零。
Microsoft.EntityFrameworkCore.Database.Command:Information: Executed DbCommand (17,211ms) [Parameters=[@p0='?' (Size = -1) (DbType = Binary), @p1='?' (Size = 4000), @p2='?' (DbType = Int32), @p3='?' (DbType = Int32), @p4='?' (Size = 4000), @p5='?' (Size = -1) (DbType = Binary), @p6='?' (DbType = Int32), @p7='?' (Size = -1) (DbType = Binary), @p8='?' (Size = 4000), @p9='?' (DbType = Int32), @p10='?' (DbType = Int32), @p11='?' (Size = 4000), @p12='?' (Size = -1) (DbType = Binary), @p13='?' (DbType = Int32), @p14='?' (Size = -1) (DbType = Binary), @p15='?' (Size = 4000), @p16='?' (DbType = Int32), @p17='?' (DbType = Int32), @p18='?' (Size = 4000), @p19='?' (Size = -1) (DbType = Binary), @p20='?' (DbType = Int32), @p21='?' (Size = 8000) (DbType = Binary), @p22='?' (Size = 4000), @p23='?' (DbType = Int32), @p24='?' (DbType = Int32), @p25='?' (Size = 4000), @p26='?' (Size = 8000) (DbType = Binary), @p27='?' (DbType = Int32), @p28='?' (Size = -1) (DbType = Binary), @p29='?' (Size = 4000), @p30='?' (DbType = Int32), @p31='?' (DbType = Int32), @p32='?' (Size = 4000), @p33='?' (Size = -1) (DbType = Binary), @p34='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DECLARE @inserted0 TABLE ([Id] int, [_Position] [int]);
MERGE [Images] USING (
VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, 0),
(@p7, @p8, @p9, @p10, @p11, @p12, @p13, 1),
(@p14, @p15, @p16, @p17, @p18, @p19, @p20, 2),
(@p21, @p22, @p23, @p24, @p25, @p26, @p27, 3),
(@p28, @p29, @p30, @p31, @p32, @p33, @p34, 4)) AS i ([Data], [Description], [Format], [Height], [Name], [OriginalData], [Width], _Position) ON 1=0
WHEN NOT MATCHED THEN
INSERT ([Data], [Description], [Format], [Height], [Name], [OriginalData], [Width])
VALUES (i.[Data], i.[Description], i.[Format], i.[Height], i.[Name], i.[OriginalData], i.[Width])
OUTPUT INSERTED.[Id], i._Position
INTO @inserted0;
Run Code Online (Sandbox Code Playgroud)
默认情况下,对于 SQL Server SaveChanges 批次。对于这种场景(加载 blob 数据),批处理实际上很糟糕,因为您不希望在客户端和服务器上绑定一个巨大的参数集,然后遍历加载。您需要单插入批次(或者如果您的 blob 非常大,则需要SqlClient Streaming,为此您需要下拉至 ADO.NET)。
您可以在指示 DbContext 使用 SQL Server 的同一行上进行配置,例如:
optionsBuilder.UseSqlServer(constr, b => b.MaxBatchSize(1).UseRelationalNulls(true) );
Run Code Online (Sandbox Code Playgroud)
禁用批处理,并选择不生成模拟 C# 空比较语义的查询。
如果需要有条件地禁用批处理,可以添加在 OnConfiguring 上读取的 DbContext 构造函数参数。例如
public class Db : DbContext
{
bool disableBatching = false;
public Db() : base()
{
}
public Db(bool disableBatching)
{
this.disableBatching = true;
}
Run Code Online (Sandbox Code Playgroud)
如果您需要说服 DI 容器有时在禁用批处理的情况下分发 DbContext,您可以为此创建一个新的子类型,因为大多数 DI 容器都会处理类型注册。例如:
public class NoBatchingDb : Db
{
public NoBatchingDb() : base(disableBatching: true) { }
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1373 次 |
| 最近记录: |