Сейчас я пытаюсь выяснить, как SQL Server оценивает количество предикатов диапазона, которые частично покрывают шаг гистограммы.
В интернете, при значении статистики кардинальности для оценки внутри шага, я наткнулся на похожий вопрос, и Пол Уайт дал на него довольно интересный ответ.
Согласно ответу Павла, формулы для оценки количества элементов для предикатов> = и> (в данном случае меня интересует только модель оценки мощности по крайней мере 120):
Для>:
Cardinality = EQ_ROWS + (AVG_RANGE_ROWS * (F * (DISTINCT_RANGE_ROWS - 1)))
Для> =:
Cardinality = EQ_ROWS + (AVG_RANGE_ROWS * ((F * (DISTINCT_RANGE_ROWS - 1)) + 1))
Я протестировал применение этих формул в таблице [Production]. [TransactionHistory] базы данных AdventureWorks2014 на основе предиката диапазона с использованием столбца TransactionDate и диапазона даты и времени между «20140614» и «20140618».
Статистика шага гистограммы этого диапазона следующая:
По формуле я рассчитал количество элементов для следующего запроса:
SELECT COUNT(1)
FROM [AdventureWorks2014].[Production].[TransactionHistory]
WHERE [TransactionDate] BETWEEN '20140615 00:00:00.000' AND '20140616 00:00:00.000'
Расчет был выполнен с использованием следующего кода:
DECLARE @predStart DATETIME = '20140615 00:00:00.000'
DECLARE @predEnd DATETIME = '20140616 00:00:00.000'
DECLARE @stepStart DATETIME = '20140614 00:00:00.000'
DECLARE @stepEnd DATETIME = '20140618 00:00:00.000'
DECLARE @predRange FLOAT = DATEDIFF(ms, @predStart, @predEnd)
DECLARE @stepRange FLOAT = DATEDIFF(ms, @stepStart, @stepEnd)
DECLARE @F FLOAT = @predRange / @stepRange;
DECLARE @avg_range_rows FLOAT = 100.3333
DECLARE @distinct_range_rows INT = 3
DECLARE @EQ_ROWS INT = 0
SELECT @F AS 'F'
--for new cardinality estimator
SELECT @EQ_ROWS + @avg_range_rows * (@F * (@distinct_range_rows - 1) + 1) AS [new_card]
После расчета я получил следующие результаты:
Согласно формуле получилось 150,5, но оптимизатор оценивает предикат в 225,75 строк, и если вы измените верхнюю границу предиката на «20140617», оптимизатор уже оценит 250,833 строк, при этом по формуле мы получаем только 200,6666 строк.
Скажите, пожалуйста, как оценивает Cardinality Estimator в этом случае, может быть, я где-то допустил ошибку в моем понимании приведенных формул?