Як співвідноситься предикати предикатів SQL Server?


15

Під час діагностування запитів SQL Server 2008 R2 з поганою оцінкою кардинальності (незважаючи на просту індексацію, сучасну статистику тощо) і, отже, погані плани запитів, я знайшов статтю про КБ, можливо, пов’язану з цим: ВИПРАВЛЕННЯ: Погана продуктивність при запуску запиту який містить корельовані І предикати в SQL Server 2008 або в SQL Server 2008 R2 або в SQL Server 2012

Я можу здогадатися, що означає стаття KB під "співвідносною", наприклад, предикат №2 та предикат №1 значною мірою націлені на одні і ті ж рядки.

Але я не знаю, як SQL Server знає про ці кореляції. Чи потрібна таблиця індексу багато стовпців, що містить стовпці з обох предикатів? Чи використовує SQL статистику для перевірки співвідношення значень одного стовпця з іншим? Або використовується якийсь інший метод?

Я прошу це з двох причин:

  1. щоб визначити, які з моїх таблиць і запитів можна вдосконалити за допомогою цього виправлення
  2. щоб знати, що мені робити в індексації, статистиці тощо, щоб вплинути на №1

Відповіді:


20

Розглянемо простий план запитів та виконання запитів 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.60238533 * 0.60306056 * 113443 = 41210.987

Після округлення це оцінка 41,211, що спостерігається в оригінальному запиті (оптимізатор також використовує математику з плаваючою точкою всередині).

Не велика оцінка

У наборі даних TransactionIDта TransactionDateстовпці є тісна кореляція у наборі даних AdventureWorks (як це часто монотонно збільшуються ключі та стовпці дати). Це співвідношення означає, що припущення про незалежність порушено. Як наслідок, план запиту після виконання показує 68 095 рядків, а не оцінені 41 211:

План після виконання

Слідовий прапор 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 366,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';

... план виконання показує оцінку, яка точно така ж, як і коли була доступна лише одна стовпецька статистика:

План статистики з декількома стовпцями

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.