代码之家  ›  专栏  ›  技术社区  ›  Jan

相对于精确匹配(基数估计不准确),对范围的聚集索引搜索较慢

  •  0
  • Jan  · 技术社区  · 6 年前

    问题: 我能以某种方式提示SQL Server从索引搜索返回的预期行数吗?

    背景:

    我有一个唯一的聚集索引:

    ALTER TABLE [dbo].[T] ADD  CONSTRAINT [X] PRIMARY KEY CLUSTERED 
    (
        [Int1] ASC,
        [Int2] ASC,
        [Int3] ASC,
        [Int4] ASC
    )
    

    SELECT 
        ...
    FROM [dbo].[T]
    WHERE
        [Int1] = @Int1 AND
        [Int2] = @Int2 AND
        [Int3] = @Int3 AND
        [Int4] = @Int4
    

    这是即时运行的。具有参数@Int1-4的任何值

    如果我用循环迭代@Int4的值递增(是的,这在SQL中听起来完全是错误的),我会立即得到结果。

    -- Looks completely wrong for SQL - but it seems to be fastest way to fetch range of values
    DECLARE @I INT = 1
    WHILE @I <= 50
    BEGIN
        SELECT 
            ...
        FROM [dbo].[T]
        WHERE
            [Int1] = @Int1 AND
            [Int2] = @Int2 AND
            [Int3] = @Int3 AND
            [Int4] = @I
    
        SET @I = @I + 1
    END
    GO
    

    如果我将最后一个条件指定为范围:

    SELECT 
        ...
    FROM [dbo].[T]
    WHERE
        [Int1] = @Int1 AND
        [Int2] = @Int2 AND
        [Int3] = @Int3 AND
        [Int4] BETWEEN @Int4 AND (@Int4 + 2)
    

    如果我完全忽略了[Int4]约束,也会发生同样的情况。

    Actual Execution Plan

    不同之处在于返回的估计行与实际行数。在精确的情况下,两者都是1。如果是“介于”或“省略”的情况,则差别很大:

    Execution Plan Analysis

    有什么方法可以让between或省略条件更快地运行?有什么方法可以提示SQL行数将非常低吗?

    顺便说一句,这个表包含730亿行。数据大小约为1.7TB,索引大小约为4.2TB。 它可能需要重建,但是需要大量的停机时间。另外,如果我只切换到dummy cycle,我可以快速简化查询。

    按要求-这是表和索引的实际DDL(前4列是我上面简化的示例中的INT1-INT4):

    CREATE TABLE [dbo].[RelationalResultValueVectorial](
        [RelationalResultRowId] [bigint] NOT NULL,
        [RelationalResultPropertyId] [int] NOT NULL,
        [RelationalResultVectorialDimensionId] [int] NOT NULL,
        [OrdinalRowIdWithinProperty] [int] NOT NULL,
        [RelationalResultValueId] [bigint] IDENTITY(1,1) NOT NULL,
     CONSTRAINT [Idx_RelationalResultValueVectorial] PRIMARY KEY CLUSTERED 
    (
        [RelationalResultRowId] ASC,
        [RelationalResultPropertyId] ASC,
        [RelationalResultVectorialDimensionId] ASC,
        [OrdinalRowIdWithinProperty] ASC
    ) ON [RelationalDataFileGroup]
    ) ON [RelationalDataFileGroup]
    GO
    
    CREATE UNIQUE NONCLUSTERED INDEX [IX_RelationalResultValueVectorial_ValueId] ON [dbo].[RelationalResultValueVectorial]
    (
        [RelationalResultValueId] ASC
    ) ON [RelationalDataFileGroup]
    GO
    
    -- + some FKs
    

    关于参数嗅探的答案-这里是如果我只使用常量(仍然是错误的估计和仍然非常缓慢的执行)得到的结果:

    enter image description here

    1 回复  |  直到 6 年前
        1
  •  0
  •   sepupic    6 年前

    这是因为你用 variables ,并且它们不会像上面写的那样在查询中被“嗅探”。

    如果4个字段中的每一个都有一个值 primary key

    当你使用这个条件时,情况就不同了 [Int4] BETWEEN @Int4 AND (@Int4 + 2) @int4 ,我重复一遍,如果您不要求服务器使用 optin(recompile) ,服务器将估计 between 作为9%的行(16%从 sql server 2014 ).

    试着用 constants 基数估计将基于 statistics ,现在它估计为“未知值”。

    所以,你的案子的解决方案是 recompile 选项。