Điều gì hiệu quả hơn, một mệnh đề where hoặc một phép nối với hàng triệu bảng hàng?


17

Chúng tôi điều hành một trang web có các hàng 250MM trong một bảng và trong một bảng khác mà chúng tôi tham gia với hầu hết các truy vấn chỉ dưới 15MM hàng.

Cấu trúc mẫu:

MasterTable (Id, UserId, Created, Updated...) -- 15MM Rows
DetailsTable (Id, MasterId, SomeColumn...) -- 250MM Rows
UserTable (Id, Role, Created, UserName...) -- 12K Rows

Chúng tôi thường xuyên phải thực hiện một vài truy vấn đối với tất cả các bảng này. Một là lấy số liệu thống kê cho người dùng miễn phí (~ 10k người dùng miễn phí).

Select Count(1) from DetailsTable dt 
join MasterTable mt on mt.Id = dt.MasterId 
join UserTable ut on ut.Id = mt.UserId 
where ut.Role is null and mt.created between @date1 and @date2

Vấn đề là truy vấn này đôi khi sẽ chạy một thời gian dài chết tiệt do thực tế là các phép nối xảy ra rất lâu trước khi có.

Trong trường hợp này, sẽ là khôn ngoan hơn khi sử dụng địa điểm thay vì tham gia hoặc có thể where column in(...)?


1
Cơ sở dữ liệu và phiên bản nào?
Leigh Riffel

1
bạn đã thử cả hai cách?
gbn

Nếu đây là Oracle, tôi sẽ tạo một chỉ mục dựa trên chức năng cho UserTable trên NVL2 (Vai trò, NULL, ID), nhưng nó trông giống như một DB khác.
Leigh Riffel

Câu trả lời:


20

Đối với RDBMS hiện đại, không có sự khác biệt giữa "THAM GIA rõ ràng" và "THAM GIA trong WHERE" (nếu tất cả THAM GIA là INNER) liên quan đến hiệu suất và kế hoạch truy vấn.

Cú pháp THAM GIA rõ ràng rõ ràng hơn và ít mơ hồ hơn (xem các liên kết bên dưới)

Bây giờ, THAM GIA trước-WHERE là xử lý logic chứ không phải xử lý thực tế và các trình tối ưu hóa hiện đại đủ thông minh để nhận ra điều này.

Vấn đề của bạn ở đây rất có thể là lập chỉ mục.

Vui lòng cho chúng tôi xem tất cả các chỉ mục và khóa trên các bảng này. Và các kế hoạch truy vấn

Lưu ý: câu hỏi này đã bị đóng trên StackOverflow vì bây giờ là một bản sao ... COUNT (1) so với COUNT (*) cũng là một huyền thoại bị đánh bại khác.


2
Nó không phải là luôn luôn đúng rằng không có sự khác biệt giữa joinwheremệnh đề. Tôi luôn tối ưu hóa các truy vấn chạy dài và đôi khi các truy vấn sử dụng wheremệnh đề hoạt động tốt hơn các truy vấn sử dụng jointheo hệ số lên tới 70 lần. Nếu nó đơn giản và dễ hiểu, cuộc sống sẽ chỉ có cầu vồng và kỳ lân. Và đây không phải là về một công cụ tối nghĩa cổ xưa nào đó - ngay bây giờ tôi đang xem xét lợi thế của wheremệnh đề
70 lần

Hơn nữa, tôi thường quan sát các kế hoạch chính xác giống nhau từ cả hai cách tiếp cận và cách ly các truy vấn thực hiện giống hệt nhau, nhưng khi wheretruy vấn mệnh đề chạy trong lô lớn, nó được coi là một phần của nó, nó vượt trội hơn jointruy vấn bởi một lề lớn. Các truy vấn SQL không thực thi trong chân không - chúng bị ảnh hưởng bởi phần còn lại của tải trọng máy chủ và thường thì các wheretruy vấn mệnh đề khá tốt, điều này gây khó chịu vì joincú pháp thực sự sạch hơn nhiều.
ajeh

