Apa yang lebih cepat, SELECT DISTINCT atau GROUP BY di MySQL?


273

Jika saya punya meja

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)
)

dan saya ingin mendapatkan semua nilai unik professionbidang, apa yang lebih cepat (atau disarankan):

SELECT DISTINCT u.profession FROM users u

atau

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

?


2
Anda dapat menguji diri sendiri secepat mengajukan pertanyaan. Menjengkelkan, hampir tidak mungkin untuk membangun skenario di mana DISTINCT mengungguli GROUP BY - yang menjengkelkan karena jelas ini bukan tujuan GROUP BY. Namun, GROUP BY dapat menghasilkan hasil yang menyesatkan, yang menurut saya cukup alasan untuk menghindarinya.
Strawberry

Ada duplikat lain dengan jawaban yang berbeda. lihat MySql - Distinct vs Group By <<< dikatakan GROUP BY lebih baik
kolunar

Silakan lihat di sini jika Anda ingin mengukur perbedaan waktu antara DISTINCT dan GROUP BY dengan menjalankan kueri Anda.
kolunar

Jawaban:


258

Mereka pada dasarnya setara satu sama lain (sebenarnya ini adalah bagaimana beberapa database mengimplementasikan di DISTINCTbawah tenda).

Jika salah satu dari mereka lebih cepat, itu akan terjadi DISTINCT. Ini karena, meskipun keduanya sama, pengoptimal kueri harus mengetahui fakta bahwa Anda GROUP BYtidak memanfaatkan anggota grup mana pun, hanya kunci mereka. DISTINCTmembuat ini eksplisit, sehingga Anda bisa lolos dengan pengoptimal yang sedikit bodoh.

Jika ragu, uji!


76
DISTINCT akan lebih cepat hanya jika Anda TIDAK memiliki indeks (karena tidak mengurutkan). Ketika Anda memiliki indeks dan digunakan, itu adalah sinonim.
Quassnoi

10
Definisi DISTINCTdan GROUP BYberbeda dalam hal DISTINCTitu tidak harus mengurutkan output, dan GROUP BYsecara default tidak. Namun, di MySQL bahkan a DISTINCT+ ORDER BYmungkin masih lebih cepat daripada GROUP BYkarena petunjuk tambahan untuk pengoptimal seperti yang dijelaskan oleh SquareCog.
rustyx

1
DISTINCT jauh lebih cepat dengan data jumlah besar.
Pankaj Wanjari

7
Saya menguji ini, dan menemukan bahwa pada kolom yang diindeks, mysql, grup oleh sekitar 6x lebih lambat daripada berbeda dengan permintaan yang cukup rumit. Hanya menambahkan ini sebagai titik data. Sekitar 100rb baris. Jadi cobalah dan lihat sendiri.
Lizardx

lihat MySql - Distinct vs Group By <<< dikatakan GROUP BY lebih baik
kolunar

100

Jika Anda memiliki indeks aktif profession, keduanya adalah sinonim.

Jika tidak, gunakan DISTINCT.

GROUP BYdalam MySQLberbagai macam hasil. Anda bahkan dapat melakukannya:

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

dan selesaikan profesi Anda DESC.

DISTINCTmembuat tabel sementara dan menggunakannya untuk menyimpan duplikat. GROUP BYmelakukan hal yang sama, tetapi mengurutkan hasil yang berbeda sesudahnya.

Begitu

SELECT DISTINCT u.profession FROM users u

lebih cepat, jika Anda tidak memiliki indeks profession.


6
Anda dapat menambahkan ORDER BY NULLke GROUP BYuntuk menghindari penyortiran.
Ariel

Masih lebih lambat bahkan dengan pengelompokan oleh null
Thanh Trung

@ Shanhrung: apa yang lebih lambat dari apa?
Quassnoi

@Quassnoi groupby lebih lambat dari yang berbeda bahkan jika menghindari semacam
Thanh Trung

