Tôi có hai bảng, bảng đầu tiên chứa tất cả các bài viết / bài đăng trên blog trong một CMS. Một số bài viết này cũng có thể xuất hiện trên một tạp chí, trong trường hợp đó chúng có mối quan hệ khóa ngoại với một bảng khác có chứa thông tin cụ thể của tạp chí.
Đây là một phiên bản đơn giản của cú pháp tạo bảng cho hai bảng này với một số hàng không cần thiết được loại bỏ:
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 chứa tổng cộng khoảng 250.000 bài viết và tôi đã viết một tập lệnh Python đơn giản có thể được sử dụng để điền vào cơ sở dữ liệu thử nghiệm với dữ liệu mẫu nếu họ muốn sao chép vấn đề này cục bộ.
Nếu tôi chọn từ một trong các bảng này, MySQL không có vấn đề gì trong việc chọn một chỉ mục thích hợp hoặc truy xuất các bài viết một cách nhanh chóng. Tuy nhiên, khi hai bảng được nối với nhau trong một truy vấn đơn giản, chẳng hạn như:
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 không chọn được một truy vấn thích hợp và hiệu suất giảm mạnh. Dưới đây là phần giải thích có liên quan được kéo dài (thời gian thực hiện trong hơn một giây):
+----+-------------+--------------+--------+-----------------------------------+---------+---------+----------------------------------------+-------+----------+---------------------------------+
| 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 SEPT 30: Tôi có thể xóa
WHERE
mệnh đề khỏi truy vấn này, nhưng truy vấnEXPLAIN
vẫn giống nhau và truy vấn vẫn chậm.
Một giải pháp tiềm năng là buộc một chỉ số. Chạy cùng một truy vấn với FORCE INDEX (base_articel_date_published)
kết quả trong một truy vấn thực hiện trong khoảng 1,6 mili giây.
+----+-------------+--------------+--------+---------------+-----------------------------+---------+-------------------------+------+-----------+-------------+
| 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 | |
+----+-------------+--------------+--------+---------------+-----------------------------+---------+-------------------------+------+-----------+-------------+
Tôi muốn không phải buộc một chỉ mục trên truy vấn này nếu tôi có thể tránh nó, vì một số lý do. Đáng chú ý nhất, truy vấn cơ bản này có thể được lọc / sửa đổi theo nhiều cách khác nhau (chẳng hạn như lọc theo issue_slug
) sau đó base_article_date_published
có thể không còn là chỉ mục tốt nhất để sử dụng.
Bất cứ ai cũng có thể đề xuất một chiến lược để cải thiện hiệu suất cho truy vấn này?
base_article_is_published
(is_published
) .. đối với tôi đó là loại boolean ..