Saya punya dua tabel, tabel pertama berisi semua artikel / posting blog dalam CMS. Beberapa artikel ini juga dapat muncul di majalah, dalam hal ini mereka memiliki hubungan kunci asing dengan tabel lain yang berisi informasi spesifik majalah.
Berikut ini adalah versi sederhana dari sintaks membuat tabel untuk dua tabel ini dengan beberapa baris yang tidak penting dihapus:
CREATE TABLE `base_article` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date_published` datetime DEFAULT NULL,
`title` varchar(255) NOT NULL,
`description` text,
`content` longtext,
`is_published` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `base_article_date_published` (`date_published`),
KEY `base_article_is_published` (`is_published`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `mag_article` (
`basearticle_ptr_id` int(11) NOT NULL,
`issue_slug` varchar(8) DEFAULT NULL,
`rubric` varchar(75) DEFAULT NULL,
PRIMARY KEY (`basearticle_ptr_id`),
KEY `mag_article_issue_slug` (`issue_slug`),
CONSTRAINT `basearticle_ptr_id_refs_id` FOREIGN KEY (`basearticle_ptr_id`) REFERENCES `base_article` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CMS berisi sekitar 250.000 artikel total dan saya telah menulis skrip Python sederhana yang dapat digunakan untuk mengisi basis data uji dengan data sampel jika mereka ingin mereplikasi masalah ini secara lokal.
Jika saya memilih dari salah satu tabel ini, MySQL tidak memiliki masalah memilih indeks yang sesuai atau mengambil artikel dengan cepat. Namun, saat kedua tabel digabungkan bersama dalam kueri sederhana seperti:
SELECT * FROM `base_article`
INNER JOIN `mag_article` ON (`mag_article`.`basearticle_ptr_id` = `base_article`.`id`)
WHERE is_published = 1
ORDER BY `base_article`.`date_published` DESC
LIMIT 30
MySQL gagal memilih kueri yang sesuai dan kinerja menurun. Berikut penjelasan yang relevan diperpanjang (waktu eksekusi lebih dari satu detik):
+----+-------------+--------------+--------+-----------------------------------+---------+---------+----------------------------------------+-------+----------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------------+--------+-----------------------------------+---------+---------+----------------------------------------+-------+----------+---------------------------------+
| 1 | SIMPLE | mag_article | ALL | PRIMARY | NULL | NULL | NULL | 23830 | 100.00 | Using temporary; Using filesort |
| 1 | SIMPLE | base_article | eq_ref | PRIMARY,base_article_is_published | PRIMARY | 4 | my_test.mag_article.basearticle_ptr_id | 1 | 100.00 | Using where |
+----+-------------+--------------+--------+-----------------------------------+---------+---------+----------------------------------------+-------+----------+---------------------------------+
- EDIT SEPTEMBER 30: Saya bisa menghapus
WHERE
klausa dari kueri ini, tetapi klausaEXPLAIN
masih terlihat sama dan kueri masih lambat.
Salah satu solusi potensial adalah dengan memaksa indeks. Menjalankan kueri yang sama dengan FORCE INDEX (base_articel_date_published)
hasil dalam kueri yang dijalankan sekitar 1,6 milidetik.
+----+-------------+--------------+--------+---------------+-----------------------------+---------+-------------------------+------+-----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------------+--------+---------------+-----------------------------+---------+-------------------------+------+-----------+-------------+
| 1 | SIMPLE | base_article | index | NULL | base_article_date_published | 9 | NULL | 30 | 833396.69 | Using where |
| 1 | SIMPLE | mag_article | eq_ref | PRIMARY | PRIMARY | 4 | my_test.base_article.id | 1 | 100.00 | |
+----+-------------+--------------+--------+---------------+-----------------------------+---------+-------------------------+------+-----------+-------------+
Saya lebih suka tidak harus memaksa indeks pada permintaan ini jika saya bisa menghindarinya, karena beberapa alasan. Paling khusus, permintaan dasar ini dapat difilter / dimodifikasi dalam berbagai cara (seperti pemfilteran oleh issue_slug
) setelah itu base_article_date_published
mungkin tidak lagi menjadi indeks terbaik untuk digunakan.
Adakah yang bisa menyarankan strategi untuk meningkatkan kinerja untuk permintaan ini?
base_article_is_published
(is_published
) .. menurut saya ini adalah tipe boolean ..Jawaban:
Bagaimana dengan ini, ini harus menghapus kebutuhan untuk "Menggunakan sementara; Menggunakan filesort" karena data sudah dalam jenis yang tepat.
Anda perlu mengetahui trik mengapa MySQL perlu "Menggunakan sementara; Menggunakan filesort" untuk menghapus kebutuhan itu.
Lihat sqlfriddle kedua untuk penjelasan tentang menghapus kebutuhan
lihat http://sqlfiddle.com/#!2/302710/2
Bekerja cukup baik saya membutuhkan ini juga beberapa waktu lalu untuk tabel Negara / kota lihat demo di sini dengan contoh data http://sqlfiddle.com/#!2/b34870/41
Diedit Anda juga mungkin ingin menganalisis jawaban ini jika base_article.is_published = 1 selalu mengembalikan 1 catatan seperti penjelasan Anda menjelaskan tabel deliverd INNER JOIN dapat memberikan kinerja yang lebih baik seperti pertanyaan dalam jawaban di bawah ini
/programming/18738483/mysql-slow-query-using-filesort/18774937#18774937
sumber
JOIN
hanya menggunakan tetapi MySQL tidak mengambil indeks. Terima kasih banyak, RaymondREFACTOR QUERY THE
atau
MODIFIKASI INDEKS ANDA
COBALAH !!!
sumber
LIMIT 30
ada di subquery (tidak semua dari 30 baris itu juga ada dimag_articles
tabel). Jika saya memindahkanLIMIT
ke kueri luar, kinerjanya sama dengan yang asli. Ubah Indeks: MySQL juga tidak menggunakan indeks itu. MenghapusWHERE
klausa dari permintaan awal saya sepertinya tidak membuat perbedaan.