Ước tính Cardinality cho toán tử THÍCH (Biến cục bộ)


24

Tôi có ấn tượng rằng khi sử dụng LIKEtoán tử trong tất cả các tối ưu hóa cho các kịch bản chưa biết, cả di sản và CE mới đều sử dụng ước tính 9% (giả sử rằng các số liệu thống kê có liên quan có sẵn và trình tối ưu hóa truy vấn không phải dùng đến các phỏng đoán chọn lọc).

Khi thực hiện truy vấn dưới đây đối với cơ sở dữ liệu tín dụng, tôi nhận được các ước tính khác nhau theo các CE khác nhau. Theo CE mới, tôi nhận được ước tính 900 hàng mà tôi đang mong đợi, theo CE kế thừa tôi nhận được ước tính là 241.416 và tôi không thể tìm ra cách ước tính này được rút ra. Có ai có thể làm sáng tỏ?

-- New CE (Estimate = 900)
DECLARE @LastName VARCHAR(15) = 'BA%'
SELECT * FROM [Credit].[dbo].[member]
WHERE [lastname] LIKE @LastName;

-- Forcing Legacy CE (Estimate = 241.416)
DECLARE @LastName VARCHAR(15) = 'BA%'
SELECT * FROM [Credit].[dbo].[member]
WHERE [lastname] LIKE @LastName
OPTION (
QUERYTRACEON 9481,
QUERYTRACEON 9292,
QUERYTRACEON 9204,
QUERYTRACEON 3604
);

Trong kịch bản của tôi, tôi đã có cơ sở dữ liệu tín dụng được đặt ở mức tương thích 120, do đó tại sao trong truy vấn thứ hai tôi sử dụng cờ theo dõi để buộc CE kế thừa và cũng cung cấp thông tin về những gì được sử dụng / xem xét bởi trình tối ưu hóa truy vấn. Tôi có thể thấy số liệu thống kê cột trên 'họ' đang được sử dụng nhưng tôi vẫn không thể tìm ra cách ước tính của 241.416.

Tôi không thể tìm thấy bất cứ điều gì trực tuyến ngoài bài viết này của Itzik Ben-Gan , trong đó nêu rõ "Khi sử dụng vị từ THÍCH trong tất cả các tối ưu hóa cho các kịch bản chưa biết cả di sản và CE mới đều sử dụng ước tính 9%.". Thông tin trong bài đăng đó sẽ xuất hiện không chính xác.

Câu trả lời:


28

Dự đoán LIKE trong trường hợp của bạn dựa trên:

  • G: 9% đoán chuẩn ( sqllang!x_Selectivity_Like)
  • M: Hệ số 6 (số ma thuật)
  • D: Độ dài dữ liệu trung bình tính bằng byte (từ thống kê), làm tròn xuống thành số nguyên

Cụ thể, sqllang!CCardUtilSQL7::ProbLikeGuesssử dụng:

Selectivity (S) = G / M * LOG(D)

Ghi chú:

  • Các LOG(D)thuật ngữ được bỏ qua nếu Dlà giữa 1 và 2.
  • Nếu Dnhỏ hơn 1 (bao gồm thiếu hoặc NULLthống kê):
    D = FLOOR(0.5 * maximum column byte length)

Kiểu khó hiểu và phức tạp này khá điển hình của CE gốc.

Trong ví dụ câu hỏi, độ dài trung bình là 5 (5.654 từ DBCC SHOW_STATISTICSlàm tròn xuống):

Ước tính = 10.000 * (0,09 / 6 * LOG (5)) = 241.416

Các giá trị mẫu khác:

 D   = Ước tính sử dụng công thức cho S
 15 = 406.208
 14 = 395.859
 13 = 384.742
 12 = 372.736
 11 = 359,684
 10 = 345.388
 09 = 329.584
 08 = 311.916
 07 = 291.887
 06 = 268,764
 05 = 241.416
 04 = 207.944
 03 = 164,792
 02 = 150.000 (LOG không được sử dụng)
 01 = 150.000 (LOG không được sử dụng)
 00 = 291.887 (LOG 7) / * FLOOR (0.5 * 15) [15 vì tên cuối cùng là varchar (15)] * /

Kiểm tra giàn khoan

DECLARE
    @CharLength integer = 5, -- Set length here
    @Counter integer = 1;

CREATE TABLE #T (c1 varchar(15) NULL);

-- Add 10,000 rows
SET NOCOUNT ON;
SET STATISTICS XML OFF;

BEGIN TRANSACTION;
WHILE @Counter <= 10000
BEGIN
    INSERT #T (c1) VALUES (REPLICATE('X', @CharLength));
    SET @Counter = @Counter + 1;
END;
COMMIT TRANSACTION;

SET NOCOUNT OFF;
SET STATISTICS XML ON;

-- Test query
DECLARE @Like varchar(15);
SELECT * FROM #T AS T 
WHERE T.c1 LIKE @Like;

DROP TABLE #T;

15

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:

đồ thị công thức đầu tiên

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.

đồ thị công thức thứ hai

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.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.