Оценка мощности вне гистограммы

14

Настроить

У меня возникли проблемы с пониманием оценки количества элементов. Вот моя тестовая установка:

  • версия базы данных Stack Overflow 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).

Когда запрашивается примерный план для этого, «ожидаемые строки» выходят из dbo.Posts1934,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 (до 2 147 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 привело меня к некоторым постам в блоге:

Эти посты показывают, что новые CE основывают эти оценки вне гистограммы на комбинации вектора плотности и счетчика модификаций статистики. К сожалению, я уже исключил вектор плотности (я думаю ?!), и счетчик модификации равен нулю ( 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

Форрест
источник