Рассмотрим простой запрос и план выполнения AdventureWorks, показанные ниже. Запрос содержит предикаты, связанные с AND. Оценка кардинальности оптимизатора составляет 41 211 строк:
-- Estimate 41,211 rows
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE
TH.TransactionID BETWEEN 100000 AND 168336
AND TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13';

Использование статистики по умолчанию
Учитывая только статистику по одному столбцу, оптимизатор производит эту оценку, оценивая количество элементов для каждого предиката в отдельности и умножая полученную селективность вместе. Эта эвристика предполагает, что предикаты полностью независимы.
Разделение запроса на две части упрощает вычисление:
-- Estimate 68,336.4 rows
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE
TH.TransactionID BETWEEN 100000 AND 168336;
Таблица истории транзакций содержит в общей сложности 113 443 строки, поэтому оценка 68 336,4 представляет селективность 68336,4 / 113443 = 0,60238533 для этого предиката. Эта оценка получается с использованием информации гистограммы для TransactionIDстолбца и значений констант, указанных в запросе.
-- Estimate 68,413 rows
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE
TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13';
Этот предикат имеет оценочную селективность 68413,0 / 113443 = 0,60306056 . Опять же, он рассчитывается на основе постоянных значений предиката и гистограммы TransactionDateобъекта статистики.
Предполагая, что предикаты полностью независимы, мы можем оценить селективность двух предикатов вместе, умножив их вместе. Окончательная оценка количества элементов получается умножением результирующей селективности на 113 443 строки в базовой таблице:
0,6038533 * 0,60306056 * 113443 = 41210,987
После округления это 41 211 оценка, показанная в исходном запросе (оптимизатор также использует внутреннюю математику с плавающей запятой).
Не очень хорошая оценка
TransactionIDИ TransactionDateстолбцы имеют тесную корреляцию данных AdventureWorks набор (как монотонно возрастающие ключи и столбцы дат часто делают). Эта корреляция означает, что предположение о независимости нарушается. Как следствие, план запроса после выполнения показывает 68 095 строк, а не 41 411:

Флаг трассировки 4137
Включение этого флага трассировки изменяет эвристику, используемую для объединения предикатов. Вместо полной независимости оптимизатор считает, что селективности двух предикатов достаточно близки, чтобы их можно было коррелировать:
-- Estimate 68,336.4
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE
TH.TransactionID BETWEEN 100000 AND 168336
AND TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13'
OPTION (QUERYTRACEON 4137);
Напомним, что TransactionIDодин только предикат оценил 68,336,4 строки, а TransactionDateодин только предикат оценил 68,413 строк. Оптимизатор выбрал нижнюю из этих двух оценок, а не умножающую селективность.
Конечно, это просто другая эвристика, но она может помочь улучшить оценки для запросов с коррелированными ANDпредикатами. Каждый предикат рассматривается для возможной корреляции, и есть другие корректировки, сделанные, когда ANDзадействовано много предложений, но этот пример служит для демонстрации его основ.
Статистика по нескольким столбцам
Это может помочь в запросах с корреляциями, но информация гистограммы по-прежнему основана исключительно на ведущем столбце статистики. Таким образом, следующие статистические данные-кандидаты отличаются по важности:
CREATE STATISTICS
[stats Production.TransactionHistory TransactionID TransactionDate]
ON Production.TransactionHistory
(TransactionID, TransactionDate);
CREATE STATISTICS
[stats Production.TransactionHistory TransactionDate TransactionID]
ON Production.TransactionHistory
(TransactionDate, TransactionID);
Взяв только один из них, мы видим, что единственная дополнительная информация - это дополнительные уровни плотности «все». Гистограмма все еще содержит только подробную информацию о TransactionDateстолбце.
DBCC SHOW_STATISTICS
(
'Production.TransactionHistory',
'stats Production.TransactionHistory TransactionDate TransactionID'
);

С этой многостолбцовой статистикой на месте ...
SELECT COUNT_BIG(*)
FROM Production.TransactionHistory AS TH
WHERE
TH.TransactionID BETWEEN 100000 AND 168336
AND TH.TransactionDate BETWEEN '2007-09-01' AND '2008-03-13';
... план выполнения показывает оценку, точно такую же, как тогда, когда была доступна только статистика по одному столбцу:

Statistics objects on multiple columns also store statistical information about the correlation of values among the columns