3
@ajeh: Tôi muốn đề xuất rằng kinh nghiệm của bạn là rất không điển hình. Bạn có vấn đề lớn hơn với các truy vấn nếu bạn có x70 khác biệt: thật đơn giản
gbn

5

Bạn phải cấu trúc lại truy vấn hoàn toàn

Hãy thử thực hiện các mệnh đề WHERE trước đó và THAM GIA sau

Select Count(1) from DetailsTable dt
join (Select UserId,Id FROM MasterTable where
created between @date1 and @date2) mt on mt.Id = dt.MasterId 
join (Select Id FROM UserTable WHERE Role is NULL) ut
on ut.Id = mt.UserId;

Ngay cả khi bạn chạy gói EXPLAIN trên truy vấn được cấu trúc lại này và nó có vẻ tệ hơn bản gốc của bạn, hãy thử dù sao đi nữa. Các bảng tạm thời được tạo bên trong sẽ thực hiện các phép nối cartesian nhưng các bảng đó nhỏ hơn để làm việc.

Tôi có ý tưởng này từ video YouTube này .

Tôi đã thử các nguyên tắc từ video trong một câu hỏi rất phức tạp trong StackOverflow và nhận được tiền thưởng 200 điểm.

@gbn đề cập đến việc đảm bảo bạn có đúng chỉ mục. Trong trường hợp này, vui lòng lập chỉ mục cột đã tạo trong MasterTable.

Hãy thử một lần !!!

CẬP NHẬT 2011-06-24 22:31 EDT

Bạn nên chạy các truy vấn sau:

SELECT COUNT(1) AllRoles FROM UserTable;
SELECT COUNT(1) NullRoles FROM UserTable WHERE Role is NULL;

Nếu NullRoles X 20 <AllRoles (nói cách khác, nếu NullRoles nhỏ hơn 5% số hàng của bảng), bạn nên tạo một chỉ mục không duy nhất là Vai trò trong UserTable. Mặt khác, một bảng đầy đủ của UserTable sẽ đủ vì Trình tối ưu hóa truy vấn có thể loại trừ bằng cách sử dụng một chỉ mục.

CẬP NHẬT 2011-06-25 12:40 EDT

Vì tôi là một DBA của MySQL, nên phương pháp làm việc của tôi đòi hỏi không tin vào Trình tối ưu hóa truy vấn MySQL thông qua sự bi quan tích cực và bảo thủ. Do đó, tôi sẽ thử cấu trúc lại một truy vấn hoặc tạo các chỉ mục bao quát cần thiết để vượt qua các thói quen xấu tiềm ẩn của Trình truy vấn MySQL. Câu trả lời của @ gbn dường như đầy đủ hơn trong SQL Server có thể có nhiều truy vấn đánh giá "đúng đắn hơn".


0

Chúng tôi đã có một bảng [Chi tiết] khoảng 75M hàng; bảng [Chính] khoảng 400K hàng và bảng [Mục] có liên quan có 7 hàng - luôn luôn và mãi mãi. Nó lưu trữ một tập hợp nhỏ các số vật phẩm của Nhật Bản (1-7) và đang mô hình hóa một mẫu giấy, hàng triệu được in và phân phát mỗi tháng. Truy vấn nhanh nhất là câu hỏi mà bạn ít nghĩ đến đầu tiên, liên quan đến việc sử dụng Cartesian Join. IIRC, nó giống như:

SELECT m.order_id, i.line_nr, d.Item_amt
FROM Master m, Item i 
INNER JOIN Detail d ON m.order_id = d.order_id

Mặc dù có một liên kết logic id tốt giữa [Mục] và [Chi tiết] CROSS THAM GIA hoạt động tốt hơn INNER THAM GIA.

RDBMS là Teradata với công nghệ MPP của nó và IDR là lược đồ lập chỉ mục. Bảng 7 hàng không có chỉ số vì TABLE SCAN luôn hoạt động tốt nhấ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.