2011-06-23 73 views
5

Tôi là một truy vấn MySQL noobie vì vậy tôi chắc chắn đây là câu hỏi có câu trả lời rõ ràng.Nhóm MySQL theo và CÓ

Nhưng, tôi đã xem xét hai truy vấn này. Họ sẽ trả về các bộ kết quả khác nhau? Tôi hiểu rằng quá trình phân loại sẽ bắt đầu khác nhau, nhưng tôi tin rằng họ sẽ trả lại kết quả tương tự với truy vấn đầu tiên có hiệu quả hơn một chút?

Query 1: CÓ, sau đó VÀ

SELECT user_id 
FROM forum_posts 
GROUP BY user_id 
    HAVING COUNT(id) >= 100 
    AND user_id NOT IN (SELECT user_id FROM banned_users) 

Query 2: WHERE, sau đó CÓ

SELECT user_id 
FROM forum_posts 
WHERE user_id NOT IN(SELECT user_id FROM banned_users) 
GROUP BY user_id 
    HAVING COUNT(id) >= 100 

Trả lời

1

Trên thực tế truy vấn đầu tiên sẽ ít hiệu quả (HAVING áp dụng sau khi WHERE).
CẬP NHẬT

Một số mã giả để minh họa cách truy vấn của bạn được thực hiện ([rất] phiên bản đơn giản).
truy vấn đầu tiên:
1. SELECT user_id FROM forum_posts
2. SELECT user_id FROM banned_user
3. Group, đếm vv
4. Loại trừ hồ sơ từ kết quả đầu tiên được thiết lập nếu họ được thể hiện trong phần thứ hai

Thứ hai truy vấn
1. SELECT user_id FROM forum_posts
2. SELECT user_id FROM banned_user
3. Loại trừ hồ sơ từ kết quả đầu tiên được thiết lập nếu họ được thể hiện trong phần thứ hai
4. Nhóm, số, vv

Thứ tự các bước 1,2 không quan trọng, mysql có thể chọn bất cứ điều gì nó nghĩ là tốt hơn. Điểm khác biệt quan trọng là ở bước 3.4. Có được áp dụng sau GROUP BY. Việc nhóm thường tốn kém hơn việc tham gia (không bao gồm các hồ sơ có thể được coi là hoạt động tham gia trong trường hợp này), vì vậy ít bản ghi hơn phải nhóm, hiệu suất tốt hơn.

+0

tuyệt vời, cảm ơn! Thú vị, tôi sẽ phải chạy một số xét nghiệm. Tôi nghĩ hiệu quả hơn bởi vì có ít hồ sơ để so sánh phần NOT IN banned_users sau khi nó được nhóm lại trước đây? Nếu điều đó hợp lý. – kimmothy

+0

Có, điều kiện đó sẽ chỉ được kiểm tra cho các nhóm theo kết quả, không phải tất cả, trước khi nhóm. – aorcsik

+0

@kimmothy: Truy vấn phụ trong 'NOT IN' thực sự chỉ cần được thực thi một lần. – a1ex07

0

Điều kiện HAVING được áp dụng cho được nhóm bởi kết quả và do bạn nhóm theo user_id, tất cả giá trị có thể sẽ có trong kết quả được nhóm nên việc đặt điều kiện user_id không quan trọng.

+0

Đặt là quan trọng. Nếu 'WHERE' được áp dụng, việc nhóm được thực hiện bằng ít hàng hơn (thậm chí là 0), vì vậy COUNT() phải được tính cho chỉ những hàng đó. Nếu nó được để lại cho mệnh đề 'HAVING', việc nhóm (và đếm) được thực hiện trên tất cả các hàng và sau đó điều kiện được kiểm tra. Kết quả: nếu người dùng bị cấm là tỷ lệ lớn của tất cả người dùng, sự khác biệt là tốc độ sẽ rất lớn (tỷ lệ) –

+0

Tất nhiên sự khác biệt về tốc độ chỉ tồn tại nếu trình tối ưu hóa mang lại các kế hoạch khác nhau cho 2 truy vấn. –

+0

Cảm ơn bạn đã chỉ ra điều đó, tôi thực sự đã học được rất nhiều từ các câu trả lời ở đây. :) – aorcsik

-1

Không có kết quả tương tự.

