我在我们应用程序的实时系统上观察 Profiler,我看到有一条我们定期(每秒)运行的更新指令非常慢。每次大约需要 400 毫秒。 查询包括此更新(这是缓慢的部分)
UPDATE BufferTable
SET LrbCount = LrbCount + 1,
LrbUpdated = getdate()
WHERE LrbId = @LrbId
这是表格
CREATE TABLE BufferTable(
LrbId [bigint] IDENTITY(1,1) NOT NULL,
...
LrbInserted [datetime] NOT NULL,
LrbProcessed [bit] NOT NULL,
LrbUpdated [datetime] NOT NULL,
LrbCount [tinyint] NOT NULL,
)
该表有 2 个索引(非唯一索引和非聚集索引),字段按以下顺序排列:
* Index1 - (LrbProcessed, LrbCount)
* Index2 - (LrbInserted, LrbCount, LrbProcessed)
当我看到这个时,我认为问题可能来自 Index1,因为 LrbCount 变化很大,它改变了索引中数据的顺序。
但是在停用 index1 之后,我看到查询所花的时间与最初相同。
然后我重建了index1并停用了index2,这次查询非常快。
在我看来 Index2 应该更新得更快,数据的顺序不应该改变,因为 LrbInserted 时间没有改变。
有人能解释一下为什么 index2 比 index1 更难更新吗?
谢谢!
编辑
我刚刚意识到我的假设是错误的。
完整的查询还有另一部分负责延迟:
DECLARE @LrbId as bigint
SELECT TOP 1 @LrbId = LrbId
FROM Buffertable
WHERE LrbProcessed = 0
AND LrbCount < 5
ORDER BY LrbInserted
所以,这很可能与 Sql 引擎对使用哪个索引的错误决定有关。
对困惑感到抱歉。我想我们可以结束这个问题了。
最佳答案
Can someone explain why index2 is much heavier to update then index1?
index2
长得多: key 大小是 10
字节 (8 + 1 + 1) 而不是 2
(1 + 1)
可能它不适合缓存,需要页面查找来定位记录。
你的 table 有多大?
您可能还想启用 I/O 统计信息:
SET STATISTICS IO ON
,运行查询几次并在输出中查看物理页面读取数。
更新:
对于这个查询:
SELECT TOP 1 @LrbId = LrbId
FROM Buffertable
WHERE LrbProcessed = 0
AND LrbCount < 5
ORDER BY
LrbInserted
为了快速工作,创建以下索引:
CREATE INDEX ix_buffertable_p_c_i ON BufferTable (LrbProcessed, lrbCount, LrbInserted)
并重写查询:
WITH cts (cnt) AS
(
SELECT 1
UNION ALL
SELECT cnt + 1
FROM cts
WHERE cnt < 5
)
SELECT TOP 1 bt.*
FROM cts
CROSS APPLY
(
SELECT TOP 1 bti.*
FROM BufferTable bti
WHERE LrbProcessed = 0
AND LrbCount = cts.cnt
ORDER BY
LrbInserted
) bt
ORDER BY
LrbInserted
关于sql-server - 用索引更新表太慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2524234/