Tôi đã thử nghiệm trên SQL Server 2014 với CE kế thừa và cũng không nhận được 9% như ước tính về số lượng thẻ. Tôi không thể tìm thấy bất cứ điều gì chính xác trực tuyến vì vậy tôi đã thực hiện một số thử nghiệm và tôi đã tìm thấy một mô hình phù hợp với tất cả các trường hợp thử nghiệm mà tôi đã thử, nhưng tôi không thể chắc chắn rằng nó đã hoàn thành.
Trong mô hình mà tôi tìm thấy, ước tính được lấy từ số lượng hàng trong bảng, độ dài khóa trung bình của số liệu thống kê cho cột được lọc và đôi khi là độ dài kiểu dữ liệu của cột được lọc. Có hai công thức khác nhau được sử dụng để ước tính.
Nếu FLOOR (độ dài khóa trung bình) = 0 thì công thức ước tính bỏ qua số liệu thống kê cột và tạo ước tính dựa trên độ dài kiểu dữ liệu. Tôi chỉ thử nghiệm với VARCHAR (N) để có thể có một công thức khác cho NVARCHAR (N). Đây là công thức cho VARCHAR (N):
(ước tính hàng) = (hàng trong bảng) * (-0.004869 + 0.032649 * log10 (độ dài của loại dữ liệu))
Điều này có một sự phù hợp rất tốt đẹp, nhưng nó không hoàn toàn chính xác:
Trục x là chiều dài của kiểu dữ liệu và trục y là số lượng hàng ước tính cho một bảng có 1 triệu hàng.
Trình tối ưu hóa truy vấn sẽ sử dụng công thức này nếu bạn không có số liệu thống kê trên cột hoặc nếu cột có đủ giá trị NULL để điều khiển độ dài khóa trung bình xuống dưới 1.
Ví dụ: giả sử bạn có một bảng có 150 nghìn hàng với tính năng lọc trên VARCHAR (50) và không có thống kê cột. Dự đoán ước tính hàng là:
150000 * (-0.004869 + 0.032649 * log10 (50)) = 7590.1 hàng
SQL để kiểm tra nó:
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 đưa ra số lượng hàng ước tính là 7242,47, đây là loại gần đúng.
Nếu FLOOR (độ dài khóa trung bình)> = 1 thì một công thức khác được sử dụng dựa trên giá trị của FLOOR (độ dài khóa trung bình). Dưới đây là bảng một số giá trị mà tôi đã thử:
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%
Nếu FLOOR (độ dài khóa trung bình) <6 thì sử dụng bảng trên. Mặt khác sử dụng phương trình sau:
(ước tính hàng) = (hàng trong bảng) * (-0.003381 + 0,034539 * log10 (FLOOR (độ dài khóa trung bình)))
Cái này phù hợp hơn cái kia, nhưng nó vẫn không hoàn toàn chính xác.
Trục x là chiều dài khóa trung bình và trục y là số lượng hàng ước tính cho một bảng có 1 triệu hàng.
Để đưa ra một ví dụ khác, giả sử rằng bạn có một bảng có 10k hàng với độ dài khóa trung bình là 5,5 cho các số liệu thống kê trên cột được lọc. Ước tính hàng sẽ là:
10000 * 0,241416 = 241,416 hàng.
SQL để kiểm tra nó:
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;
Ước tính hàng là 241.416 phù hợp với những gì bạn có trong câu hỏi. Sẽ có một số lỗi nếu tôi sử dụng một giá trị không có trong bảng.
Các mô hình ở đây không hoàn hảo nhưng tôi nghĩ rằng chúng minh họa hành vi chung khá tốt.