Closed ajcvickers closed 2 years ago
In doing some testing for other features I noticed these changes kicking in for inserting a graph of entities. /cc @roji @JeremyLikness
EF Core 6.0 does six round trips:
info: 8/10/2022 12:21:38.321 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
Executed DbCommand (18ms) [Parameters=[@p0='cf7e7f72-42e5-4b72-375a-08da7ac27df8', @p1='FarmFood' (Nullable = false) (Size = 4000), @p2='Hay' (Size = 4000), @p3='8dd245bd-d4b5-4b51-3758-08da7ac27df8', @p4='670' (Nullable = true), @p5='HumanFood' (Nullable = false) (Size = 4000), @p6='Sushi' (Size = 4000),
@p7='1f1c8912-5e70-4750-3757-08da7ac27df8', @p8='Canagan' (Size = 4000), @p9='PetFood' (Nullable = false) (Size = 4000), @p10='1' (Nullable = true), @p11='e13a0b04-ac1a-4671-3759-08da7ac27df8', @p12='Lily's Kitchen' (Size = 4000), @p13='PetFood' (Nullable = false) (Size = 4000), @p14='1' (Nullable = true)], Co
mmandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
INSERT INTO [Foods] ([Id], [Discriminator], [Name])
VALUES (@p0, @p1, @p2);
INSERT INTO [Foods] ([Id], [Calories], [Discriminator], [Name])
VALUES (@p3, @p4, @p5, @p6);
INSERT INTO [Foods] ([Id], [Brand], [Discriminator], [LifeStage])
VALUES (@p7, @p8, @p9, @p10),
(@p11, @p12, @p13, @p14);
info: 8/10/2022 12:21:38.347 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
Executed DbCommand (13ms) [Parameters=[@p15='Cat' (Nullable = false) (Size = 4000), @p16='MBA' (Size = 4000), @p17='e13a0b04-ac1a-4671-3759-08da7ac27df8' (Nullable = true), @p18='Alice' (Nullable = false) (Size = 4000), @p19='Cat' (Nullable = false) (Size = 4000), @p20='Preschool' (Size = 4000), @p21='e13
a0b04-ac1a-4671-3759-08da7ac27df8' (Nullable = true), @p22='Mac' (Nullable = false) (Size = 4000), @p23='Dog' (Nullable = false) (Size = 4000), @p24='Mr. Squirrel' (Size = 4000), @p25='1f1c8912-5e70-4750-3757-08da7ac27df8' (Nullable = true), @p26='Toast' (Nullable = false) (Size = 4000), @p27='FarmAnimal' (Null
able = false) (Size = 4000), @p28='cf7e7f72-42e5-4b72-375a-08da7ac27df8' (Nullable = true), @p29='Clyde' (Nullable = false) (Size = 4000), @p30='Equus africanus asinus' (Size = 4000), @p31='100.0' (Nullable = true) (Precision = 18) (Scale = 2)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DECLARE @inserted0 TABLE ([Id] int, [_Position] [int]);
MERGE [Animals] USING (
VALUES (@p15, @p16, @p17, @p18, 0),
(@p19, @p20, @p21, @p22, 1)) AS i ([Discriminator], [EducationLevel], [FoodId], [Name], _Position) ON 1=0
WHEN NOT MATCHED THEN
INSERT ([Discriminator], [EducationLevel], [FoodId], [Name])
VALUES (i.[Discriminator], i.[EducationLevel], i.[FoodId], i.[Name])
OUTPUT INSERTED.[Id], i._Position
INTO @inserted0;
SELECT [i].[Id] FROM @inserted0 i
ORDER BY [i].[_Position];
INSERT INTO [Animals] ([Discriminator], [FavoriteToy], [FoodId], [Name])
VALUES (@p23, @p24, @p25, @p26);
SELECT [Id]
FROM [Animals]
WHERE @@ROWCOUNT = 1 AND [Id] = scope_identity();
INSERT INTO [Animals] ([Discriminator], [FoodId], [Name], [Species], [Value])
VALUES (@p27, @p28, @p29, @p30, @p31);
SELECT [Id]
FROM [Animals]
WHERE @@ROWCOUNT = 1 AND [Id] = scope_identity();
info: 8/10/2022 12:21:38.372 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
Executed DbCommand (2ms) [Parameters=[@p0='Human' (Nullable = false) (Size = 4000), @p1='3' (Nullable = true), @p2=NULL (DbType = Guid), @p3='Wendy' (Nullable = false) (Size = 4000)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
INSERT INTO [Animals] ([Discriminator], [FavoriteAnimalId], [FoodId], [Name])
VALUES (@p0, @p1, @p2, @p3);
SELECT [Id]
FROM [Animals]
WHERE @@ROWCOUNT = 1 AND [Id] = scope_identity();
info: 8/10/2022 12:21:38.378 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
Executed DbCommand (1ms) [Parameters=[@p0='Human' (Nullable = false) (Size = 4000), @p1='1' (Nullable = true), @p2='8dd245bd-d4b5-4b51-3758-08da7ac27df8' (Nullable = true), @p3='Arthur' (Nullable = false) (Size = 4000)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
INSERT INTO [Animals] ([Discriminator], [FavoriteAnimalId], [FoodId], [Name])
VALUES (@p0, @p1, @p2, @p3);
SELECT [Id]
FROM [Animals]
WHERE @@ROWCOUNT = 1 AND [Id] = scope_identity();
info: 8/10/2022 12:21:38.379 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
Executed DbCommand (0ms) [Parameters=[@p0='Human' (Nullable = false) (Size = 4000), @p1='4' (Nullable = true), @p2=NULL (DbType = Guid), @p3='Christi' (Nullable = false) (Size = 4000)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
INSERT INTO [Animals] ([Discriminator], [FavoriteAnimalId], [FoodId], [Name])
VALUES (@p0, @p1, @p2, @p3);
SELECT [Id]
FROM [Animals]
WHERE @@ROWCOUNT = 1 AND [Id] = scope_identity();
info: 8/10/2022 12:21:38.384 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
Executed DbCommand (3ms) [Parameters=[@p4='5', @p5='1', @p6='5', @p7='2', @p8='5', @p9='3', @p10='6', @p11='1', @p12='6', @p13='2', @p14='6', @p15='3'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
INSERT INTO [Dictionary<object, string>] ([HumansId], [PetsId])
VALUES (@p4, @p5),
(@p6, @p7),
(@p8, @p9),
(@p10, @p11),
(@p12, @p13),
(@p14, @p15);
EF7 with Identity does three round trips:
info: 8/10/2022 12:19:13.006 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
Executed DbCommand (24ms) [Parameters=[@p0='7093f657-a3b8-4624-4d58-08da7ac22757', @p1='FarmFood' (Nullable = false) (Size = 4000), @p2='Hay' (Size = 4000), @p3='df0a116c-f55d-42f2-4d56-08da7ac22757', @p4='670' (Nullable = true), @p5='HumanFood' (Nullable = false) (Size = 4000), @p6='Sushi' (Size = 4000),
@p7='1ecefb3b-6489-4a09-4d57-08da7ac22757', @p8='Lily's Kitchen' (Size = 4000), @p9='PetFood' (Nullable = false) (Size = 4000), @p10='1' (Nullable = true), @p11='d4925a5b-601f-4ea4-4d55-08da7ac22757', @p12='Canagan' (Size = 4000), @p13='PetFood' (Nullable = false) (Size = 4000), @p14='1' (Nullable = true), @p1
5='Cat' (Nullable = false) (Size = 4000), @p16='MBA' (Size = 4000), @p17='1ecefb3b-6489-4a09-4d57-08da7ac22757' (Nullable = true), @p18='Alice' (Nullable = false) (Size = 4000), @p19='Cat' (Nullable = false) (Size = 4000), @p20='Preschool' (Size = 4000), @p21='1ecefb3b-6489-4a09-4d57-08da7ac22757' (Nullable = t
rue), @p22='Mac' (Nullable = false) (Size = 4000), @p23='Dog' (Nullable = false) (Size = 4000), @p24='Mr. Squirrel' (Size = 4000), @p25='d4925a5b-601f-4ea4-4d55-08da7ac22757' (Nullable = true), @p26='Toast' (Nullable = false) (Size = 4000), @p27='FarmAnimal' (Nullable = false) (Size = 4000), @p28='7093f657-a3b8
-4624-4d58-08da7ac22757' (Nullable = true), @p29='Clyde' (Nullable = false) (Size = 4000), @p30='Equus africanus asinus' (Size = 4000), @p31='100.0' (Nullable = true) (Precision = 18) (Scale = 2)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
INSERT INTO [Foods] ([Id], [Discriminator], [Name])
VALUES (@p0, @p1, @p2);
INSERT INTO [Foods] ([Id], [Calories], [Discriminator], [Name])
VALUES (@p3, @p4, @p5, @p6);
INSERT INTO [Foods] ([Id], [Brand], [Discriminator], [LifeStage])
VALUES (@p7, @p8, @p9, @p10),
(@p11, @p12, @p13, @p14);
MERGE [Animals] USING (
VALUES (@p15, @p16, @p17, @p18, 0),
(@p19, @p20, @p21, @p22, 1)) AS i ([Discriminator], [EducationLevel], [FoodId], [Name], _Position) ON 1=0
WHEN NOT MATCHED THEN
INSERT ([Discriminator], [EducationLevel], [FoodId], [Name])
VALUES (i.[Discriminator], i.[EducationLevel], i.[FoodId], i.[Name])
OUTPUT INSERTED.[Id], i._Position;
INSERT INTO [Animals] ([Discriminator], [FavoriteToy], [FoodId], [Name])
OUTPUT INSERTED.[Id]
VALUES (@p23, @p24, @p25, @p26);
INSERT INTO [Animals] ([Discriminator], [FoodId], [Name], [Species], [Value])
OUTPUT INSERTED.[Id]
VALUES (@p27, @p28, @p29, @p30, @p31);
info: 8/10/2022 12:19:13.040 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
Executed DbCommand (7ms) [Parameters=[@p32='Human' (Nullable = false) (Size = 4000), @p33='3' (Nullable = true), @p34=NULL (DbType = Guid), @p35='Wendy' (Nullable = false) (Size = 4000), @p36='Human' (Nullable = false) (Size = 4000), @p37='1' (Nullable = true), @p38='df0a116c-f55d-42f2-4d56-08da7ac22757'
(Nullable = true), @p39='Arthur' (Nullable = false) (Size = 4000), @p40='Human' (Nullable = false) (Size = 4000), @p41='4' (Nullable = true), @p42=NULL (DbType = Guid), @p43='Christi' (Nullable = false) (Size = 4000)], CommandType='Text', CommandTimeout='30']
SET IMPLICIT_TRANSACTIONS OFF;
SET NOCOUNT ON;
MERGE [Animals] USING (
VALUES (@p32, @p33, @p34, @p35, 0),
(@p36, @p37, @p38, @p39, 1),
(@p40, @p41, @p42, @p43, 2)) AS i ([Discriminator], [FavoriteAnimalId], [FoodId], [Name], _Position) ON 1=0
WHEN NOT MATCHED THEN
INSERT ([Discriminator], [FavoriteAnimalId], [FoodId], [Name])
VALUES (i.[Discriminator], i.[FavoriteAnimalId], i.[FoodId], i.[Name])
OUTPUT INSERTED.[Id], i._Position;
info: 8/10/2022 12:19:13.045 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
Executed DbCommand (2ms) [Parameters=[@p44='5', @p45='3', @p46='5', @p47='1', @p48='5', @p49='2', @p50='6', @p51='3', @p52='6', @p53='1', @p54='6', @p55='2'], CommandType='Text', CommandTimeout='30']
SET IMPLICIT_TRANSACTIONS OFF;
SET NOCOUNT ON;
INSERT INTO [Dictionary<object, string>] ([HumansId], [PetsId])
VALUES (@p44, @p45),
(@p46, @p47),
(@p48, @p49),
(@p50, @p51),
(@p52, @p53),
(@p54, @p55);
EF7 with HiLo does it all in a single database call!
info: 8/10/2022 12:27:56.971 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
Executed DbCommand (17ms) [Parameters=[@p0='6012a865-624b-4a17-402a-08da7ac35fa7', @p1='FarmFood' (Nullable = false) (Size = 4000), @p2='Hay' (Size = 4000), @p3='e1008f20-b713-4a3c-4028-08da7ac35fa7', @p4='670' (Nullable = true), @p5='HumanFood' (Nullable = false) (Size = 4000), @p6='Sushi' (Size = 4000),
@p7='33732a70-f101-4d62-4029-08da7ac35fa7', @p8='Lily's Kitchen' (Size = 4000), @p9='PetFood' (Nullable = false) (Size = 4000), @p10='1' (Nullable = true), @p11='8d0a7091-d013-44a9-4027-08da7ac35fa7', @p12='Canagan' (Size = 4000), @p13='PetFood' (Nullable = false) (Size = 4000), @p14='1' (Nullable = true), @p1
5='4', @p16='Cat' (Nullable = false) (Size = 4000), @p17='MBA' (Size = 4000), @p18='33732a70-f101-4d62-4029-08da7ac35fa7' (Nullable = true), @p19='Alice' (Nullable = false) (Size = 4000), @p20='7', @p21='Cat' (Nullable = false) (Size = 4000), @p22='Preschool' (Size = 4000), @p23='33732a70-f101-4d62-4029-08da7ac
35fa7' (Nullable = true), @p24='Mac' (Nullable = false) (Size = 4000), @p25='2', @p26='Dog' (Nullable = false) (Size = 4000), @p27='Mr. Squirrel' (Size = 4000), @p28='8d0a7091-d013-44a9-4027-08da7ac35fa7' (Nullable = true), @p29='Toast' (Nullable = false) (Size = 4000), @p30='6', @p31='FarmAnimal' (Nullable = f
alse) (Size = 4000), @p32='6012a865-624b-4a17-402a-08da7ac35fa7' (Nullable = true), @p33='Clyde' (Nullable = false) (Size = 4000), @p34='Equus africanus asinus' (Size = 4000), @p35='100.0' (Nullable = true) (Precision = 18) (Scale = 2), @p36='1', @p37='Human' (Nullable = false) (Size = 4000), @p38='2' (Nullable
= true), @p39=NULL (DbType = Guid), @p40='Wendy' (Nullable = false) (Size = 4000), @p41='3', @p42='Human' (Nullable = false) (Size = 4000), @p43='4' (Nullable = true), @p44='e1008f20-b713-4a3c-4028-08da7ac35fa7' (Nullable = true), @p45='Arthur' (Nullable = false) (Size = 4000), @p46='5', @p47='Human' (Nullable
= false) (Size = 4000), @p48='6' (Nullable = true), @p49=NULL (DbType = Guid), @p50='Christi' (Nullable = false) (Size = 4000), @p51='1', @p52='2', @p53='1', @p54='4', @p55='1', @p56='7', @p57='3', @p58='2', @p59='3', @p60='4', @p61='3', @p62='7'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
INSERT INTO [Foods] ([Id], [Discriminator], [Name])
VALUES (@p0, @p1, @p2);
INSERT INTO [Foods] ([Id], [Calories], [Discriminator], [Name])
VALUES (@p3, @p4, @p5, @p6);
INSERT INTO [Foods] ([Id], [Brand], [Discriminator], [LifeStage])
VALUES (@p7, @p8, @p9, @p10),
(@p11, @p12, @p13, @p14);
INSERT INTO [Animals] ([Id], [Discriminator], [EducationLevel], [FoodId], [Name])
VALUES (@p15, @p16, @p17, @p18, @p19),
(@p20, @p21, @p22, @p23, @p24);
INSERT INTO [Animals] ([Id], [Discriminator], [FavoriteToy], [FoodId], [Name])
VALUES (@p25, @p26, @p27, @p28, @p29);
INSERT INTO [Animals] ([Id], [Discriminator], [FoodId], [Name], [Species], [Value])
VALUES (@p30, @p31, @p32, @p33, @p34, @p35);
INSERT INTO [Animals] ([Id], [Discriminator], [FavoriteAnimalId], [FoodId], [Name])
VALUES (@p36, @p37, @p38, @p39, @p40),
(@p41, @p42, @p43, @p44, @p45),
(@p46, @p47, @p48, @p49, @p50);
INSERT INTO [Dictionary<object, string>] ([HumansId], [PetsId])
VALUES (@p51, @p52),
(@p53, @p54),
(@p55, @p56),
(@p57, @p58),
(@p59, @p60),
(@p61, @p62);
EF7 with HiLo does it all in a single database call!
@ajcvickers: What is HiLo
?
@Saibamen It's a value generation strategy that reserves a range of key values in the database and then uses those values as needed, as opposed to requesting key values at the time of insert.
@Saibamen take a look at this blog post, which summarizes optimizations done under this epic; it contains a brief explanation of HiLo.
Over the past few releases, we have focused on improving EF Core performance on non-tracking queries. For EF7, we plan to focus on performance related to database inserts and updates. This includes performance of change-tracking queries, performance of
DetectChanges
, and performance of the insert and update commands sent to the database.The work done here is described in this blog post, and discussed in this community standup.