Оцінка кардинальності для> = і> для значення статистики на внутрішньому етапі


9

Я намагаюся зрозуміти, як SQL Server намагається оцінити "більше, ніж" і "більше, ніж рівне", де пропозиції в SQL Server 2014.

Я думаю, що я розумію оцінку кардинальності, коли вона потрапляє на крок, наприклад, якщо я це роблю

    select * from charge where charge_dt >= '1999-10-13 10:47:38.550'

Оцінка кардинальності - 6672, що може бути легко обчислено як 32 (EQ_ROWS) + 6624 (RANGE_ROWS) + 16 (EQ_ROWS) = 6672 (гістограма нижче на скріншоті)

введіть тут опис зображення

Але коли я

    select * from charge where charge_dt >= '1999-10-13 10:48:38.550' 

(збільшив час до 10:48, так що це не крок)

оцінка - 4844,13.

Як це обчислюється?

Відповіді:


9

Єдина складність полягає у вирішенні питання, як обробити етап (и) гістограми, частково охоплені інтервалом предикатів запиту. Цілі етапи гістограми, охоплені діапазоном предиката, є тривіальними, як зазначено в питанні.

Оцінювач спадковості кардинальності

F = частка (від 0 до 1) діапазону кроків, охопленого предикатом запиту.

Основна ідея полягає у використанні F(лінійна інтерполяція), щоб визначити, скільки значень, що знаходяться на внутрішньому етапі, охоплені присудком. Помноження цього результату на середню кількість рядків на окреме значення (якщо вважати рівномірність) та додавання крокових рівних рядків дає оцінку кардинальності:

Сердечність = EQ_ROWS + (AVG_RANGE_ROWS * F * DISTINCT_RANGE_ROWS)

Ця ж формула використовується >і >=для спадщини СЕ.

Новий оцінювач кардинальності

Новий СЕ трохи модифікує попередній алгоритм, щоб розмежувати >та >=.

По- >перше, формула така:

Сердечність = EQ_ROWS + (AVG_RANGE_ROWS * (F * (DISTINCT_RANGE_ROWS - 1)))

Бо >=це:

Сердечність = EQ_ROWS + (AVG_RANGE_ROWS * ((F * (DISTINCT_RANGE_ROWS - 1)) + 1))

+ 1Відображає , що , коли порівняння включає в себе рівність, матч вважається (включення припущення).

У прикладі запитання Fможна обчислити як:

DECLARE 
    @Q datetime = '1999-10-13T10:48:38.550',
    @K1 datetime = '1999-10-13T10:47:38.550',
    @K2 datetime = '1999-10-13T10:51:19.317';

DECLARE
    @QR float = DATEDIFF(MILLISECOND, @Q, @K2), -- predicate range
    @SR float = DATEDIFF(MILLISECOND, @K1, @K2) -- whole step range

SELECT
    F = @QR / @SR;

Результат 0,728219019233034 . Підключення до формули для >=інших відомих значень:

Сердечність = EQ_ROWS + (AVG_RANGE_ROWS * ((F * (DISTINCT_RANGE_ROWS - 1)) + 1))
            = 16 + (16.1956 * ((0.728219019233034 * (409 - 1)) + 1))
            = 16 + (16.1956 * ((0.728219019233034 * 408) + 1))
            = 16 + (16.1956 * (297.113359847077872 + 1))
            = 16 + (16.1956 * 298.113359847077872)
            = 16 + 4828.1247307393343837632
            = 4844.1247307393343837632
            = 4844.12473073933 (точно плавати)

Цей результат відповідає оцінці 4844,13, наведеній у запитанні.

Цей же запит, що використовує застарілий CE (наприклад, використовуючи прапор сліду 9481), повинен дати оцінку:

Сердечність = EQ_ROWS + (AVG_RANGE_ROWS * F * DISTINCT_RANGE_ROWS)
            = 16 + (16.1956 * 0.728219019233034 * 409)
            = 16 + 4823,72307468722
            = 4839.72307468722

Зауважте, що оцінка буде однаковою для використання >та >=використаного спадщини CE.


4

