MySQL:Index, wenn der Beitritt zu den Tabellen nicht verwendet wird (Performance-Optimierung Frage)
-
16-10-2019 - |
Frage
Ich brauche optimieren Sie die folgende Abfrage:
SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM blogposts
JOIN articles ON articles.blogpost_id = blogposts.id
WHERE blogposts.deleted = 0
AND blogposts.title LIKE '%{de}%'
AND blogposts.visible = 1
AND blogposts.date_published <= NOW()
ORDER BY blogposts.date_created DESC
LIMIT 0 , 50
ERKLÄREN Sie WÄHLEN, gibt mir das folgende Ergebnis:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE articles ALL blogpost_id NULL NULL NULL 6915 Using temporary; Using filesort
1 SIMPLE blogposts eq_ref PRIMARY PRIMARY 4 articles.blogpost_id 1 Using where
Warum muss es zuerst den Artikel und dann die Beiträge?Ist es, weil die Beiträge haben mehr Einträge?Und wie kann ich die Abfrage so, dass die articlepost können einen index verwenden?
Update: Ein index ist auf Artikel.date_created.Entfernen der Beiträge.Titel WIE Zustand und die date_published <= JETZT() tut nichts.
Wenn ich mit dem entfernen des "Artikel.id artikelid"es kann die blogpost_id-Index für Artikel, die...Klingt seltsam für mich, weiß jemand warum?(weil ich wirklich brauchen es..)
Die neue erklären sieht aus wie diese:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE articles index blogpost_id blogpost_id 4 NULL 6915 Using index; Using temporary; Using filesort
1 SIMPLE blogposts eq_ref PRIMARY PRIMARY 4 articles.blogpost_id 1 Using where
Lösung
Ich nahm einen genaueren Blick auf die Abfrage, und Sie könnten in der Lage sein, um die Neugestaltung es.Hier ist was ich meine:
Der GRENZWERT 0,50 Teil der Abfrage zu haben scheint, beschäftigt in der letzten Abfrage.
Verbessern Sie das layout der Abfrage, indem Sie Folgendes tun:
Schritt 1) Erstellen Sie eine inline-Abfrage zu sammeln, die nur Tasten.In diesem Fall ist die id für Beiträge.
Schritt 2) Impose any WHERE, ORDER BY und GROUP BY-Klauseln auf die inline-Abfrage bringen die Schlüssel.
Schritt 3) Impost die LIMIT-Klausel, die als letzter Schritt der Herstellung der inline-Abfrage.
Schritt 4) nehmen Sie die inline-Abfrage mit der Artikel-Tabelle in dem Fall müssen Sie zusätzliche Spalten aus Beitrag als blostpost temptable
Schritt 5) nehmen Sie diese neuen blogpost temptable mit der Artikel-Tabelle.
Die Schritte 1-3 soll temptable mit genau 50 Zeilen und enthalten die Blog-id.Führen Sie dann alle Verknüpfungen tot zuletzt.
Mit diese Schritte, die in Bezug auf Ihre ursprüngliche Abfrage, sollten Sie diese:
SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM
(
SELECT B.*
FROM
(
SELECT id FROM blogposts
WHERE date_published <= NOW()
AND deleted = 0 AND visible = 1
AND title LIKE '%{de}%'
ORDER BY date_created DESC
LIMIT 0,50
) A
INNER JOIN blogposts B USING (id)
) blogposts
INNER JOIN articles
ON blogposts.id = articles.blogpost_id;
Da Sie bearbeitet die Frage und erklärte, dass Sie entfernen MÖCHTEN, nun Ihre Abfrage sollte Aussehen wie dieses:
SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM
(
SELECT B.*
FROM
(
SELECT id FROM blogposts
WHERE date_published <= NOW()
AND deleted = 0 AND visible = 1
ORDER BY date_created DESC
LIMIT 0,50
) A
INNER JOIN blogposts B USING (id)
) blogposts
INNER JOIN articles
ON blogposts.id = articles.blogpost_id;
In der phrase [die Dinge weggelassen], wenn Sie nicht benötigen, alles von Artikel zu anderen als den Schlüssel, dann Ihre Abfrage sollte wie folgt Aussehen:
SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM
(
SELECT id FROM blogposts
WHERE date_published <= NOW()
AND deleted = 0 AND visible = 1
ORDER BY date_created DESC
LIMIT 0,50
) blogposts
INNER JOIN articles
ON blogposts.id = articles.blogpost_id;
CAVEAT
Stellen Sie sicher, dass Sie einen index erstellen, um die Spalten gelöscht, sichtbar, und date_created wie folgt:
ALTER TABLE blogposts ADD INDEX deleted_visible_date_created (deleted,visible,date_created);
Probieren Sie es aus !!!
Andere Tipps
Ihr Ort blogposts.title LIKE '%{de}%'
führt zu einem vollständigen Tischscan auf der Blogeinträge Tisch. Es ist wahrscheinlich, dass MySQL -Zahlen 6915 Artikel effizienter scannen.
Um es zu verbessern, können Sie einen Index hinzufügen Blogeinträge Verwendung der date_created
oder date_published
und fügen Sie einen Bereich hinzu, um die Bedingung zu erhalten (etwas anderes als <= jetzt ())
Und blogposts.title wie '%{de}%' - nutzlos für die Optimierung (führende Wildkarte)
Wobei blogposts.deleted = 0 und blogposts.vissible = 1 - Yuck: Wenn sie nicht angezeigt werden sollten, bringen Sie sie aus der Tabelle.
Und blogposts.date_published <= now () order by blogposts.date_created Desc Limit 0, 50 - Dies führt dazu, dass der Index benötigt wird (Datum_Published) (jedoch wie und Flags können verhindern, dass dieser Index verwendet wird.)
Bitte geben Sie die Tabelle erstellen erstellen ...; Tabellenstatus anzeigen ...;
Vielen Dank :)
Ich habe es versucht und herausgefunden, dass tatsächlich Ihr letzter Kommentar zum Index das war, was ich brauchte. Manchmal ist es nur eine kleine Verbesserung, die benötigt wird ...;) Vergleich:
Alte Abfrage:
SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM blogposts
JOIN articles ON articles.blogpost_id = blogposts.id
WHERE blogposts.deleted = 0
AND blogposts.title LIKE '%{de}%'
AND blogposts.visible = 1
AND blogposts.date_published <= NOW()
ORDER BY blogposts.date_created DESC
LIMIT 0 , 50
Neue Abfrage:
SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM
(
SELECT B.*
FROM
(
SELECT id FROM blogposts
WHERE date_published <= NOW()
AND deleted = 0 AND visible = 1
AND title LIKE '%{de}%'
ORDER BY date_created DESC
LIMIT 0,50
) A
INNER JOIN blogposts B USING (id)
) blogposts
INNER JOIN articles
ON blogposts.id = articles.blogpost_id
Nun ohne den genannten Index:
Altes Ergebnis erklären:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE articles ALL blogpost_id NULL NULL NULL 6915 Using temporary; Using filesort
1 SIMPLE blogposts eq_ref PRIMARY PRIMARY 4 articles.blogpost_id 1 Using where
Neues Erklärungsergebnis:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 50
1 PRIMARY articles ref blogposts_id blogposts_id 4 blogposts.id 1
2 DERIVED <derived3> ALL NULL NULL NULL NULL 50
2 DERIVED B eq_ref PRIMARY PRIMARY 4 A.id 1
3 DERIVED blogposts ALL deleted,visible,date_published deleted 1 28198 Using filesort
Erläutern Sie das Ergebnis mit Index bei der alten Abfrage:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE blogposts ref PRIMARY,deleted,visible,date_published,deleted_vis... deleted_visible_date_created 2 const,const 27771 Using where
1 SIMPLE articles ref blogposts_id blogposts_id 4 db.blogposts.id 1
Erläutern Sie das Ergebnis mit Index auf neuer Abfrage:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 50
1 PRIMARY articles ref blogposts_id blogposts_id 4 blogposts.id 1
2 DERIVED <derived3> ALL NULL NULL NULL NULL 50
2 DERIVED B eq_ref PRIMARY PRIMARY 4 A.id 1
3 DERIVED blogposts ref deleted,visible,date_published,deleted_visible_dat... deleted_visible_date_created 2 27771 Using where
Geschwindigkeit der alten Abfrage ohne/mit Index: 0.1835/0.0037
Geschwindigkeit auf einer neuen Abfrage ohne/mit Index: 0.1883/0.0035
Aufgrund der gerechten marginalen Unterschiede zwischen der alten/neuen Abfrage bevorzuge ich es, die alte Abfrage jedoch noch mit dem Index zu verwenden. Aber ich werde das berücksichtigen, als ob eines Tages die alte Abfrage zu langsam ist :)
Was für mich interessant wäre, ist zu wissen, wie Sie die Idee haben, den Index so festzulegen? Ich denke, wie ich diese Frage veröffentlicht habe, habe ich auch mit Deleted_visible versucht, aber anstelle von DATE_Created habe ich DATE_PUBLEFLEDS (wie in der Klausel) verwendet ...
Vielen Dank :)
Update von Rolandomysqldba 2011-05-19 13:03
Was es mir verschenkte, war das Wo und Ordnung durch Klauseln.
In der WHERE -Klausel sind gelöscht (0) und sichtbar (1) statische Werte. In der Reihenfolge nach Klausel war das Datum wie ein bewegendes Ziel unter allen Zeilen mit deleted = 0 und sichtbar = 1. Also habe ich zuerst die statischen Variablen vor den Index gestellt und dann das bewegte Ziel im Index. Normalerweise ist dies Teil des zugrunde liegenden Prinzips von SQL -Aussagen. Sie benötigen Indizes, die Ihre Where, Gruppen- und Bestellklauseln unterstützen.