与完全匹配(基数估计不准确)相比,聚类索引搜索速度慢

时间:2018-10-04 10:50:13

标签: sql-server indexing large-data sqlperformance

问题: 我可以以某种方式提示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]约束,也会发生同样的情况。

在所有3种情况下,实际的执行计划看起来都是相同的(聚集索引查找):

Actual Execution Plan

差异在于返回的估计行与实际行。如果是精确条件,则两者均为1。如果是之间条件或省略条件,则相差很大:

Execution Plan Analysis

为什么估算差异会严重损害性能? 有什么方法可以使之间或被忽略的条件更快地运行?有什么方法可以暗示SQL行数会很低吗?

顺便说一句。该表包含730亿行。数据大小约为1.7TB,索引大小为4.2TB。 它可能可以重建,但是将需要大量的停机时间。另外,如果我只是切换到虚拟周期,则可以使查询快速进行。

EDIT1:

根据要求-这是表和索引的实际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

EDIT2:

关于参数嗅探的答案-这是我仅使用常量时得到的结果(估计仍然错误,执行速度仍然很慢):

enter image description here

1 个答案:

答案 0 :(得分:0)

这是因为您使用了variables,并且它们在查询中并未像上面所写的那样被“嗅探”。

如果组成primary key的4个字段中的每个都有单个值,则不需要知道这些值,因为服务器知道这4个字段的每个组合都是唯一的。

使用条件[Int4] BETWEEN @Int4 AND (@Int4 + 2)时情况有所不同。结果集的基数可能会有所不同,您可以指定1个值的范围或@int4的所有可能值,如果您不要求服务器使用{{1 }},服务器将估计optin(recompile)的基数为行的9%(从between开始为16%)。

尝试用sql server 2014替换变量,基数估计将基于constants,现在它估计“未知值”。

因此,您的案例的解决方案是使用statistics选项。