Ich versuche, meine blogentries
Datenbank für eine bessere Leistung zu indizieren, habe jedoch ein Problem festgestellt.
Hier ist die Struktur:
CREATE TABLE IF NOT EXISTS `blogentries` (
`id_id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`title_id` varchar(100) COLLATE latin1_german2_ci NOT NULL,
`entry_id` varchar(5000) COLLATE latin1_german2_ci NOT NULL,
`date_id` int(11) NOT NULL,
PRIMARY KEY (`id_id`)
)
ENGINE=MyISAM
DEFAULT CHARSET=latin1
COLLATE=latin1_german2_ci
AUTO_INCREMENT=271;
Eine Abfrage wie die folgende verwendet den Index ordnungsgemäß:
EXPLAIN SELECT id_id,title_id FROM blogentries ORDER by id_id DESC
+ ---- + ------------- + ------------- + ------- + -------- ------- + --------- + --------- + ------ + ------ + -------- ----- + | id | select_type | Tabelle | Typ | mögliche_Tasten | Schlüssel | key_len | ref | Zeilen | Extra | + ---- + ------------- + ------------- + ------- + -------- ------- + --------- + --------- + ------ + ------ + -------- ----- + | 1 | EINFACH | blogentries | Index | NULL | PRIMARY | 114 | NULL | 126 | Index verwenden | + ---- + ------------- + ------------- + ------- + -------- ------- + --------- + --------- + ------ + ------ + -------- ----- +
Wenn ich das entry_id
in die SELECT
Abfrage einfüge, wird jedoch der Dateisort verwendet
EXPLAIN SELECT id_id,title_id,entry_id FROM blogentries ORDER by id_id DESC
+ ---- + ------------- + ------------- + ------ + --------- ------ + ------ + --------- + ------ + ------ + ------------ ---- + | id | select_type | Tabelle | Typ | mögliche_Tasten | Schlüssel | key_len | ref | Zeilen | Extra | + ---- + ------------- + ------------- + ------ + --------- ------ + ------ + --------- + ------ + ------ + ------------ ---- + | 1 | EINFACH | blogentries | ALL | NULL | NULL | NULL | NULL | 126 | Dateisortierung verwenden | + ---- + ------------- + ------------- + ------ + --------- ------ + ------ + --------- + ------ + ------ + ------------ ---- +
Ich habe mich gefragt, warum das passiert und wie ich es vermeiden kann. Liegt es an dem VarChar
, und das sollte in etwas anderes geändert werden?
Ich versuche, dass alle meine Abfragen den Index verwenden, da ich auf hohe Werte Handler_read_rnd
und Handler_read_rnd_next
Werte stoße.
Wenn Sie weitere Informationen benötigen, kann ich diese auch posten.
WHERE 1=1
, Ihrer zweiten Abfrage etwas hinzuzufügen .SELECT @@sort_buffer_size
)?Antworten:
Da Sie
WHERE
in keiner der Abfragen eine Klausel haben , geben Sie in beiden Fällen alle Zeilen zurück. Daher würde die Verwendung oder Nichtverwendung des Index in diesen Beispielen nur sehr geringe Auswirkungen auf die Leistung haben.quelle
ORDER BY
?varchar(5000)
.Wie unter
ORDER BY
Optimierung dokumentiert :In seinem Blog-Artikel Was genau ist read_rnd_buffer_size , erklärt Peter Zaitsev:
Dies deutet darauf hin, dass
max_length_for_sort_data
die Gesamtgröße der ausgewählten Spalten begrenzt ist, oberhalb derer afilesort
anstelle einer indexbasierten Sortierung verwendet wird.In Ihrem Fall nimmt die Auswahl
entry_id
(5002 Byte) die Gesamtgröße über den 1-KB-Standardwert dieser Variablen und wird daherfilesort
verwendet. Um das Limit auf 8 KB zu erhöhen, können Sie Folgendes tun:quelle
Sie haben hier viele interessante Antworten erhalten, aber niemand hat die Frage genau beantwortet - warum passiert das? Wenn eine SELECT-Abfrage Daten mit variabler Länge in MySQL enthält und es keinen Index gibt, der mit ALLEN angeforderten Spalten übereinstimmt, wird nach meinem Verständnis immer ein Dateisort verwendet. Die Größe der Daten ist hier nicht besonders relevant. Es ist schwer, eine direkte Antwort auf diese Frage in der MySQL-Dokumentation zu finden, aber hier ist ein guter Blog-Beitrag, in dem jemand ein sehr ähnliches Problem wie Sie hat.
Siehe auch: 10 Tipps zur Optimierung von MySQL-Abfragen (die nicht scheißen) .
Wenn es also sinnvoll ist, einen Index für entry_id zu haben, können Sie ihn hinzufügen und fertig sein. Aber ich bezweifle, dass es eine Option ist. Was tun?
Ob Sie etwas dagegen unternehmen sollten, ist eine separate Frage. Es ist wichtig zu wissen, dass 'filesort' in MySQL schlecht benannt ist - es ist wirklich nur der Name des Algorithmus, der zum Sortieren dieser bestimmten Abfrage verwendet wird, und in vielen Fällen erfolgt die Sortierung tatsächlich im Speicher. Wenn Sie nicht erwarten, dass dieser Tisch stark wächst, ist dies wahrscheinlich keine große Sache.
Wenn diese Tabelle jedoch eine Million Zeilen enthält, liegt möglicherweise ein Problem vor. Wenn Sie die Paginierung von Abfragen in dieser Tabelle unterstützen müssen, liegt hier möglicherweise ein wirklich ernstes Leistungsproblem vor. In diesem Fall ist es eine gültige Optimierung, Ihre Daten variabler Länge in eine neue Tabelle zu partitionieren und einen JOIN durchzuführen, um sie abzurufen.
Hier sind ein paar andere Antworten auf SO, die sich mit dieser Frage befassen:
quelle
filesort
wurde jedoch in diesem Fall anscheinend nicht verwendet. Ich denke auch, dass sich das Sortieren einer kleinen Tabelle im Speicher allein als inakzeptabler Leistungseinbruch erweisen könnte: z. B. wenn die Abfrage häufig ausgeführt wird (und die Tabelle sich ändert, sodass Caches nicht verwendet werden können).Fügen Sie
WHERE
Ihren Abfragen eine Klausel hinzu .http://dev.mysql.com/doc/refman/5.0/en/order-by-optimization.html
quelle
ORDER BY
stimmt das jedoch genau mit dem Index überein, sodass keineWHERE
Klausel erforderlich ist.Nach meinem Kenntnisstand kann varchar nur maximal 8000 Bytes aufnehmen, was ungefähr 4000 Zeichen entspricht. Somit scheinen 5000 die Speichergrenze zu überschreiten, und in diesem Fall wahrscheinlich der Grund, warum die Sortierung durcheinander gebracht wird.
"varchar [(n | max)] Nicht-Unicode-Zeichendaten variabler Länge. n kann ein Wert zwischen 1 und 8.000 sein. max gibt an, dass die maximale Speichergröße 2 ^ 31-1 Byte beträgt. Die Speichergröße ist die tatsächliche Länge der eingegebenen Daten + 2 Bytes. Die eingegebenen Daten können 0 Zeichen lang sein. Die SQL-2003-Synonyme für varchar sind Zeichen oder Zeichen. "
Hoffe das beantwortet deine Frage
quelle
CHAR
undVARCHAR
Types dokumentiert : " Werte in VARCHAR-Spalten sind Zeichenfolgen variabler Länge. Die Länge kann als Wert von 0 bis 255 vor MySQL 5.0.3 und von 0 bis 65.535 in 5.0.3 und späteren Versionen angegeben werden Die maximale Länge von aVARCHAR
in MySQL 5.0.3 und höher hängt von der maximalen Zeilengröße (65.535 Byte, die von allen Spalten gemeinsam genutzt wird) und dem verwendeten Zeichensatz ab. "Sie haben nur 126 Zeilen in Ihrer Tabelle. Selbst wenn jede Zeile maximal 5 KB groß ist, bedeutet dies, dass die Gesamtgröße zum Lesen von der Festplatte nur etwa 600 KB beträgt - dies ist keine ganze Menge. Um ehrlich zu sein, es ist eine sehr kleine Menge, wahrscheinlich weniger als die Cache-Größe der meisten modernen Festplatten.
Wenn der Server Ihre Daten abrufen muss, um Ihre Anfrage zu erfüllen, ist es am teuersten, sie von der Festplatte zu lesen. Das Lesen gemäß der Indexreihenfolge ist jedoch NICHT immer der schnellste Weg, insbesondere wenn die Datenmenge so gering ist.
In Ihrem Fall ist es VIEL effizienter, ganze Tabellendaten als einzelnen Block von der Festplatte in den Speicher zu lesen (wahrscheinlich in nur einer Leseoperation oder Suche) und dann im RAM zu sortieren, um ORDER BY zu erfüllen, was im Vergleich zur Festplatte sofort erfolgt Lesevorgang. Wenn der Server Ihre Daten gemäß dem Index liest, muss er bis zu 126 (oops!) Lesevorgänge ausführen und viele Male in derselben Datendatei hin und her suchen.
Mit anderen Worten, sequentieller Scan ist NICHT immer eine schlechte Sache, und MySQL ist nicht unbedingt dumm. Wenn Sie versuchen, MySQL zu zwingen, diesen Index zu verwenden, funktioniert er höchstwahrscheinlich langsamer als der derzeitige sequentielle Scan.
Der Grund, warum der Index verwendet wurde, wenn kein 5-KB-Feld enthalten war, liegt darin, dass die dann abgerufenen Daten nicht 99% der Daten in der Tabelle ausmachten. Wenn Sie Ihr 5-KB-Feld eingefügt haben, muss die Abfrage jetzt 99% der Daten lesen, und es ist billiger, das Ganze zu lesen und es anschließend im Speicher zu sortieren.
quelle
JOIN
Bedingungen undWHERE
Klauseln zu tun haben , nicht mitORDER BY
Klauseln.Welche Version von MySQL verwenden Sie?
In 5.1 habe ich versucht, Ihr Szenario einzurichten, und einige Dummy-Daten ausgefüllt. Mit den von Ihnen bereitgestellten SQLs erhalte ich jedes Mal nur einen Tabellenscan gemäß EXPLAIN. Standardmäßig wird bei Verwendung von order by MYSQL auf filesort zurückgegriffen, auch wenn der Primärindex in der Reihenfolge by verwendet wird.
quelle