Медленный поиск кластеризованного индекса по дальности по сравнению с точным соответствием (неточная оценка мощности) - PullRequest
0 голосов
/ 04 октября 2018

Вопрос: Можно ли как-то намекнуть 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, что количество строк будет очень низким?

Кстати.таблица содержит 73 миллиарда строк.Размер данных составляет ~ 1,7 ТБ, а размер индекса - 4,2 ТБ.Вероятно, его можно восстановить, однако это потребует огромных простоев.Кроме того, я могу ускорить выполнение запроса, если просто переключусь на фиктивный цикл.

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 голосов
/ 04 октября 2018

Это потому, что вы используете variables, и они не "вынюхиваются" в запросе, как написано выше.

В случае одиночных значений для каждого из ваших 4 полей, составляющих primary key, знаяэти значения не нужны, так как сервер знает, что каждая комбинация этих 4 полей уникальна.

Дело обстоит иначе, когда вы используете условие [Int4] BETWEEN @Int4 AND (@Int4 + 2).Количество элементов в наборе результатов может различаться, вы можете указать диапазон значений 1 или все возможные значения для @int4, и я повторяю, если вы не попросите сервер оценить выражение / переменные с помощью optin(recompile), сервероценим мощность between как 9% строк (16% начиная с sql server 2014).

Попробуйте заменить переменные на constants, и оценка мощности будет основана на statistics,теперь он оценивает его как «неизвестные значения».

Итак, решение для вашего случая - recompile option.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...