我在这里写过这个问题:
http://www.philliphaydon.com/2011/09/the-benefits-of-letting-the-orm-generate-the-identity-part-1/
如果您使用数据库中生成的IDENTITY
or GUID
,您将遭受插入速度慢和无法批处理的困扰。
当使用 GUID 插入 SQL 时,NHibernate 会首先发出获取新 GUID 的请求。
你最终得到这样的交易:
- statement #1
begin transaction with isolation level: Unspecified
- statement #2
select newid()
- statement #3
select newid()
- statement #4
select newid()
- statement #5
INSERT INTO Fruit
(Name,
Id)
VALUES ('Apple0' /* @p0_0 */,
'269bc638-74b4-4568-85d1-45b6e537fcbd' /* @p1_0 */)
INSERT INTO Fruit
(Name,
Id)
VALUES ('Apple1' /* @p0_1 */,
'fc848779-b173-4c31-b8b6-0a7735c0c2dc' /* @p1_1 */)
INSERT INTO Fruit
(Name,
Id)
VALUES ('Apple2' /* @p0_2 */,
'232c8971-18c7-486d-9152-26c969c3b632' /* @p1_2 */)
- statement #6
commit transaction
同样,当您使用 IDENTITY 时,NHibernate 需要从数据库中选择新的 Id 来更新模型,当 NHibernate 需要在插入之前将这个新对象与另一个对象关联时,这一点尤其重要。
使用 IDENTITY 最终会得到如下所示的事务:
- statement #1
begin transaction with isolation level: Unspecified
- statement #2
INSERT INTO People
(FirstName,
Surname)
VALUES ('Phillip0' /* @p0 */,
'Haydon' /* @p1 */);
select SCOPE_IDENTITY()
- statement #3
INSERT INTO People
(FirstName,
Surname)
VALUES ('Phillip1' /* @p0 */,
'Haydon' /* @p1 */);
select SCOPE_IDENTITY()
- statement #4
INSERT INTO People
(FirstName,
Surname)
VALUES ('Phillip2' /* @p0 */,
'Haydon' /* @p1 */);
select SCOPE_IDENTITY()
- statement #5
commit transaction
在一台相当不错的计算机上运行一些基本测试,我得到了以下时间的插入结果:
- 身份 28951 毫秒
- NEWID 30241ms
更新它以使用 HiLo 或 GuidComb,允许 NHibernate 自己生成身份。
使用 HiLo,NHibernate 将发出对下一个 hi 值的请求,然后更新 hi 值,一旦有了 hi,它就可以生成一系列 Id,直到 lo 满为止。
这导致插入如下:
- statement #1
begin transaction with isolation level: Unspecified
- statement #2
Reading high value:
select next_hi
from hibernate_unique_key with (updlock, rowlock)
- statement #3
Updating high value:
update hibernate_unique_key
set next_hi = 3 /* @p0 */
where next_hi = 2 /* @p1 */
- statement #4
INSERT INTO People
(FirstName,
Surname,
Id)
VALUES ('Phillip0' /* @p0_0 */,
'Haydon' /* @p1_0 */,
202 /* @p2_0 */)
INSERT INTO People
(FirstName,
Surname,
Id)
VALUES ('Phillip1' /* @p0_1 */,
'Haydon' /* @p1_1 */,
203 /* @p2_1 */)
INSERT INTO People
(FirstName,
Surname,
Id)
VALUES ('Phillip2' /* @p0_2 */,
'Haydon' /* @p1_2 */,
204 /* @p2_2 */)
- statement #5
commit transaction
同样使用 GuidComb,NHibernate 将为您生成一个 GUID:
- statement #1
begin transaction with isolation level: Unspecified
- statement #2
INSERT INTO Fruit
(Name,
Id)
VALUES ('Apple0' /* @p0_0 */,
'db902160-edbb-49c7-bf52-9f660018299a' /* @p1_0 */)
INSERT INTO Fruit
(Name,
Id)
VALUES ('Apple1' /* @p0_1 */,
'5e852528-3a6f-41d2-a6b1-9f660018299a' /* @p1_1 */)
INSERT INTO Fruit
(Name,
Id)
VALUES ('Apple2' /* @p0_2 */,
'2f63c6e8-e595-4393-ad15-9f660018299a' /* @p1_2 */)
- statement #3
commit transaction
这意味着 NHibernate 在进行插入时不需要往返数据库,这两者都允许发生批量插入,正如您在 HiLo 和 GuidComb 中看到的那样,只有 1 条语句被发送到服务器,不像 NEWID / IDENTITY 其中为每个插入发送一条语句,或者为每个新 id 进行选择。
这会导致更短的时间,例如:
- HiLo 9287ms
- GuidComb 9060ms
我希望这会有所帮助:)