Tìm kiếm vị ngữ không sử dụng tất cả các cột có sẵn


8

Tôi có một vấn đề biên dịch truy vấn lạ rất khó để sao chép. Nó chỉ xảy ra dưới tải cao và không thể dễ dàng lặp lại.

  • Có một bảng T với các cột A, B, C, D.
  • Có một chỉ số cụm không duy nhất trên T (A, B, C, D).
  • Có một truy vấn CHỌN * TỪ T WHERE A = @ P1 VÀ B = @ P2 VÀ (C = @ P3 HOẶC C = @ P4) VÀ D = @ P5. Điều kiện tìm kiếm nằm trên tất cả các cột của chỉ mục được nhóm, cột 3 có OR.

Vấn đề là kế hoạch truy vấn cho truy vấn này chỉ có Tìm kiếm Dự đoán trên A và B! Vị từ trên C và D là một vị từ thông thường, vì vậy điều này có nghĩa là cây tìm kiếm trên cột C và D không được sử dụng.

Các kiểu dữ liệu cho tất cả các tham số khớp với các kiểu dữ liệu cột.

Bất cứ ai có thể cung cấp bất kỳ gợi ý về lý do tại sao điều này có thể xảy ra? Phiên bản SQL là 2008 R2 (SP1) - 10.50.2789.0 (X64)


Bạn có bao giờ thực sự có được một kế hoạch cho một truy vấn được tham số hóa thực hiện tìm kiếm bình đẳng trên tất cả 4 cột không? Nếu vậy bạn đang sử dụng OPTION (RECOMPILE)?
Martin Smith

Câu trả lời:


8

Đối với một truy vấn được tham số hóa Nó không thể thực hiện hai lần tìm kiếm trên

WHERE A=@P1 AND B=@P2 AND C=@P3 AND D=@P5 

WHERE A=@P1 AND B=@P2 AND C=@P4 AND D=@P5 

Bởi vì nếu @P3 = @P4điều đó sẽ không chính xác mang lại hàng trùng lặp. Vì vậy, nó sẽ cần một toán tử loại bỏ các bản sao khỏi những cái này trước.

Từ một thử nghiệm nhanh, kết thúc này dường như phụ thuộc vào kích thước của bảng cho dù bạn có nhận được điều đó hay không. Trong thử nghiệm bên dưới 245/ 246hàng là điểm cắt giữa các kế hoạch (đây cũng là điểm cắt giữa chỉ số phù hợp tất cả trên một trang và nó trở thành 2 trang lá và trang gốc).

CREATE TABLE T(A INT,B INT,C INT,D INT)

INSERT INTO T
SELECT TOP (245) 1,2,3,5
FROM master..spt_values v1

CREATE CLUSTERED INDEX IX ON T(A, B, C, D)

SELECT index_level,page_count, record_count
FROM sys.dm_db_index_physical_stats(db_id(),object_id('T'),1,NULL, 'DETAILED')

DECLARE @C1 INT = 3,
        @C2 INT = 4

 SELECT * FROM T WHERE A=1 AND B=2 AND (C=@C1 OR C=@C2) AND D=5

 DROP TABLE T

1 trang / 245 hàng

Kế hoạch này có một tìm kiếm A=1 AND B=2với một vị từ còn lại trên(C=@C1 OR C=@C2) AND D=5

Kế hoạch 1

2 trang lá / 246 hàng

Kế hoạch 2

Trong kế hoạch thứ hai, các toán tử bổ sung có trách nhiệm loại bỏ bất kỳ bản sao nào @C1,@C2trước tiên trước khi thực hiện tìm kiếm.

Tìm kiếm trong kế hoạch thứ hai thực sự là một phạm vi tìm kiếm giữa A=1 AND B=2 AND C > Expr1010A=1 AND B=2 AND C < Expr1011với một vị từ còn lại trên D=5. Nó vẫn không phải là một tìm kiếm bình đẳng trên tất cả 4 cột. Thông tin thêm về các nhà khai thác kế hoạch bổ sung có thể được tìm thấy ở đây .

Việc thêm vào OPTION (RECOMPILE)cho phép nó kiểm tra các giá trị tham số cho các bản sao tại thời gian biên dịch và tạo ra một kế hoạch với hai lần tìm kiếm bằng nhau.

Bạn cũng có thể đạt được điều đó với

;WITH CTE
     AS (SELECT DISTINCT ( C )
         FROM   (VALUES (@C1),
                        (@C2)) V(C))
SELECT CA.*
FROM   CTE
       CROSS APPLY (SELECT *
                    FROM   T
                    WHERE A=1 AND B=2 AND D=5  AND C = CTE.C) CA

Kế hoạch 3

Nhưng thực tế trong trường hợp thử nghiệm này, nó có thể sẽ phản tác dụng khi có hai lần tìm kiếm vào chỉ mục trang duy nhất thay vì một lần tăng IO logic.


1
Đã làm một số thử nghiệm cho câu hỏi này tối qua trước khi bạn thêm nhận xét đầu tiên của bạn. Tôi đã đi xa khi nhìn thấy hành vi nhưng không hiểu được nguyên nhân gây ra nó (@ P3 = @ P4) nên +1 cho điều đó (đã làm). Tôi nghĩ rằng a select .. union select ...cũng sẽ cung cấp cho bạn hai lần tìm kiếm cộng với bước bổ sung loại bỏ trùng lặp khỏi kết quả.
Mikael Eriksson

1
@MikaelEriksson - Nhưng SELECT * FROM T WHERE A=1 AND B=2 AND C=@C1 AND D=5 UNION SELECT * FROM T WHERE A=1 AND B=2 AND C=@C2 AND D=5có thể loại bỏ không chính xác các bản sao cần được trả lại. Trong dữ liệu ví dụ của tôi, nơi tôi lười biếng điền tất cả với cùng một giá trị, nó sẽ trả về 1 hàng không256
Martin Smith

2
À, vâng. Và OP thậm chí đã chỉ định rằng khóa này là duy nhất. Lucke tôi tôi đã không cố gắng trả lời câu hỏi này :).
Mikael Eriksson

4

Hoàn toàn đồng ý với phân tích của Martin. Truy vấn này không thể tạo ra một tìm kiếm trên tất cả 4 cột do vị từ OR, trừ khi (có thể) với TÙY CHỌN (RECOMPILE). Tôi đoán đây là một truy vấn kim tiêm, có lẽ bạn không muốn có thêm chi phí.

Còn cái này thì sao:

IF @P3=@P4
    SELECT * FROM T WHERE A=@P1 AND B=@P2 AND C=@P3 AND D=@P5.
ELSE
    SELECT * FROM T WHERE A=@P1 AND B=@P2 AND C=@P3 AND D=@P5.
    UNION ALL
    SELECT * FROM T WHERE A=@P1 AND B=@P2 AND C=@P4 AND D=@P5.

Tôi đã không kiểm tra điều này nhưng phần khác sẽ đưa ra 2 lần tìm kiếm trên cả 4 giá trị và một liên minh giá rẻ thông qua việc ghép nối. Trong trường hợp khi cả hai tìm kiếm kết thúc trong cùng một trang, tôi không nghĩ rằng một trang logic đọc thêm sẽ thêm nhiều thời gian. Tuy nhiên, tùy thuộc vào dữ liệu của bạn, hai tìm kiếm rất có thể ở các trang khác nhau.

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.