Probé en SQL Server 2014 con el CE heredado y tampoco obtuve un 9% como estimación de cardinalidad. No pude encontrar nada preciso en línea, así que hice algunas pruebas y encontré un modelo que se ajusta a todos los casos de prueba que probé, pero no puedo estar seguro de que esté completo.
En el modelo que encontré, la estimación se deriva del número de filas en la tabla, la longitud de clave promedio de las estadísticas para la columna filtrada y, a veces, la longitud del tipo de datos de la columna filtrada. Hay dos fórmulas diferentes utilizadas para la estimación.
Si FLOOR (longitud de clave promedio) = 0, la fórmula de estimación ignora las estadísticas de la columna y crea una estimación basada en la longitud del tipo de datos. Solo probé con VARCHAR (N), por lo que es posible que haya una fórmula diferente para NVARCHAR (N). Aquí está la fórmula para VARCHAR (N):
(estimación de fila) = (filas en la tabla) * (-0.004869 + 0.032649 * log10 (longitud del tipo de datos))
Esto tiene un ajuste muy agradable, pero no es perfectamente preciso:
El eje x es la longitud del tipo de datos y el eje y es el número de filas estimadas para una tabla con 1 millón de filas.
El optimizador de consultas usaría esta fórmula si no tuviera estadísticas en la columna o si la columna tiene suficientes valores NULL para conducir la longitud de clave promedio a menos de 1.
Por ejemplo, suponga que tiene una tabla con 150k filas con filtrado en un VARCHAR (50) y sin estadísticas de columna. La predicción de la estimación de la fila es:
150000 * (-0.004869 + 0.032649 * log10 (50)) = 7590.1 filas
SQL para probarlo:
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 proporciona un recuento de filas estimado de 7242.47, que es un poco cerrado.
Si FLOOR (longitud de clave promedio)> = 1, se utiliza una fórmula diferente que se basa en el valor de FLOOR (longitud de clave promedio). Aquí hay una tabla de algunos de los valores que probé:
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%
Si FLOOR (longitud de clave promedio) <6, use la tabla anterior. De lo contrario, use la siguiente ecuación:
(estimación de fila) = (filas en la tabla) * (-0.003381 + 0.034539 * log10 (PISO (longitud de clave promedio)))
Este tiene un mejor ajuste que el otro, pero aún no es perfectamente preciso.
El eje x es la longitud promedio de la clave y el eje y es el número de filas estimadas para una tabla con 1 millón de filas.
Para dar otro ejemplo, suponga que tiene una tabla con 10k filas con una longitud de clave promedio de 5.5 para las estadísticas en la columna filtrada. La estimación de la fila sería:
10000 * 0.241416 = 241.416 filas.
SQL para probarlo:
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;
La estimación de la fila es 241.416, que coincide con lo que tiene en la pregunta. Habría algún error si usara un valor que no está en la tabla.
Los modelos aquí no son perfectos, pero creo que ilustran bastante bien el comportamiento general.