2009-02-24 23 views
208

Nếu tôi có một bảngCó gì nhanh hơn, CHỌN DISTINCT hoặc GROUP BY trong MySQL?

CREATE TABLE users (
    id int(10) unsigned NOT NULL auto_increment, 
    name varchar(255) NOT NULL, 
    profession varchar(255) NOT NULL, 
    employer varchar(255) NOT NULL, 
    PRIMARY KEY (id) 
) 

và tôi muốn có được tất cả các giá trị độc đáo của profession lĩnh vực, điều gì sẽ nhanh hơn (hoặc đề nghị):

SELECT DISTINCT u.profession FROM users u 

hoặc

SELECT u.profession FROM users u GROUP BY u.profession 

?

+2

Bạn có thể kiểm tra cho chính mình một cách nhanh chóng khi đặt câu hỏi. Đáng ngạc nhiên, gần như không thể xây dựng một kịch bản trong đó DISTINCT vượt trội hơn GROUP BY - điều này gây phiền toái vì rõ ràng đây không phải là mục đích của GROUP BY. Tuy nhiên, GROUP BY có thể tạo ra những kết quả gây nhầm lẫn, mà tôi nghĩ là đủ lý do để tránh nó. – Strawberry

+0

Có một bản sao khác có câu trả lời khác. xem [MySql - Distinct vs Group By] (http://stackoverflow.com/questions/25114506/mysql-distinct-vs-group-by/25114686) <<< nó nói GROUP BY là tốt hơn – kolunar

+0

Vui lòng xem [tại đây] (http://stackoverflow.com/questions/581521/whats-faster-select-distinct-or-group-by-in-mysql/37611287#answer-37611287) nếu bạn muốn đo chênh lệch thời gian giữa DISTINCT và GROUP BY đang chạy truy vấn của bạn. – kolunar

Trả lời

199

Về cơ bản, chúng tương đương với nhau (thực tế đây là cách một số cơ sở dữ liệu triển khai DISTINCT dưới mui xe).

Nếu một trong số đó nhanh hơn, nó sẽ là DISTINCT. Điều này là bởi vì, mặc dù hai là như nhau, một trình tối ưu hóa truy vấn sẽ phải nắm bắt thực tế rằng GROUP BY của bạn không tận dụng lợi thế của bất kỳ thành viên nhóm nào, chỉ là khóa của chúng. DISTINCT làm cho điều này rõ ràng, vì vậy bạn có thể nhận được ngay với một trình tối ưu hóa hơi dumber.

Khi nghi ngờ, hãy kiểm tra!

+59

DISTINCT sẽ chỉ nhanh hơn nếu bạn KHÔNG có chỉ mục (vì nó không phân loại). Khi bạn có một chỉ mục và nó được sử dụng, chúng là từ đồng nghĩa. – Quassnoi

+7

Định nghĩa 'DISTINCT' và' GROUP BY' khác với 'DISTINCT' không phải sắp xếp đầu ra, và' GROUP BY' theo mặc định. Tuy nhiên, trong MySQL thậm chí một 'DISTINCT' +' ORDER BY' có thể _still_ nhanh hơn 'GROUP BY' do các gợi ý bổ sung cho trình tối ưu hóa như được giải thích bởi SquareCog. – rustyx

+0

DISTINCT nhanh hơn nhiều với dữ liệu số lượng lớn. –

0

Nếu bạn không phải thực hiện bất kỳ chức năng nhóm nào (tổng, trung bình v.v. trong trường hợp bạn muốn thêm dữ liệu số vào bảng), hãy sử dụng SELECT DISTINCT. Tôi nghi ngờ nó nhanh hơn, nhưng tôi không có gì để cho nó.

Trong mọi trường hợp, nếu bạn lo lắng về tốc độ, hãy tạo chỉ mục trên cột.

5

Dường như các truy vấn không chính xác giống nhau. Ít nhất là cho MySQL.

Hãy so sánh:

  1. mô tả chọn tên sản phẩm khác biệt với northwind.products
  2. mô tả chọn tên sản phẩm từ nhóm northwind.products bởi tên sản phẩm

Các truy vấn thứ hai cho biết thêm "Sử dụng filesort" của Extra .

+1

Chúng giống nhau trong các điều khoản của những gì họ nhận được, không phải về cách họ có được nó. Trình tối ưu hóa lý tưởng sẽ thực thi chúng theo cùng một cách, nhưng trình tối ưu hóa MySQL không lý tưởng. Dựa trên bằng chứng của bạn, dường như DISTINCT sẽ đi nhanh hơn - O (n) so với O (n * log n). – SquareCog

+0

Vì vậy, "bằng cách sử dụng filesort" về cơ bản là điều xấu? – vava

+0

Trong trường hợp này, vì bạn không cần phải sắp xếp (bạn sẽ cần nếu bạn cần các nhóm). MySQL sắp xếp để đặt cùng các mục với nhau, và sau đó nhận các nhóm bằng cách quét tệp được sắp xếp. Bạn chỉ cần phân biệt, vì vậy bạn chỉ cần băm khóa của bạn trong khi làm một quét bảng duy nhất. – SquareCog

17

Đi cho đơn giản nhất và ngắn nhất nếu bạn có thể - DISTINCT có vẻ là nhiều hơn những gì bạn đang tìm kiếm chỉ vì nó sẽ cung cấp cho bạn chính xác câu trả lời bạn cần và chỉ có vậy!

83

Nếu bạn có chỉ mục trên profession, hai số này là từ đồng nghĩa.

Nếu không, hãy sử dụng DISTINCT.

GROUP BY trong MySQL sắp xếp kết quả. Bạn thậm chí có thể làm:

SELECT u.profession FROM users u GROUP BY u.profession DESC 

và nhận các nghề nghiệp của bạn được sắp xếp theo thứ tự DESC.

DISTINCT tạo bảng tạm thời và sử dụng bảng này để lưu trữ bản sao. GROUP BY thực hiện tương tự, nhưng phân loại các kết quả khác biệt sau đó.

Vì vậy

SELECT DISTINCT u.profession FROM users u 

là nhanh hơn, nếu bạn không có một chỉ mục trên profession.

+3

Đây là câu trả lời chính xác nhất. Nên được chấp nhận .. –

+1

Bạn có thể thêm 'ORDER BY NULL' vào' GROUP BY' để tránh sắp xếp. – Ariel

0

CHỌN DISTINCT sẽ luôn giống hoặc nhanh hơn GROUP BY. Trên một số hệ thống (ví dụ: Oracle), nó có thể được tối ưu hóa giống với DISTINCT cho hầu hết các truy vấn. Trên những người khác (như SQL Server), nó có thể nhanh hơn đáng kể.

7

cũng khác biệt có thể chậm hơn so với nhóm vào một số trường hợp trong bưu điện (không biết về các dbs khác).

kiểm tra ví dụ:

postgres=# select count(*) from (select distinct i from g) a; 

count 

10001 
(1 row) 

Time: 1563,109 ms 

postgres=# select count(*) from (select i from g group by i) a; 

count 
10001 
(1 row) 

Time: 594,481 ms 

http://www.pgsql.cz/index.php/PostgreSQL_SQL_Tricks_I

vì vậy hãy cẩn thận ... :)

2

(nhiều hơn một lưu ý chức năng)

Có những trường hợp khi bạn phải sử dụng GROUP BY, ví dụ: nếu bạn muốn nhận số lượng nhân viên cho mỗi chủ nhân:

SELECT u.employer, COUNT(u.id) AS "total employees" FROM users u GROUP BY u.employer 

Trong trường hợp như vậy DISTINCT u.employer không hoạt động chính xác. Có lẽ có một cách, nhưng tôi chỉ không biết điều đó. (Nếu ai đó biết cách thực hiện truy vấn đó với DISTINCT, vui lòng thêm ghi chú!)

13

Tất cả các câu trả lời ở trên đều đúng, đối với trường hợp DISTINCT trên một cột so với GROUP BY trên một cột. Mỗi công cụ db có triển khai và tối ưu hóa riêng của nó và nếu bạn quan tâm đến sự khác biệt rất nhỏ (trong hầu hết các trường hợp) thì bạn phải kiểm tra với máy chủ cụ thể VÀ phiên bản cụ thể! Khi triển khai có thể thay đổi ...

NHƯNG, nếu bạn chọn nhiều cột trong truy vấn, thì DISTINCT cơ bản là khác nhau! Bởi vì trong trường hợp này, nó sẽ so sánh TẤT CẢ các cột của tất cả các hàng, thay vì chỉ một cột.

Vì vậy, nếu bạn có một cái gì đó như:

// This will NOT return unique by [id], but unique by (id,name) 
SELECT DISTINCT id, name FROM some_query_with_joins 

// This will select unique by [id]. 
SELECT id, name FROM some_query_with_joins GROUP BY id 

Đó là một sai lầm phổ biến khi nghĩ rằng từ khóa DISTINCT phân biệt hàng bằng cột đầu tiên mà bạn chỉ định, nhưng DISTINCT là một từ khóa chung theo cách này.

Vì vậy, mọi người bạn phải cẩn thận để không đưa ra câu trả lời ở trên là chính xác cho mọi trường hợp ... Bạn có thể bị lẫn lộn và nhận được kết quả sai trong khi tất cả những gì bạn muốn là tối ưu hóa!

+3

Mặc dù câu hỏi này * là * về MySQL cần lưu ý rằng truy vấn thứ hai sẽ hoạt động * chỉ * trong MySQL. Gần như mọi DBMS khác sẽ từ chối câu lệnh thứ hai vì đó là việc sử dụng không hợp lệ của toán tử GROUP BY. –

+0

Vâng, "gần" là một định nghĩa có vấn đề :-) Sẽ hữu ích hơn nhiều nếu bạn nêu một DBMS cụ thể mà bạn đã * kiểm tra * để thấy rằng nó tạo ra lỗi cho câu lệnh này. –