Формула для оцінювання рядків стає незначною, коли фільтр "більший за" або "менший за", але це число, до якого можна прийти.

Цифри

Використовуючи крок 193, ось відповідні номери:

RANGE_ROWS = 6624

EQ_ROWS = 16

AVG_RANGE_ROWS = 16.1956

RANGE_HI_KEY з попереднього кроку = 1999-10-13 10: 47: 38,550

RANGE_HI_KEY з поточного кроку = 1999-10-13 10: 51: 19.317

Значення з пункту WHERE = 1999-10-13 10: 48: 38,550

Формула

1) Знайдіть повідомлення між двома клавішами hi hi

SELECT DATEDIFF (ms, '1999-10-13 10:47:38.550', '1999-10-13 10:51:19.317')

Результат - 220767 мс.

2) Відрегулюйте кількість рядків

Нам потрібно знайти рядки в мілісекунді, але перед цим ми повинні відняти AVG_RANGE_ROWS від RANGE_ROWS:

6624 - 16.1956 = 6607.8044 рядів

3) Обчисліть рядки на мс із скоригованою кількістю рядків:

6607.8044 рядків / 220767 мс = .0299311 рядків на мс

4) Обчисліть мс між значенням із пункту WHERE та поточним кроком RANGE_HI_KEY

SELECT DATEDIFF (ms, '1999-10-13 10:48:38.550', '1999-10-13 10:51:19.317')

Це дає нам 160767 мс.

5) Обчисліть рядки на цьому кроці на основі рядків за секунду:

.0299311 рядків / мс * 160767 мс = 4811.9332 рядків

6) Пригадайте, як ми віднімали AVG_RANGE_ROWS раніше? Час додати їх назад. Тепер, коли ми закінчили обчислення чисел, пов'язаних з рядками в секунду, ми можемо сміливо додати і EQ_ROWS:

4811.9332 + 16.1956 + 16 = 4844.1288

Округлена, ось наша оцінка 4844,13.

Тестування формули

Я не зміг знайти жодних статей чи публікацій в блозі, чому AVG_RANGE_ROWS вилучається до обчислення рядків за мс. Я був в змозі підтвердити , що вони враховуються в оцінці, але тільки в останню мілісекунду - в буквальному сенсі.

Використовуючи базу даних WideWorldImporters , я провів кілька поступових тестувань і виявив, що зменшення оцінок рядків є лінійним до кінця кроку, де раптово враховується 1x AVG_RANGE_ROWS.

Ось мій зразок запиту:

SELECT PickingCompletedWhen
FROM Sales.Orders
WHERE PickingCompletedWhen >= '2016-05-24 11:00:01.000000'

Я оновив статистику для PickingCompletedWhen, після чого отримав гістограму:

DBCC SHOW_STATISTICS([sales.orders], '_WA_Sys_0000000E_44CA3770')

Гістограма для _WA_Sys_0000000E_44CA3770 (останні 3 кроки)

Щоб побачити, як зменшуються оцінені рядки, коли ми наближаємось до RANGE_HI_KEY, я збирав зразки протягом кроку. Зменшення лінійне, але поводиться так, ніби кількість рядків, рівних значенню AVG_RANGE_ROWS, просто не є частиною тренду ... доки ви не натиснете на RANGE_HI_KEY і раптом вони не скидаються як списаний борг. Ви можете бачити це у зразкових даних, особливо на графіку.

введіть тут опис зображення

Зверніть увагу на постійне зменшення рядків, поки ми не потрапимо на RANGE_HI_KEY, а потім на BOOM, який останній шматок AVG_RANGE_ROWS, раптом відняли. Це легко помітити і в графіку.

введіть тут опис зображення

Підводячи підсумок, непарне лікування AVG_RANGE_ROWS робить обчислення рядків складнішими, але ви завжди можете узгодити те, що робить CE.

Що з експоненціальним Бакоффом?

Експоненційний Backoff - це метод, який новий (станом на SQL Server 2014) Оцінювач кардинальності використовує для отримання кращих оцінок при використанні декількох статистичних даних про один стовпчик. Оскільки це питання стосувалося однієї стовпчикової статистики, воно не включає формулу EB.

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