Вопрос: Можно ли как-то намекнуть 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 случаях фактический план выполнения выглядит одинаково (поиск кластеризованного индекса):
Разница в оценках и фактических возвращенных строк.В случае точного условия это оба 1. В случае между или пропущенным условием это огромная разница:
Почему разница в оценке наносит ущербпроизводительность так плохо?Можно ли как-нибудь ускорить выполнение промежуточного или пропущенного условия?В любом случае, как намекнуть 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:
Что касается ответа о параметризации - вот что я получаюесли я использую только константы (все еще неправильная оценка и все еще очень медленное выполнение):