Я тестировал на SQL Server 2014 с устаревшим CE и не получил 9% в качестве оценки мощности. Я не смог найти ничего точного в Интернете, поэтому я провел некоторое тестирование и нашел модель, которая подходит для всех тестовых случаев, которые я пробовал, но я не уверен, что она завершена.
В модели, которую я нашел, оценка получается из числа строк в таблице, средней длины ключа статистики для отфильтрованного столбца и иногда длины типа данных отфильтрованного столбца. Для оценки используются две разные формулы.
Если FLOOR (средняя длина ключа) = 0, тогда формула оценки игнорирует статистику столбца и создает оценку на основе длины типа данных. Я тестировал только с VARCHAR (N), поэтому возможно, что есть другая формула для NVARCHAR (N). Вот формула для VARCHAR (N):
(оценка строки) = (строки в таблице) * (-0,004869 + 0,032649 * log10 (длина типа данных))
Это очень хорошо подходит, но не совсем точно:
Ось X - это длина типа данных, а ось Y - это количество оценочных строк для таблицы с 1 миллионом строк.
Оптимизатор запросов будет использовать эту формулу, если у вас нет статистики по столбцу или если в столбце достаточно значений NULL, чтобы средняя длина ключа была ниже 1.
Например, предположим, что у вас была таблица с 150 тыс. Строк с фильтрацией по VARCHAR (50) и без статистики по столбцам. Прогноз оценки строки:
150000 * (-0,004869 + 0,032649 * log10 (50)) = 7590,1 строки
SQL, чтобы проверить это:
CREATE TABLE X_CE_LIKE_TEST_1 (
STRING VARCHAR(50)
);
CREATE STATISTICS X_STAT_CE_LIKE_TEST_1 ON X_CE_LIKE_TEST_1 (STRING) WITH NORECOMPUTE;
WITH
L0 AS (SELECT 1 AS c UNION ALL SELECT 1),
L1 AS (SELECT 1 AS c FROM L0 A CROSS JOIN L0 B),
L2 AS (SELECT 1 AS c FROM L1 A CROSS JOIN L1 B),
L3 AS (SELECT 1 AS c FROM L2 A CROSS JOIN L2 B),
L4 AS (SELECT 1 AS c FROM L3 A CROSS JOIN L3 B CROSS JOIN L2 C),
NUMS AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS NUM FROM L4)
INSERT INTO X_CE_LIKE_TEST_1 WITH (TABLOCK) (STRING)
SELECT TOP (150000) 'ZZZZZ'
FROM NUMS
ORDER BY NUM;
DECLARE @LastName VARCHAR(15) = 'BA%'
SELECT * FROM X_CE_LIKE_TEST_1
WHERE STRING LIKE @LastName;
SQL Server дает приблизительное количество строк в 7242,47, что довольно близко.
Если FLOOR (средняя длина ключа)> = 1, то используется другая формула, основанная на значении FLOOR (средняя длина ключа). Вот таблица некоторых значений, которые я пробовал:
1 1.5%
2 1.5%
3 1.64792%
4 2.07944%
5 2.41416%
6 2.68744%
7 2.91887%
8 3.11916%
9 3.29584%
10 3.45388%
Если FLOOR (средняя длина ключа) <6, используйте таблицу выше. В противном случае используйте следующее уравнение:
(оценка строки) = (строки в таблице) * (-0,003381 + 0,034539 * log10 (FLOOR (средняя длина ключа)))
Этот лучше подходит, чем другой, но все еще не совсем точен.
Ось X - это средняя длина ключа, а ось Y - количество оценочных строк для таблицы с 1 миллионом строк.
Чтобы привести другой пример, предположим, что у вас была таблица с 10 тыс. Строк со средней длиной ключа 5,5 для статистики по отфильтрованному столбцу. Оценка строки будет:
10000 * 0,241416 = 241,416 строк.
SQL, чтобы проверить это:
CREATE TABLE X_CE_LIKE_TEST_2 (
STRING VARCHAR(50)
);
WITH
L0 AS (SELECT 1 AS c UNION ALL SELECT 1),
L1 AS (SELECT 1 AS c FROM L0 A CROSS JOIN L0 B),
L2 AS (SELECT 1 AS c FROM L1 A CROSS JOIN L1 B),
L3 AS (SELECT 1 AS c FROM L2 A CROSS JOIN L2 B),
L4 AS (SELECT 1 AS c FROM L3 A CROSS JOIN L3 B CROSS JOIN L2 C),
NUMS AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS NUM FROM L4)
INSERT INTO X_CE_LIKE_TEST_2 WITH (TABLOCK) (STRING)
SELECT TOP (10000)
CASE
WHEN NUM % 2 = 1 THEN REPLICATE('Z', 5)
ELSE REPLICATE('Z', 6)
END
FROM NUMS
ORDER BY NUM;
CREATE STATISTICS X_STAT_CE_LIKE_TEST_2 ON X_CE_LIKE_TEST_2 (STRING)
WITH NORECOMPUTE, FULLSCAN;
DECLARE @LastName VARCHAR(15) = 'BA%'
SELECT * FROM X_CE_LIKE_TEST_2
WHERE STRING LIKE @LastName;
Оценка строки 241,416 соответствует тому, что у вас есть в вопросе. Там было бы какая-то ошибка, если бы я использовал значение не в таблице.
Модели здесь не идеальны, но я думаю, что они довольно хорошо иллюстрируют общее поведение.