ati*_*yar 1 sql sql-server sql-insert
下面的 SQL 命令是如何工作的?
exec sp_executesql N'SET NOCOUNT ON;
DECLARE @inserted0 TABLE ([Id] int, [_Position] [int]);
MERGE [OrderLine] USING (
VALUES (@p1, @p2, 0),
(@p3, @p4, 1),
(@p5, @p6, 2),
(@p7, @p8, 3)) AS i ([Item], [OrderId], _Position) ON 1=0
WHEN NOT MATCHED THEN
INSERT ([Item], [OrderId])
VALUES (i.[Item], i.[OrderId])
OUTPUT INSERTED.[Id], i._Position
INTO @inserted0;
SELECT [t].[Id] FROM [OrderLine] t
INNER JOIN @inserted0 i ON ([t].[Id] = [i].[Id])
ORDER BY [i].[_Position];
',N'@p1 nvarchar(64),@p2 int,@p3 nvarchar(64),@p4 int,@p5 nvarchar(64),@p6 int,@p7 nvarchar(64),@p8 int',@p1=N'Item-1',@p2=1,@p3=N'Item-2',@p4=1,@p5=N'Item-3',@p6=1,@p7=N'Item-4',@p8=1
Run Code Online (Sandbox Code Playgroud)
(它由 EF Core 生成并插入了一些OrderLine实体)。
编辑:
我了解 TABLE 类型变量的声明并且对 MERGE 操作有基本的了解。但是很难理解实际数据是如何以及何时插入到 OrderLine 表中的。
这是一个有趣的问题,值得一整篇文章来回答。幸运的是,Brent Ozar 写了The Case of Entity Framework Core's Odd SQL。
MERGE 语句基本上做了 anINSERT ... OUTPUT inserted.ID VALUES (),(),()会做的事情。该子句ON 1=0确保仅执行 INSERT 分支。那么为什么会有如此复杂的语法呢?
这种奇怪的 SQL 的原因是批量插入的性能。具体来说,10K 行的性能提高了 248%。
在表中插入多行的方法只有几种:
身份证呢?
table 变量用于收集生成的 id,_Position即使在并行执行的情况下也用于维护顺序。我怀疑,这就是为什么INSERT VALUES也没有使用的原因。
由于 EF Core 仅在单个批次中发送了 5000 个项目,因此它需要一种方法来检索 5000 个新 ID,以允许它识别这些 ID 属于哪些对象。通常,人们会使用 ID 来标识行,但没有 ID 开始!
剩下的唯一事情就是按照插入对象的相同顺序返回 ID。INSERT OUTPUT VALUES并不能保证-没有一个ORDER子句,该服务器可以自由地在可能的最便宜的方式返回数据。
在这种情况下,保留 ID 和顺序的唯一安全方法是将它们与显式_Position值一起存储@inserted0并按该顺序返回它们。
结论
这是关于性能的,正如 Brent Ozar 所说:
所以是的,SQL 并不完美,但它的速度提高了 248%。
布伦特说:呼,孩子。这……不理想。
| 归档时间: |
|
| 查看次数: |
124 次 |
| 最近记录: |