Mengapa SELECT * menjadi lebih cepat daripada SELECT foo?

28

Pertimbangkan tabel nilai dan hash, seperti:

+------------+----------+------+-----+---------+----------------+
| Field      | Type     | Null | Key | Default | Extra          |
+------------+----------+------+-----+---------+----------------+
| id         | int(11)  | NO   | PRI | NULL    | auto_increment |
| val        | char(9)  | NO   |     | NULL    |                |
| val_hashed | char(50) | YES  |     | NULL    |                |
+------------+----------+------+-----+---------+----------------+

Permintaan berikut selesai dalam 0,00 detik:

SELECT * FROM hashes ORDER BY 1 DESC LIMIT 1;

Namun, kueri ini membutuhkan 3 menit 17 detik:

SELECT val FROM hashes ORDER BY 1 DESC LIMIT 1;

Saya melihat bahwa ketika kueri sedang menjalankan daftar proses menunjukkannya sebagai status Sorting result. Situasi ini sepenuhnya dapat direproduksi. Perhatikan bahwa ada proses lain yang melakukan INSERToperasi di atas meja secara terus menerus.

Mengapa kueri yang lebih spesifik membutuhkan waktu lebih lama untuk dijalankan daripada *kueri? Saya selalu percaya bahwa *pertanyaan harus dihindari secara khusus karena alasan kinerja.

dotancohen
sumber
7
Pernyataan pertama paling mungkin menggunakan indeks kunci utama iduntuk menemukan baris pertama. Yang kedua perlu mengurutkan hasil lengkap pada kolom (tidak diindeks) val.
a_horse_with_no_name
8
The ORDER BY NUMBERsintaks cukup kesalahan rawan.
usr
2
Menambahkan ke komentar terakhir Anda, SELECT *dikombinasikan dengan indeks kolom dalam ORDER BYmengaburkan kolom mana yang sedang disortir - alasan lain untuk menghindari *...
lc.
@ lc., Apa maksudmu?
Pacerier
@Pacerier Maksud saya *tidak eksplisit. Jadi mengatakan "beri saya semua kolom dan urutkan berdasarkan yang ketiga" adalah tentang deterministik seperti mengatakan "pergi ke supermarket dan katakan berapa banyak lampu lalu lintas yang Anda lewati"
lc.

Jawaban:

33

Ungkapan tersebut ORDER BY 1merujuk pada kolom yang berbeda; di pertama akan id, di kedua val. Karena idkuncinya akan diindeks dan order byakan menjadi jumlah pekerjaan yang sepele. Untuk order by val, bagaimanapun, sistem harus mengambil setiap baris, mengurutkan tabel lengkap dengan val, lalu pilih hanya satu dari baris itu.

Ubah kedua kueri order by iddan saya pikir waktu eksekusi Anda akan hampir sama.

Michael Green
sumber
3
Terkadang pertanyaan yang paling sulit adalah pertanyaan yang hanya menatap wajah kita. Terima kasih, Michael!
dotancohen
7

Perbedaan kinerja dalam permintaan Anda dijelaskan dengan baik oleh MG. Saya akan membahas ini:

Saya selalu percaya bahwa permintaan * harus dihindari secara khusus karena alasan kinerja.

select *tidak membawa hukuman tertentu dengan sendirinya, itu bermasalah ketika disalahgunakan. Dalam kueri tabel tunggal berfungsi dengan baik. sekarang gabung tabel itu ke yang lain dengan 20 kolom, dan kemudian tambahkan bergabung ke 5 tabel lainnya dengan banyak kolom masing-masing. SEKARANG itu masalah. Begitu juga orang-orang yang mengajar bantuan band yang luas "never do X" tanpa menjelaskan alasannya.

paul
sumber
3
SELECT *mungkin menjadi masalah bahkan untuk kueri tabel tunggal. Misalnya, SELECT * FROM hashes ORDER BY val;mungkin akan melakukan pemindaian tabel penuh dan kemudian pengurutan sementara SELECT val FROM hashes ORDER BY val;hanya akan melakukan pemindaian indeks penuh, dan tidak ada pengurutan (dengan asumsi indeks ada pada val). Jadi, tidak ada salahnya untuk memilih hanya hasil yang kita butuhkan.
ypercubeᵀᴹ
Saya berasumsi Anda telah melihat ini? sqlblog.com/blogs/aaron_bertrand/archive/2009/10/10/…
Max Vernon
@ ypercube, Apakah itu terjadi bahkan jika kami select(*)hanya digunakan sebagai sub-pilihan ? Karena ini merupakan pilihan yang disematkan, Bukankah MySQL cukup pintar untuk mengetahui kolom sebenarnya yang perlu dipilih?
Pacerier
@Pacerier optimizer mysql memiliki tingkat "kecerdasan" yang berbeda, tergantung pada versi yang Anda gunakan. Di Gerneal, itu sangat bodoh tentang subqueries bersarang, jadi apa pun yang Anda bisa untuk membantunya, itu bagus.
ypercubeᵀᴹ
@ ypercube, Ah, kalau saja itu secerdas pgsql.
Pacerier