+1

Postgres, Oracle, Firebird, DB2, SQL Server cho người mới bắt đầu. MySQL: http: //sqlfiddle.com/#! 2/6897c/1 Postgres: http://sqlfiddle.com/#!12/6897c/1 Oracle: http://sqlfiddle.com/#!12/6897c/ 1 Máy chủ SQL: http://sqlfiddle.com/#!6/6897c/1 –

5

Nhóm bởi đắt hơn Phân biệt vì Nhóm theo một loại trên kết quả trong khi phân biệt tránh được. Nhưng nếu bạn muốn tạo nhóm bằng cách mang lại kết quả tương tự như riêng biệt, hãy cung cấp cho đơn đặt hàng theo số không ..

SELECT DISTINCT u.profession FROM users u 

bằng

SELECT u.profession FROM users u GROUP BY u.profession order by null 
2

Trong MySQL, "Group By" sử dụng thêm một bước: filesort. Tôi nhận thấy DISTINCT nhanh hơn GROUP BY và điều đó thật bất ngờ.

0

Nếu vấn đề cho phép, hãy thử với EXISTS, vì nó được tối ưu hóa để kết thúc ngay sau khi kết quả được tìm thấy (Và không đệm bất kỳ phản hồi nào), vì vậy, nếu bạn đang cố gắng chuẩn hóa dữ liệu cho mệnh đề WHERE như thế này

