Tại sao ĐẶT HÀNG của tôi sắp xếp hai bảng trước EXCEPT (chậm) và không sau (nhanh)?


12

Câu đố tối ưu hóa truy vấn SQL server 2008 R2

Chúng tôi có hai bảng, cả hai đều chứa 9 triệu hàng. 70.000 hàng là khác nhau, những hàng khác là như nhau.

Tốc độ này nhanh, 13 giây,

select * from bigtable1
except select * from similar_bigtable2

Điều này sắp xếp đầu ra và cũng nhanh, 13 giây là tốt,

select * into #q from bigtable1
except select * from similar_bigtable2
select * from #q order by sort_column

Trong khi điều này là rất chậm:

;with q as (
    select * from bigtable1
    except select * from similar_bigtable2
)
select * from q order by sort_column

Và thậm chí một "mẹo" mà đôi khi tôi sử dụng để gợi ý SQL Server rằng nó cần phải tính toán trước một phần nhất định của truy vấn trước khi tiếp tục, không hoạt động và cũng dẫn đến truy vấn chậm:

;with q as (
    select top 100 percent * from bigtable1
    except select * from similar_bigtable2
)
select * from q order by sort_column

Nhìn vào các kế hoạch truy vấn, lý do không khó để tìm thấy:

Kế hoạch truy vấn Gói truy vấn với ORDER BY

SQL Server đặt hai loại 9 triệu hàng trước hashmatch, trong khi tôi muốn nó chỉ thêm một loại 70.000 hàng sau hashmatch.

Vì vậy, câu hỏi: làm thế nào tôi có thể hướng dẫn trình tối ưu hóa truy vấn để làm điều đó?


3
Nó không sắp xếp trước hashmatch, nó sắp xếp và sau đó thực hiện hợp nhất (không phải là băm-tham gia). Có lẽ có một gợi ý để buộc tham gia băm (hoặc ngăn chặn tham gia hợp nhất)?
Thilo

3
Có vẻ như trình tối ưu hóa truy vấn SQL Server đã xác định rằng việc sắp xếp dữ liệu là có lợi để nó có thể sử dụng Merge Join nhanh hơn nhiều (chỉ hoạt động đối với dữ liệu được sắp xếp) thay vì chậm hơn Hash Match Join hoặc Nested Loop Join ....
marc_s

9
Bạn đã thử thay thế EXCEPT(ví dụ OUTER JOIN)? Tôi nhận ra cú pháp ít thuận tiện hơn nhưng bạn có thể chơi với gợi ý chỉ mục / tham gia tốt hơn ở đó (hoặc bạn có thể không cần). Cách thay thế bạn đang sử dụng bây giờ (đưa vào bảng #temp trước) là cách giải quyết cuối cùng nhưng trong một số trường hợp là cách duy nhất để buộc trình tối ưu hóa tách biệt hoàn toàn hai phần của truy vấn theo cách bạn muốn.
Aaron Bertrand

Câu trả lời:


1

Sự khác biệt chính giữa hai kế hoạch truy vấn này thực tế là ở sự khác biệt của Hash Match và Hợp nhất Tham gia. Hash Match hiệu quả hơn và như bạn có thể thấy truy vấn chạy nhanh hơn trong tùy chọn 1 (không sử dụng CTE).

CTE là một công cụ tuyệt vời, nhưng dường như nó không hiệu quả trong hai trường hợp, Dự báo phức tạp hoặc Khóa cha / con không độc đáo. Trong trường hợp của bạn, không có khóa duy nhất và máy chủ SQL phải sắp xếp các bộ dữ liệu trước để có thể đáp ứng yêu cầu của bạn. Hãy xem liên kết dưới đây để cho bạn biết thêm về vấn đề này: http://bloss.msdn.com/b/sqlcat/archive/2011/04/28/optizes-recursive-cte-query.aspx

Vì vậy, có vẻ như bạn phải chấp nhận sự chậm chạp của nó hoặc viết lại logic với vòng lặp WHILE có thể hiệu quả hơn.


0

Hãy thử điều này, tốt hơn?

select * from
(
    select * from bigtable1
    except 
    select * from similar_bigtable2
) t
order by sort_column

0

Đây không phải là một giải pháp lý tưởng nhưng nếu bạn không thể cấu trúc tsql để tạo ra một kế hoạch hiệu quả, bạn có thể đặt một hướng dẫn kế hoạch để buộc kế hoạch bạn muốn. Làm điều này có nghĩa là nếu một kế hoạch hiệu quả hơn trở nên khả dụng thì SQL sẽ không xem xét nó nhưng đó là một tùy chọn.

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.