用索引更新表太慢

2024-05-02

我正在观察我们应用程序的实时系统上的探查器,我发现我们定期(每秒)运行一条更新指令,速度相当慢。每次大约需要400ms。 查询包含此更新(这是缓慢的部分)

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-(Lrb处理,Lrb计数)
* Index2-(Lrb插入、Lrb计数、Lrb处理)

当我看到这个时,我认为问题出在Index1因为 LrbCount 变化很大,并且它改变了索引中数据的顺序。
但停用后index1我看到查询花费的时间与最初相同。 然后我重建了index1并停用index2,这次查询速度很快。

在我看来,这Index2更新应该更快,数据的顺序不应该改变,因为 LrbInserted 时间没有改变。

有人可以解释为什么吗index2那么更新要繁重得多index1?

谢谢你!

EDIT

我刚刚意识到我的假设是错误的。
完整的查询还有另一个部分导致延迟:

DECLARE @LrbId as bigint
SELECT TOP 1 @LrbId = LrbId
FROM Buffertable
WHERE LrbProcessed = 0
    AND LrbCount < 5
ORDER BY LrbInserted

因此,很可能这与 Sql 引擎关于使用哪个索引的错误决定有关。
对困惑感到抱歉。我想我们可以结束这个问题了。


有人可以解释为什么索引 2 比更新索引 1 重得多吗?

index2更长:密钥大小是10字节 (8 + 1 + 1) 而不是2 (1 + 1)

可能它不适合缓存,需要进行页面查找来定位记录。

你的桌子有多大?

您可能还想启用 I/O 统计:

SET STATISTICS IO ON

,运行查询几次并查看输出中的物理页读取数。

Update:

对于此查询:

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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

用索引更新表太慢 的相关文章

随机推荐