Ich habe zwei Tabellen, die erste Tabelle enthält alle Artikel / Blog-Beiträge innerhalb eines CMS. Einige dieser Artikel erscheinen möglicherweise auch in einer Zeitschrift. In diesem Fall haben sie eine Fremdschlüsselbeziehung zu einer anderen Tabelle, die magazinspezifische Informationen enthält.
Hier ist eine vereinfachte Version der Syntax zum Erstellen von Tabellen für diese beiden Tabellen, wobei einige nicht wesentliche Zeilen entfernt wurden:
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;
Das CMS enthält insgesamt rund 250.000 Artikel. Ich habe ein einfaches Python-Skript geschrieben , mit dem eine Testdatenbank mit Beispieldaten gefüllt werden kann, wenn dieses Problem lokal repliziert werden soll.
Wenn ich aus einer dieser Tabellen auswähle, hat MySQL kein Problem damit, einen geeigneten Index auszuwählen oder Artikel schnell abzurufen. Wenn die beiden Tabellen jedoch in einer einfachen Abfrage zusammengefügt werden, z.
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 kann keine geeigneten Abfragen auswählen und die Leistung sinkt. Hier ist die relevante Erklärung verlängert (die Ausführungszeit beträgt mehr als eine Sekunde):
+----+-------------+--------------+--------+-----------------------------------+---------+---------+----------------------------------------+-------+----------+---------------------------------+
| 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: Ich kann die
WHERE
Klausel aus dieser Abfrage entfernen , aber dieEXPLAIN
sieht immer noch gleich aus und die Abfrage ist immer noch langsam.
Eine mögliche Lösung besteht darin, einen Index zu erzwingen. Das Ausführen derselben Abfrage mit FORCE INDEX (base_articel_date_published)
Ergebnissen führt zu einer Abfrage, die in etwa 1,6 Millisekunden ausgeführt wird.
+----+-------------+--------------+--------+---------------+-----------------------------+---------+-------------------------+------+-----------+-------------+
| 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 | |
+----+-------------+--------------+--------+---------------+-----------------------------+---------+-------------------------+------+-----------+-------------+
Ich würde es aus mehreren Gründen vorziehen, keinen Index für diese Abfrage erzwingen zu müssen, wenn ich dies vermeiden kann. Insbesondere kann diese grundlegende Abfrage auf verschiedene Arten gefiltert / geändert werden (z. B. durch Filtern nach issue_slug
). Danach ist sie base_article_date_published
möglicherweise nicht mehr der beste zu verwendende Index.
Kann jemand eine Strategie zur Verbesserung der Leistung für diese Abfrage vorschlagen?
base_article_is_published
(is_published
) wirklich löschen . Für mich ist es ein boolescher Typ.