Настроить
У меня возникли проблемы с пониманием оценки количества элементов. Вот моя тестовая установка:
- версия базы данных Stack Overflow 2010 года
- SQL Server 2017 CU15 + GDR (KB4505225) - 14.0.3192.2
- новый CE (уровень совместимости 140)
У меня есть этот процесс:
USE StackOverflow2010;
GO
CREATE OR ALTER PROCEDURE #sp_PostsByCommentCount
@CommentCount int
AS
BEGIN
SELECT *
FROM dbo.Posts p
WHERE
p.CommentCount = @CommentCount
OPTION (RECOMPILE);
END;
GO
В dbo.Posts
таблице нет некластеризованных индексов или статистики (включен кластерный индекс Id
).
Когда запрашивается примерный план для этого, «ожидаемые строки» выходят из dbo.Posts
1934,99:
EXEC #sp_PostsByCommentCount @CommentCount = 51;
При запросе приблизительного плана автоматически был создан следующий объект статистики:
DBCC SHOW_STATISTICS('dbo.Posts', [_WA_Sys_00000006_0519C6AF]);
Основные моменты из этого:
- Статистика имеет довольно низкую частоту выборки - 1,81% (67 796/3 744 192)
- Было использовано только 31 шаг гистограммы
- Значение «Все плотность» является
0.03030303
(33 различных значений были отобраны) - Последний
RANGE_HI_KEY
в гистограмме 50, сEQ_ROWS
1
Вопрос
Передача любого значения выше 50 (до 2 147 483 647 включительно) приводит к оценке строки 1 934,99. Какой расчет или значение используется для получения этой оценки? Кстати, устаревшая оценка мощности дает оценку в 1 строку.
Что я пробовал
Вот некоторые теории, которые у меня были, вещи, которые я пробовал, или дополнительные фрагменты информации, которые я смог найти, изучая это.
Вектор плотности
Сначала я думал, что это будет вектор плотности, такой же, как если бы я использовал OPTION (OPTIMIZE FOR UNKNOWN)
. Но вектор плотности для этого объекта статистики равен 3 744 192 * 0,03030303 = 113 460, так что это не так.
Расширенные события
Я попытался запустить сеанс расширенного события, на котором было собрано query_optimizer_estimate_cardinality
событие (о котором я узнал из блога Пола Уайта в блоге « Оценка кардинальности: объединение статистики плотности» ), и получил следующие интересные трюки:
<CalculatorList>
<FilterCalculator CalculatorName="CSelCalcColumnInInterval" Selectivity="-1.000"
CalculatorFailed="true" TableName="[p]" ColumnName="CommentCount" />
<FilterCalculator CalculatorName="CSelCalcAscendingKeyFilter" Selectivity="0.001"
TableName="[p]" ColumnName="CommentCount" UseAverageFrequency="true"
StatId="4" />
</CalculatorList>
Таким образом, кажется, что CSelCalcAscendingKeyFilter
калькулятор использовался (другой говорит, что он потерпел неудачу, что бы это ни значило). Этот столбец не является ни ключевым, ни уникальным, ни обязательно восходящим, но каким бы то ни было.
Использование этого термина в Google привело меня к некоторым постам в блоге:
- Джо Сэк - калькулятор CSelCalcAscendingKeyFilter ,
- Ицик Бен-Ган - Ищи и просканируй Часть II: Восходящие ключи
Эти посты показывают, что новые CE основывают эти оценки вне гистограммы на комбинации вектора плотности и счетчика модификаций статистики. К сожалению, я уже исключил вектор плотности (я думаю ?!), и счетчик модификации равен нулю ( sys.dm_db_stats_properties
во всяком случае).
Флаги трассировки
Форрест предложил мне включить TF 2363, чтобы получить больше информации о процессе оценки. Я думаю, что самая важная вещь из этого вывода это:
Plan for computation:
CSelCalcAscendingKeyFilter(avg. freq., QCOL: [p].CommentCount)
Selectivity: 0.000516798
Это прорыв (спасибо, Форрест!): Это 0.000516798
число (которое, кажется, было бесполезно округлено в Selectivity="0.001"
атрибуте XE выше), умноженное на количество строк в таблице, является оценкой, которую я искал (1 934,99).
Возможно, я упускаю что-то очевидное, но я не смог перепроектировать, как это значение селективности создается внутри CSelCalcAscendingKeyFilter
калькулятора.