Catatan: Kualifikasi pesanan pada GROUP BY tidak digunakan lagi di MySQL 8.
Matthew Lenz

18

Semua jawaban di atas benar, untuk kasus DISTINCT pada satu kolom vs GROUP BY pada satu kolom. Setiap mesin db memiliki implementasi dan optimalisasi sendiri, dan jika Anda peduli dengan perbedaan yang sangat kecil (dalam kebanyakan kasus) maka Anda harus menguji server tertentu DAN versi spesifik! Karena implementasinya dapat berubah ...

TETAPI, jika Anda memilih lebih dari satu kolom dalam kueri, maka PERBEDAAN pada dasarnya berbeda! Karena dalam hal ini akan membandingkan SEMUA kolom dari semua baris, bukan hanya satu kolom.

Jadi, jika Anda memiliki sesuatu seperti:

// 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

Merupakan kesalahan umum untuk berpikir bahwa kata kunci DISTINCT membedakan baris dengan kolom pertama yang Anda tentukan, tetapi DISTINCT adalah kata kunci umum dengan cara ini.

Jadi, orang yang Anda harus berhati-hati untuk tidak mengambil jawaban di atas sebagai benar untuk semua kasus ... Anda mungkin bingung dan mendapatkan hasil yang salah sementara yang Anda inginkan adalah mengoptimalkan!


3
Meskipun pertanyaan ini tentang MySQL, perlu dicatat bahwa permintaan kedua hanya akan berfungsi di MySQL. Hampir setiap DBMS lainnya akan menolak pernyataan kedua karena ini merupakan penggunaan yang tidak benar dari operator GROUP BY.
a_horse_with_no_name

Yah, "hampir" adalah definisi yang bermasalah :-) Akan jauh lebih bermanfaat jika Anda menyatakan DBMS spesifik yang telah Anda uji untuk melihat bahwa itu menghasilkan kesalahan untuk pernyataan ini.
daniel.gindi

3
Postgres, Oracle, Firebird, DB2, SQL Server sebagai permulaan. MySQL: sqlfiddle.com/#!2/6897c/1 Postgres: sqlfiddle.com/#!12/6897c/1 Oracle: sqlfiddle.com/#!12/6897c/1 SQL Server: sqlfiddle.com/#!6/ 6897c / 1
a_horse_with_no_name

17

Pergi untuk yang paling sederhana dan terpendek jika Anda bisa - BERPIKIR tampaknya lebih apa yang Anda cari hanya karena itu akan memberi Anda PERSIS jawaban yang Anda butuhkan dan hanya itu!


7

Kelompokkan lebih mahal daripada Yang Berbeda karena Kelompokkan mengurutkan hasil sementara yang berbeda menghindarinya. Tetapi jika Anda ingin membuat grup dengan menghasilkan hasil yang sama seperti berbeda, beri perintah dengan nol ..

SELECT DISTINCT u.profession FROM users u

adalah sama dengan

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

sama denganSELECT profession FROM users GROUP BY profession

6

well well bisa lebih lambat daripada grup pada beberapa kesempatan di postgres (tidak tahu tentang dbs lain)

contoh yang diuji:

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

jadi hati-hati ... :)


5

Tampaknya kueri tidak persis sama. Setidaknya untuk MySQL.

Membandingkan:

  1. menjelaskan pilih nama produk yang berbeda dari northwind.products
  2. menjelaskan pilih productname dari grup northwind.products oleh productname

Permintaan kedua memberikan tambahan "Menggunakan filesort" di Extra.


1
Mereka sama dalam hal apa yang mereka dapatkan, bukan dalam hal bagaimana mereka mendapatkannya. Pengoptimal yang ideal akan mengeksekusinya dengan cara yang sama, tetapi pengoptimal MySQL tidak ideal. Berdasarkan bukti Anda, tampaknya DISTINCT akan berjalan lebih cepat - O (n) vs O (n * log n).
SquareCog

