我们产品的数据库包含一个审计跟踪表:
CREATE TABLE gn_AuditTable(
gn_ObjectId int NULL,
gn_Action smallint NULL,
gn_Time datetime NULL,
gn_UserId int NULL,
gn_Login varbinary(16) NULL,
gn_ExtraObjectId int NULL,
gn_ExtraInfo int NULL
) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)
我们用一个简单的insert
语句向这个表添加行- 没有存储过程:
insert into gn_AuditTable (
gn_ObjectId,gn_Time,gn_UserId,gn_Login,gn_Action,gn_ExtraObjectId,gn_ExtraInfo
) values (
?,?,?,?,?,?,?
)
Run Code Online (Sandbox Code Playgroud)
将列的值作为参数传递给查询;也没有触发器。
问题是有时这个插入是超慢的——在某些情况下需要超过 30 秒和超时。
我们对同一产品进行了多次安装,并且我们在其中一些(但不是全部)中遇到了问题。
审计表可能非常大——多达几百万行。非常慢的插入发生在具有大表的数据库中(很自然) - 但是我们有其他具有相似行数的其他数据库运行良好,甚至遇到问题的数据库也会间歇性地出现问题,在大多数情况下插入相当快(亚秒)。
该表有 6 个非聚集、非唯一索引:
gn_Login
;
gn_ObjectId
;
gn_Action
和gn_ExtraInfo
;
gn_ExtraObjectId
;
gn_Time
;
gn_UserId
.
拥有所有这些索引可能会导致问题,但同样,我们到处都有相同的索引,而问题只是在某处/有时。
我们在只有一个用户的测试数据库上至少有一次插入超时,因此问题似乎与整体负载无关,而是与插入和表本身有关。
我们曾经在 上有一个聚集索引gn_ObjectId
,但为了解决这个问题,我们去掉了它。gn_ObjectId
不是顺序的,所以我们认为它是聚集索引的一个糟糕选择,迫使 SQL Server 在插入时重新排序行。可能gn_Time
- …