我们产品的数据库包含一个审计跟踪表:
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]
我们用一个简单的语句向这个表添加行insert
- 没有存储过程:
insert into gn_AuditTable (
gn_ObjectId,gn_Time,gn_UserId,gn_Login,gn_Action,gn_ExtraObjectId,gn_ExtraInfo
) values (
?,?,?,?,?,?,?
)
将列的值作为参数传递给查询;也没有触发器。
问题是有时这个插入非常慢——在某些情况下需要超过 30 秒并且超时。
我们多次安装了同一产品,我们在其中一些(但不是全部)中遇到了问题。
审计表可能非常大——多达几百万行。非常慢的插入发生在具有大表的数据库(很自然) - 但是我们有其他数据库具有类似数量的运行良好的行,甚至遇到问题的数据库也会间歇性地出现它,在大多数情况下插入相当快(亚秒)。
该表有 6 个非聚集、非唯一索引:
gn_Login
;gn_ObjectId
;gn_Action
和gn_ExtraInfo
;gn_ExtraObjectId
;gn_Time
;gn_UserId
.
拥有所有这些索引可能会导致问题,但同样,我们到处都有相同的索引,而问题只是在某个地方/有时。
我们在只有一个用户的测试数据库上至少有一次插入超时,因此问题似乎与整体负载无关,而是与插入和表本身有关。
我们曾经有一个聚集索引gn_ObjectId
,但我们为了解决这个问题而放弃了它。gn_ObjectId
不是顺序的,所以我们认为它对于聚集索引来说是一个糟糕的选择,迫使 SQL Server 在插入时重新排序行。可能gn_Time
- 这总是在增加 - 将是一个更好的选择。
没有主键,因为没有“自然”唯一的列或列组合——我们必须添加一个 id 列,这似乎只是开销。
有没有人对我们可以用来诊断问题的方法有什么建议?什么是insert
间歇性地花费这么多时间的事情?