Di MySQL, apakah urutan kolom dalam klausa WHERE memengaruhi kinerja kueri?

38

Saya mengalami masalah kinerja pada permintaan basis data tertentu yang memiliki set hasil yang besar.

Kueri yang dimaksud, saya punya tiga ANDdalam klausa WHERE

Apakah urutan klausa itu penting?

Seperti pada, jika saya menempatkan klausa ASI_EVENT_TIME pertama (karena itu akan menghapus sebagian besar hasil dari salah satu klausa.

Apakah itu akan meningkatkan waktu berjalan pada kueri?

PERTANYAAN:

SELECT DISTINCT  activity_seismo_info.* 
FROM `activity_seismo_info` 
WHERE 
    activity_seismo_info.ASI_ACTIVITY_ID IS NOT NULL  AND 
    activity_seismo_info.ASI_SEISMO_ID IN (43,44,...,259) AND 
    (
        activity_seismo_info.ASI_EVENT_TIME>='2011-03-10 00:00:00' AND 
        activity_seismo_info.ASI_EVENT_TIME<='2011-03-17 23:59:59'
    ) 

ORDER BY activity_seismo_info.ASI_EVENT_TIME DESC

JELASKAN kueri:

+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+ 
| id | select_type | table   | type  | possible_keys             | key          | key_len | ref  | rows  | Extra                       |
+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+ 
|  1 | SIMPLE      | act...o | range | act...o_FI_1,act...o_FI_2 | act...o_FI_1 | 5       | NULL | 65412 | Using where; Using filesort |
+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+

Menggunakan:

PHP 5.2

MySQL 5.0.51a-3ubuntu5.4

Propel 1.3

Symfony 1.2.5

Patrick
sumber
ORDER BY mungkin butuh waktu lama. "Menggunakan filesort" bisa sangat lambat. Saya menemukan melakukan pemesanan dalam logika aplikasi jauh lebih cepat daripada menggunakan ORDER BY.
maclema
Saya menanyakan pertanyaan yang sama beberapa waktu lalu (sebelum situs ini) di stackoverflow. Periksa tautan untuk jawaban yang saya terima di sana. stackoverflow.com/questions/3805863/…
Scott
2
@maclema - Kecuali aplikasi Anda berjalan pada mesin yang jauh lebih cepat dari database Anda, pernyataan Anda tentu tidak benar, belum lagi beban sia-sia dari semua logika penyortiran dalam aplikasi Anda. order bytermasuk dalam database.
Jack Douglas

Jawaban:

24

Saya kira tidak. Pengoptimal kueri harus cukup pintar.

Anda dapat mencoba mengatur ulang klausa WHERE dan melihat bahwa EXPLAINS memberi tahu Anda hal yang sama dalam setiap kasus.


Tentang apa yang dapat dilakukan untuk mengoptimalkan kueri ini: Apakah ada indeks di ASI_EVENT_TIME? (ini yang paling penting menurut saya untuk kueri ini karena Anda juga mengurutkan hasil menggunakannya).

Apakah ada indeks pada dua bidang lainnya (ASI_SEISMO_ID dan ASI_ACTIVITY_ID)?

Akan sangat membantu jika Anda memposting struktur tabel.

ypercubeᵀᴹ
sumber
Saya tidak pernah berpikir untuk membuat indeks waktu acara. Saya akan mencobanya besok pada dev db dan melihat apakah ada perbedaan yang nyata.
Patrick
@Patrick Dengan asumsi semua pertanyaan lain yang akan menggunakan indeks ini memesan tanggal ini dalam urutan menurun, Anda juga ingin memesan kunci indeks (activity_seismo_info.ASI_EVENT_TIME) dalam urutan menurun juga.
Matt M
@MattM Saya tidak tahu bahwa Anda BISA memesan kunci indeks. Luar biasa Jika saya memesan kunci indeks, apakah hal itu akan mengganggu kinerja pemesanan dengan arah yang berlawanan dengan titik yang lebih buruk daripada tidak ada kunci indeks?
Patrick
@ Patrick Anda benar. Otak saya macet di tanah SQL Server. Anda bisa menentukan urutan sortir dalam MYSQL dan itu akan diurai, tetapi diabaikan. Semua indeks diurutkan dalam urutan naik dalam MYSQL. Maaf bila membingungkan.
Matt M
13

Dari dokumentasi :

Jika tabel memiliki indeks multi-kolom, awalan paling kiri dari indeks dapat digunakan oleh pengoptimal untuk menemukan baris. Misalnya, jika Anda memiliki indeks tiga kolom di (col1, col2, col3), Anda telah mengindeks kemampuan pencarian di (col1), (col1, col2), dan (col1, col2, col3).

MySQL tidak dapat menggunakan indeks jika kolom tidak membentuk awalan paling kiri dari indeks.

Jadi ya, itu harus sama dengan urutan kolom dalam indeks gabungan .

Gayus
sumber
4
Jika tabel memiliki indeks multi-kolom memilih kolom dari hal-hal kiri - tetapi urutan yang Anda pilih tidak masalah. Jadi jika Anda memiliki indeks a, b, c dan Anda lakukan WHERE c = 'foo' AND a = 'bar' AND b = 'foobar'dan indeks masih memenuhi syarat untuk digunakan.
texelate
10

Tidak, itu tidak masalah.

Pengoptimal melakukan banyak transformasi sederhana langsung setelah mem-parsing SQL - ini adalah salah satunya.

Morgan Tocker
sumber
8

DI MANA foo DAN bar

mengoptimalkan sama dengan

DI MANA bar DAN foo

Namun,

WHERE tidak sama dengan # 1 DAN tidak sama dengan # 2

Tidak dapat mengoptimalkan kedua bagian. Sebagai contoh,

DI MANA ANTARA 1 dan 3 DAN b> 17

tidak dapat memanfaatkan INDEX (a, b) atau INDEX (b, a)

Untuk frasa berbeda, tes '=' apa pun DAN bersama-sama dalam klausa WHERE digunakan terlebih dahulu satu non - '=' (IN, ANTARA,>, dll) dapat ditangani. Tidak lebih dari satu dapat dioptimalkan secara efektif.

Kueri Anda memiliki 3 klausa seperti itu.

Ternyata, INDEX (EVENT_TIME) mungkin yang paling berguna - ini akan membantu dengan salah satu AND, dan mungkin digunakan untuk menghindari "filesort" untuk ORDER BY.

Jika tidak ada baris duplikat (mengapa ada?), Lalu singkirkan DISTINCT. Itu bahkan menyebabkan lebih banyak upaya.

Berikan SHOW CREATE TABLE dan SHOW TABLE STATUS saat mengajukan pertanyaan kinerja.

Perbarui ... Versi yang lebih baru (mis., MySQL 5.7) dapat, dalam beberapa situasi, memperlakukan IN( list of constants )hampir seperti =. Agar aman, patuhi pesanan ini (setiap bagian bersifat opsional):

  1. Sejumlah =.
  2. Beberapa INs.
  3. Paling banyak satu rentang.
Rick James
sumber
1

MySQL di mana dokumen pengoptimalan mengatakan:

Anda mungkin tergoda untuk menulis ulang pertanyaan Anda untuk membuat operasi aritmatika lebih cepat, sambil mengorbankan keterbacaan. Karena MySQL melakukan optimasi serupa secara otomatis , Anda sering dapat menghindari pekerjaan ini, dan meninggalkan kueri dalam bentuk yang lebih mudah dipahami dan dipelihara. Beberapa optimasi yang dilakukan oleh MySQL mengikuti:

  • ...

  • Untuk setiap tabel dalam suatu join, WHERE yang lebih sederhana dibuat untuk mendapatkan evaluasi WHERE yang cepat untuk tabel tersebut dan juga untuk melewati baris sesegera mungkin .

  • Setiap indeks tabel dipertanyakan, dan indeks terbaik digunakan kecuali pengoptimal percaya bahwa lebih efisien menggunakan pemindaian tabel . Pada suatu waktu, pemindaian digunakan berdasarkan apakah indeks terbaik membentang lebih dari 30% dari tabel, tetapi persentase tetap tidak lagi menentukan pilihan antara menggunakan indeks atau pemindaian. Pengoptimal sekarang lebih kompleks dan mendasarkan perkiraannya pada faktor-faktor tambahan seperti ukuran tabel, jumlah baris, dan ukuran blok I / O.

Dengan cara ini rasional untuk pengoptimal kueri untuk menghilangkan BAGAIMANA kita menggunakan kolom dalam kueri (Tidak hanya MySQL tetapi SQL adalah bahasa deklaratif dan harus melakukan apa yang kita inginkan bukan seperti yang kita inginkan).

Namun saya masih suka memiliki jenis yang sama untuk kolom kunci komposit dalam permintaan tetapi kadang-kadang tak terhindarkan misalnya ketika kita menggunakan ORM atau ActiveRecord, dalam beberapa kerangka kerja seperti yii2, menyesuaikan kriteria relasi akan ditambahkan pada akhir kondisi "aktif" tetapi kita masih membutuhkan kemampuan QueryBuilders di berbagai bagian aplikasi.

Alix
sumber
-2

Setiap bidang yang digunakan dalam klausa WHERE / HAVING Anda dan memiliki selektivitas tinggi (jumlah nilai unik / jumlah total catatan> 10% ~ 20%) HARUS diindeks.

Jadi, jika ASI_EVENT_TIMEkolom Anda memiliki banyak nilai yang mungkin, pertama-tama indeks semuanya. Kemudian seperti yang dikatakan @ypercube, coba atur ulang dan lihat apa yang EXPLAIN katakan. Seharusnya semuanya hampir sama.

Selain itu, ingin Anda melihat pada Indexing SQL LIKE Filter . Meskipun itu bukan jawaban yang Anda butuhkan, tetapi Anda masih akan belajar tentang bagaimana pengindeksan bekerja di bawah tenda.

* Sunting: Lihat tautan yang disediakan di bawah di komentar untuk mempelajari lebih lanjut tentang pengindeksan.

Mata
sumber
8
-1 Mengindeks setiap kolom BUKAN praktik terbaik. Setiap indeks membebani Anda dengan berbagai cara. Pastikan Anda memilih indeks yang baik, yang biasanya terdiri dari beberapa kolom, biasanya dalam urutan selektivitas dan frekuensi yang digunakan. Ini mungkin SQL Server miring, tetapi info indeks masih valid: sqlskills.com/BLOGS/KIMBERLY/post/… .
Eric Humphrey - lotsahelp
@Eric Humphrey +1 Untuk penjelasan dan tautan ke situs Kimberly.
Matt M
Anda salah, memiliki indeks pada kolom terkadang merusak kinerja Anda pada pertanyaan tertentu: mysqlperformanceblog.com/2007/08/28/… . Anda harus TIDAK PERNAH menggunakan aturan praktis: kadang-kadang itu berhasil, kadang tidak.
sumar
Benar saya setuju. Namun, ini berlaku jika selektivitas nilai rendah. Mengingat tipe data yang Patrick (penulis pertanyaan ini) gunakan, yaitu DATETIME, pengindeksan disarankan. Biasanya tipe bidang ini memiliki set nilai yang cukup besar, kecuali ada situasi aneh ketika ia hanya menggunakan beberapa tanggal yang mungkin. * Saya akan mengedit jawaban saya di atas untuk membuat pernyataan yang lebih jelas dan valid.
Eye