SELECT FROM SOMETHING S WHERE S.ID IN (SELECT DISTINCT DCR.SOMETHING_ID FROM DIFF_CARDINALITY_RELATIONSHIP DCR) -- to keep same cardinality 

một phản ứng nhanh hơn sẽ là:

SELECT FROM SOMETHING S WHERE EXISTS (SELECT 1 FROM DIFF_CARDINALITY_RELATIONSHIP DCR WHERE DCR.SOMETHING_ID = S.ID) 

Đây không phải là lúc nào cũng có thể nhưng khi có sẵn, bạn sẽ thấy một phản ứng nhanh hơn.

1

Sau khi kiểm tra nặng chúng tôi đi đến kết luận rằng GROUP BY là nhanh hơn

CHỌN sql_no_cache opnamegroep_intern TỪ telwerken ĐÂU opnemergroep IN (7,8,9,10,11,12,13) ​​nhóm bởi opnamegroep_intern

635 totaal 0,0944 giây van hồ sơ Weergave 0-29 (635 totaal, truy vấn duurde 0,0484 giây)

CHỌN sql_no_cache distinc t (opnamegroep_intern) TỪ telwerken ĐÂU opnemergroep TRÊN (7,8,9,10,11,12,13) ​​

635 totaal 0,2117 giây (chậm hơn gần 100%) van hồ sơ Weergave 0-29 (635 totaal , truy vấn duurde 0,3468 giây)

1

Đây không phải là một quy tắc

Đối với mỗi truy vấn .... thử biệt riêng và sau đó nhóm bằng ... so sánh thời gian để hoàn thành mỗi truy vấn và sử dụng nhanh hơn ...

Trong dự án của tôi đôi khi tôi sử dụng nhóm theo và những người khác riêng biệt

1

Đây là một cách tiếp cận đơn giản sẽ in 2 thời gian trôi qua khác nhau cho mỗi truy vấn.

DECLARE @t1 DATETIME; 
DECLARE @t2 DATETIME; 

SET @t1 = GETDATE(); 
SELECT DISTINCT u.profession FROM users u; --Query with DISTINCT 
SET @t2 = GETDATE(); 
PRINT 'Elapsed time (ms): ' + CAST(DATEDIFF(millisecond, @t1, @t2) AS varchar); 

SET @t1 = GETDATE(); 
SELECT u.profession FROM users u GROUP BY u.profession; --Query with GROUP BY 
SET @t2 = GETDATE(); 
PRINT 'Elapsed time (ms): ' + CAST(DATEDIFF(millisecond, @t1, @t2) AS varchar); 

HOẶC thử SET STATISTICS TIME (Transact-SQL)

SET STATISTICS TIME ON; 
SELECT DISTINCT u.profession FROM users u; --Query with DISTINCT 
SELECT u.profession FROM users u GROUP BY u.profession; --Query with GROUP BY 
SET STATISTICS TIME OFF; 

Nó chỉ đơn giản hiển thị số mili giây cần thiết để phân tích cú pháp, biên dịch, và thực hiện từng tuyên bố như sau:

SQL Server Execution Times: 
    CPU time = 0 ms, elapsed time = 2 ms. 
Các vấn đề liên quan