Vì truy vấn đầu tiên sẽ lọc các bản ghi từ điều kiện đếm (id)

Một hồ sơ bộ lọc truy vấn khác và sau đó áp dụng mệnh đề.

Second Query được viết một cách chính xác

+2

Vì bạn đang nói kết quả sẽ khác nhau, bạn khó có thể yêu cầu cái nào được viết chính xác trước khi bạn biết vấn đề nào đang được giải quyết.Ít nhất, chúng đều chính xác * cú pháp *. Và, trên thực tế, kết quả sẽ giống nhau. Đó là hiệu quả mà chúng sẽ khác nhau. –

+0

@Andriy: bạn có chắc chắn có sự khác biệt về hiệu quả không? –

+0

@ypercube: Tôi mong đợi HAVING để đánh giá sau WHERE, và, trên thực tế, ngay cả sau khi GROUP BY (mà, tôi nghĩ, được tính sau WHERE quá). Vì vậy, truy vấn đầu tiên sẽ không cần thiết tính toán số lượng hàng mà sau này sẽ bị loại bỏ dựa trên 'user_id'. Bộ lọc thứ hai lọc ra 'user_id' trước khi tổng hợp. –

0

Đối với tôi, câu hỏi thứ hai là hiệu quả hơn bởi vì nó làm giảm số lượng hồ sơ cho GROUP BY và HAVING.

Ngoài ra, bạn có thể thử truy vấn sau để tránh sử dụng IN:

SELECT `fp`.`user_id` 
FROM `forum_posts` `fp` 
LEFT JOIN `banned_users` `bu` ON `fp`.`user_id` = `bu`.`user_id` 
WHERE `bu`.`user_id` IS NULL 
GROUP BY `fp`.`user_id` 
HAVING COUNT(`fp`.`id`) >= 100 

Hope this helps.

0

Bạn đã trả lời rằng hai truy vấn sẽ hiển thị cùng một kết quả và các ý kiến ​​khác nhau về cái nào hiệu quả hơn.

opininion của tôi là sẽ có một sự khác biệt hiệu quả (tốc độ), chỉ khi sản lượng tối ưu với kế hoạch khác nhau cho 2 câu truy vấn. Tôi nghĩ rằng đối với các phiên bản MySQL mới nhất của tối ưu là đủ thông minh để tìm ra kế hoạch tương tự cho một trong hai câu hỏi như vậy sẽ có có sự khác biệt ở tất cả nhưng tắt khóa học người ta có thể kiểm tra và thấy một trong hai phương án THI HÀNH với GIẢI THÍCH hoặc chạy 2 truy vấn chống lại một số bảng thử nghiệm.

tôi sẽ sử dụng phiên bản thứ hai trong mọi trường hợp, chỉ để chơi an toàn.


Hãy để tôi nói thêm rằng:

  • COUNT(*) thường là hiệu quả hơn COUNT(notNullableField) trong MySQL. Cho đến khi được khắc phục trong các phiên bản MySQL trong tương lai, hãy sử dụng COUNT(*) nếu có.

Do đó, bạn cũng có thể sử dụng:

SELECT user_id 
FROM forum_posts 
WHERE user_id NOT IN 
    (SELECT user_id FROM banned_users) 
GROUP BY user_id 
HAVING COUNT(*) >= 100 
  • Ngoài ra còn có những cách khác để đạt được cùng (để NOT IN) phụ kết quả trước khi áp dụng GROUP BY.

Sử dụng LEFT JOIN/NULL:

SELECT fp.user_id 
FROM forum_posts AS fp 
    LEFT JOIN banned_users AS bu 
    ON bu.user_id = fp.user_id 
WHERE bu.user_id IS NULL 
GROUP BY fp.user_id 
HAVING COUNT(*) >= 100 

Sử dụng NOT EXISTS:

SELECT fp.user_id 
FROM forum_posts AS fp 
WHERE NOT EXISTS 
    (SELECT * 
    FROM banned_users AS bu 
    WHERE bu.user_id = fp.user_id 
) 
GROUP BY fp.user_id 
HAVING COUNT(*) >= 100 

nào trong 3 phương pháp là nhanh hơn phụ thuộc vào kích thước bảng và rất nhiều yếu tố khác, vì vậy tốt nhất là để kiểm tra với dữ liệu của bạn.

Các vấn đề liên quan