TSQL 慢查询,未按预期使用索引

Gee*_*zer 1 sql-server index-tuning azure-sql-database query-performance

我有一个宽表,相对较大,有 14,264,775 行,在 Azure SQL 数据库上运行。

以下查询需要一些 TLC。

IF EXISTS (
    SELECT  1/0 
    FROM dbo.table1 src
      INNER JOIN dbo.table1 tgt 
        ON tgt.Col1 = src.Col1
    WHERE tgt.ValidFrom <= src.ValidTo
    AND tgt.ValidTo >= src.ValidFrom
    AND tgt.RecordId <> src.RecordId  
)
 BEGIN
    RAISERROR('Overlap detected in dbo.table1', 11, 1); 
 END ;
Run Code Online (Sandbox Code Playgroud)

我有这个索引。

CREATE NONCLUSTERED INDEX [IX__table1] ON dbo.table1
        ( Col1 ) 
INCLUDE (ValidFrom, ValidTo, RecordId)
GO
Run Code Online (Sandbox Code Playgroud)

这是查询的 io 统计信息。逻辑阅读能力非常出色。

在此输入图像描述

这是计划 XML。我尝试了 PasteThePlan,但它无法解析计划 XML。(也许它不喜欢Axure sql数据库计划xml)。

如您所见,[src] 上有一个索引扫描;读取 14,264,775 行(与表中的所有行数相同)。并在 [tgt] 上进行索引查找;读取 194,405,307 行。

我需要改变什么来提高查询的性能?

总共 1400 万行中有 210 万个唯一的 Col1 值。

Pau*_*ite 7

您似乎手动编辑了 XML 并使其无效,主要是通过添加无效字符(例如<和 )>。修复了一些问题后,我能够将计划加载到 SSMS 和 Plan Explorer 中:

\n

计划

\n

这表明您有一个名为[IX__dbo_table1__DateRange]\xe2\x80\x94 的索引,问题中未提及。从seek谓词来看,该索引在索引键中至少有Col1and 。ValidTo

\n

另一个问题是使用IF EXISTS. 这引入了行目标,这导致优化器倾向于嵌套循环解决方案。请参阅相关的问答IF EXISTS 花费的时间比嵌入的 select 语句更长

\n

也就是说,找到任何可能的重叠范围是使用 b 树索引完全解决的一个难题,请参阅解决 BETWEEN join - eager spool 的性能问题

\n

如果不知道完整的表定义、索引和数据分布,就很难提出正确的解决方案。如果您只是想要快速轻松地尝试一些东西,而不需要过多更改索引或源查询,请尝试哈希连接提示:

\n
IF EXISTS (\n    SELECT  1/0 \n    FROM dbo.table1 src\n      INNER HASH JOIN dbo.table1 tgt -- hint added\n        ON tgt.Col1 = src.Col1\n    WHERE tgt.ValidFrom <= src.ValidTo\n    AND tgt.ValidTo >= src.ValidFrom\n    AND tgt.RecordId <> src.RecordId  \n)\n BEGIN\n    RAISERROR(\'Overlap detected in dbo.table1\', 11, 1); \n END ;\n
Run Code Online (Sandbox Code Playgroud)\n

这将完全扫描索引两次,但如果您的系统可以处理内存或 I/O 要求,并且并行或批处理模式执行可用,那么这可能还不错。如果有相当数量的不同的,这将是最好的Col1值,这将最有效。

\n

并行批处理模式哈希连接计划

\n

假设应该禁止重叠,我的偏好是首先使用约束来避免这种情况发生。看确保时态数据库设计中唯一条目的正确方法是什么?

\n
\n

或者,如ypercube\xe1\xb5\x80\xe1\xb4\xb9聊天中

\n
IF EXISTS\n(\n    SELECT 1/0\n    FROM\n    (\n        SELECT \n            T.ValidFrom,\n            PrevValidTo =\n                LAG(T.ValidTo) OVER ( \n                    PARTITION BY T.Col1\n                    ORDER BY T.ValidFrom)\n        FROM dbo.table1 AS T\n    ) AS T1\n    WHERE \n        T1.PrevValidTo >= T1.ValidFrom\n)\nBEGIN\n    RAISERROR(\'Overlap detected in dbo.table1\', 11, 1); \nEND;\n
Run Code Online (Sandbox Code Playgroud)\n

具有如下索引:

\n
CREATE NONCLUSTERED INDEX [IX__table1] \nON dbo.table1\n    (Col1, ValidFrom) \nINCLUDE \n    (ValidTo, RecordId);\n
Run Code Online (Sandbox Code Playgroud)\n

窗函数解决方案

\n


归档时间:

查看次数:

251 次

最近记录:

3 年,7 月 前