Jadi, "menggunakan filesort" pada dasarnya adalah hal yang buruk?
vava

Dalam hal ini, karena Anda tidak perlu menyortir (Anda akan melakukannya jika Anda membutuhkan grup). MySQL mengurutkan untuk menempatkan entri yang sama bersama, dan kemudian mendapatkan grup dengan memindai file yang diurutkan. Anda hanya perlu perbedaan, jadi Anda hanya perlu hash kunci Anda saat melakukan pemindaian tabel tunggal.
SquareCog

1
Tambahkan ORDER BY NULLke GROUP BYversi dan mereka akan sama.
Ariel

3

Dalam MySQL , " Group By" menggunakan langkah tambahan: filesort. Saya menyadari DISTINCTlebih cepat daripada GROUP BY, dan itu mengejutkan.


3

Setelah pengujian berat kami sampai pada kesimpulan bahwa GROUP BY lebih cepat

SELECT sql_no_cache opnamegroep_intern DARI telwerken MANA opnemergroep(7,8,9,10,11,12,13) ​​dikelompokkan oleh opnamegroep_intern

635 totaal 0,0944 detik Weergave van mencatat 0 - 29 (635 totaal, kueri duurde 0,0484 dtk)

PILIH sql_no_cache berbeda (opnamegroep_intern) DARI DI telwerken MANA opnemergroep(7,8,9,10,11,12,13)

635 totaal 0,2117 detik (hampir 100% lebih lambat) Weergave van mencatat 0 - 29 (635 totaal, kueri duurde 0,3468 detik)


2

(lebih dari catatan fungsional)

Ada kasus ketika Anda harus menggunakan GROUP BY, misalnya jika Anda ingin mendapatkan jumlah karyawan per perusahaan:

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

Dalam skenario seperti DISTINCT u.employeritu tidak berhasil. Mungkin ada jalan, tapi saya tidak tahu. (Jika seseorang tahu cara membuat pertanyaan dengan DISTINCT, harap tambahkan catatan!)


2

Berikut ini adalah pendekatan sederhana yang akan mencetak 2 waktu berlalu yang berbeda untuk setiap permintaan.

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);

ATAU coba SET WAKTU STATISTIK (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;

Ini hanya menampilkan jumlah milidetik yang diperlukan untuk mem-parsing, mengkompilasi, dan mengeksekusi setiap pernyataan seperti di bawah ini:

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 2 ms.

1

Ini bukan aturan

Untuk setiap kueri .... coba secara terpisah yang berbeda lalu kelompokkan dengan ... bandingkan waktu untuk menyelesaikan setiap kueri dan gunakan yang lebih cepat ....

Dalam proyek saya kadang-kadang saya menggunakan grup oleh dan orang lain yang berbeda


0

Jika Anda tidak harus melakukan fungsi grup apa pun (jumlah, rata-rata dll jika Anda ingin menambahkan data numerik ke tabel), gunakan SELECT DISTINCT. Saya curiga ini lebih cepat, tetapi saya tidak punya apa-apa untuk ditunjukkan.

Bagaimanapun, jika Anda khawatir tentang kecepatan, buat indeks pada kolom.


0

SELECT DISTINCT akan selalu sama, atau lebih cepat, daripada GROUP BY. Pada beberapa sistem (yaitu Oracle), mungkin dioptimalkan untuk sama dengan berbeda untuk sebagian besar permintaan. Pada yang lain (seperti SQL Server), ini bisa menjadi jauh lebih cepat.


0

Jika masalah memungkinkan, coba dengan EXIS, karena ini dioptimalkan untuk mengakhiri segera setelah hasilnya ditemukan (Dan jangan buffer setiap respons), jadi, jika Anda hanya mencoba untuk menormalkan data untuk klausa WHERE seperti ini

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

Respons yang lebih cepat adalah:

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

Ini tidak selalu mungkin tetapi jika tersedia Anda akan melihat respons yang lebih cepat.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.