Оцінка кардинальності поза гістограмою


14

Налаштування

У мене виникають проблеми з розумінням оцінки кардинальності. Ось моя тестова установка:

  • версія 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).

На запит прогнозного плану для цього "розрахункові рядки", які виходять, становлять 1 dbo.Posts934,99:

EXEC #sp_PostsByCommentCount @CommentCount = 51;

Наступний об’єкт статистики був автоматично створений, коли я запитав прогнозний план:

DBCC SHOW_STATISTICS('dbo.Posts', [_WA_Sys_00000006_0519C6AF]);

скріншот виводу статистики в SSMS

Основні моменти цього:

  • Статистика має досить низький рівень вибірки 1,81% (67,796 / 3,744,192)
  • Було використано лише 31 крок гістограми
  • Значення "Вся щільність" 0.03030303(33 вибіркових значення були відібрані)
  • Остання RANGE_HI_KEYв гістограмі - 50, з EQ_ROWS1

Питання

Передача будь-якого значення, що перевищує 50 (аж до 2147,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, привів мене до деяких публікацій у блозі:

Ці повідомлення вказують на нову основу СЕ ці зовнішні оцінки гістограми на поєднанні вектора щільності та лічильника модифікації стати. На жаль, я вже виключив вектор щільності (я думаю ?!), а лічильник модифікацій дорівнює нулю (у 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калькулятора.

Відповіді:


13

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

У вашому випадку 1,934,99 = SQRT (3744192)

Налаштування тестування нижче:

--setup
USE TestDB
ALTER DATABASE [TestDB] SET AUTO_UPDATE_STATISTICS OFF
GO

DROP TABLE IF EXISTS dbo.Hist

CREATE TABLE dbo.Hist (
ID int identity primary key,
Num int
)

INSERT dbo.Hist
SELECT TOP 300
(ROW_NUMBER() OVER(ORDER BY(SELECT 1/0)))%3
FROM master..spt_values a
CROSS JOIN master..spt_values b
--Get estimated plan
--don't forget to run right after setup to auto-create stats
SELECT *
FROM dbo.Hist
WHERE Num = 1000
--gradually add rows, then rerun estimate above
INSERT dbo.Hist
SELECT TOP 100
-1
FROM master..spt_values a
--I sure hope you weren't testing this in prod (cleanup)
ALTER DATABASE [TestDB] SET AUTO_UPDATE_STATISTICS ON
GO

Напрочуд, навіть такі оцінки рядків були сформовані з цього підходу: 20 на 400 усього рядків, 30 на 900, 40 на 1600 тощо.

Однак за минулий 10000 оцінка рядків досягає 100, тобто кількість рядків на значення в існуючих статистичних даних. Якщо додати лише 10 рядків, встановити оцінку буде 10, оскільки sqrt (300)> 10.

Таким чином, оцінки можна виразити за такою формулою:

Estimate = MIN(SQRT(AC), MIN(AR, MC))

Зауважте, що якщо статистичні дані вибірюються, то MC не враховується. Тож формула стає:

Estimate = MIN(SQRT(AC), AR))

Де

  • MC - "кількість змін" (# модифікацій з моменту створення статистики)
  • AC - це "скоригована кардинальність" (кількість рядків зі статистики плюс MC),
  • AR - середнє число рядків на значення (кількість рядків зі статистичних даних, поділене на окремі значення у стовпці)

Формули для цих оцінок та інші подробиці про калькулятор можна знайти в цьому дописі в блозі: Аналіз оцінок з калькулятора CSelCalcAscendingKeyFilter

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