概要
1行のINSERTならSELECT SCOPE_IDENTITY()
で取得すればいいのでしょうけど、
複数行のINSERTを考慮した際、手法がいくつかあるのでベンチ測ってどれがベストか調査してみました。
パターン1 ~愚直に繰り返す~
INSERT INTO [User] ([Name], [Email], [AccountId]) VALUES (@Name, @Email, @AccountId);
SELECT SCOPE_IDENTITY()
↑これを複数回実行する
パターン2 ~1つのSQLに纏めただけ~
INSERT INTO [User] ([Name], [Email], [AccountId]) VALUES (@0_Name, @0_Email, @0_AccountId);
SELECT SCOPE_IDENTITY();
INSERT INTO [User] ([Name], [Email], [AccountId]) VALUES (@1_Name, @1_Email, @1_AccountId);
SELECT SCOPE_IDENTITY();
INSERT INTO [User] ([Name], [Email], [AccountId]) VALUES (@2_Name, @2_Email, @2_AccountId);
SELECT SCOPE_IDENTITY();
INSERT INTO [User] ([Name], [Email], [AccountId]) VALUES (@3_Name, @3_Email, @3_AccountId);
SELECT SCOPE_IDENTITY();
INSERT INTO [User] ([Name], [Email], [AccountId]) VALUES (@4_Name, @4_Email, @4_AccountId);
SELECT SCOPE_IDENTITY()
パターン3 ~OUTPUT句を使う~
INSERT INTO [User] ([Name], [Email], [AccountId])
OUTPUT inserted.[Id] VALUES
(@0_Name, @0_Email, @0_AccountId),
(@1_Name, @1_Email, @1_AccountId),
(@2_Name, @2_Email, @2_AccountId),
(@3_Name, @3_Email, @3_AccountId),
(@4_Name, @4_Email, @4_AccountId)
結果
Method | Mean | Error | StdDev | Gen0 | Allocated |
---|---|---|---|---|---|
パターン1 | 1,049.8 us | 19.93 us | 32.18 us | 5.8594 | 12.28 KB |
パターン2 | 811.9 us | 8.43 us | 7.89 us | 4.8828 | 11.17 KB |
パターン3 | 259.4 us | 5.13 us | 5.71 us | 4.3945 | 9.82 KB |
OUTPUT句を使うパターンが圧倒的に優れていることが分かりました。
おそらく単一行の場合もこの手法がベストかと思います。
ただし、これはSQL Serverの機能であるためMySQLなどでは使うことができません。
似たような機能を探してはみたものの見つけられませんでした。
MySQLの場合同時に挿入した時は連番が保証されているらしいのでSELECT LAST_INSERT_ID()
を1回行えば逆算できるらしい(自信無い)。
MySQL/MariaDB/SQLiteの場合
INSERT INTO User (Name) VALUES (@0_Name), (@1_Name) RETURNING Id
が同等の機能です。