Angenommen, Sie haben die folgende Tabelle und Daten:
create table t (
k int,
v int,
index k(k)
) engine=memory;
insert into t (k, v)
values (10, 1),
(10, 2),
(10, 3);
Bei der Ausgabe von select * from t where k = 10
ohne order by
Klausel, wie sortiert MySQL die Datensätze standardmäßig?
Reposting meine Antwort auf eine ähnliche Frage zu SQL Server:
In der SQL-Welt ist die Reihenfolge keine inhärente Eigenschaft eines Datensatzes. Daher erhalten Sie von Ihrem RDBMS keine Garantie dafür, dass Ihre Daten in einer bestimmten Reihenfolge - oder sogar in einer konsistenten Reihenfolge - zurückgegeben werden, es sei denn, Sie fragen Ihre Daten mit einer ORDER BY-Klausel ab.
Um Ihre Frage zu beantworten:
ORDER BY
Angeben. Alles andere zu tun bedeutet, sich auf unerwünschte Überraschungen vorzubereiten. Dies ist eine Eigenschaft von SQL, nicht nur von MySQL. Der relevante Text in der SQL-92-Spezifikation lautet:
Wenn keine <order by-Klausel> angegeben ist, ist die Reihenfolge der Zeilen von Q implementierungsabhängig.
Die Spezifikation für Cursor enthält ähnliche Textteile.
Die Reihenfolge der Zeilen in Abwesenheit von ORDER BY
Klausel kann sein:
Das Einfügen ist bei der Ankunft ungeordnet, chaotisch. Der Index, der erstellt wird, hat eine Reihenfolge, in der Elemente an der richtigen Stelle in die verknüpfte Liste eingefügt werden, die der Index ist. Stellen Sie sich eine dreifach verknüpfte Liste für einen Index vor, in der Sie einen vorwärts bewegenden Link von einem Indexelement zum nächsten, einen rückwärts gerichteten Link für die Durchlauf- und Integritätszwecke und dann eine Reihe von Zeigern auf die tatsächlichen Datensätze in der Tabelle haben stimmen mit dem betreffenden indizierten Element überein.
Aktuelle Daten, chaotisch im Speicher. Index zu den Daten, geordnet nach Lagerung und Konstruktion. Das tatsächliche Abrufen von geordneten oder ungeordneten Daten hängt von der jeweiligen Abfrage ab.
Wenn es um die MEMORY-Speicher-Engine geht, würde ich erwarten, dass die Reihenfolge in der Reihenfolge der Einfügung liegt, da der Standardindex Das Layout ist HASH
anstelle von BTREE
und keiner der Aspekte des Indexlayouts wird verwendet. Da Sie k indiziert haben und k der gleiche Wert ist, geben alle Schlüssel den gleichen Hash-Bucket ein. Da es keinen Grund gibt, eine zusätzliche Komplexität beim Auffüllen eines Hash-Buckets anzunehmen, ist die Reihenfolge des Einfügens am sinnvollsten.
Ich habe dieselbe Beispieltabelle und dieselben Daten genommen und 30 INSERT
s ausgeführt, und ich habe Folgendes erhalten:
mysql> use test
Database changed
mysql> drop table if exists t;
Query OK, 0 rows affected (0.00 sec)
mysql> create table t(k int, v int,index k(k)) engine=memory;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into t values
-> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
-> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
-> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
-> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
-> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3);
Query OK, 30 rows affected (0.00 sec)
Records: 30 Duplicates: 0 Warnings: 0
mysql> select * from t;
+------+------+
| k | v |
+------+------+
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
+------+------+
30 rows in set (0.00 sec)
mysql>
Ich habe mich entschlossen, zwei verschiedene Werte für k: 10 und 11 zu testen. Ich habe Folgendes erhalten:
mysql> use test
Database changed
mysql> drop table if exists t;
Query OK, 0 rows affected (0.02 sec)
mysql> create table t(k int, v int,index k(k)) engine=memory;
Query OK, 0 rows affected (0.01 sec)
mysql> insert into t values
-> (11, 1), (11, 2), (11, 3), (10, 1), (10, 2), (10, 3),
-> (11, 1), (11, 2), (11, 3), (10, 1), (10, 2), (10, 3),
-> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
-> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
-> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3);
Query OK, 30 rows affected (0.00 sec)
Records: 30 Duplicates: 0 Warnings: 0
mysql> select * from t;
+------+------+
| k | v |
+------+------+
| 11 | 1 |
| 11 | 2 |
| 11 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 11 | 1 |
| 11 | 2 |
| 11 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
+------+------+
30 rows in set (0.00 sec)
mysql>
Sieht aus wie die Reihenfolge des Einfügens. k = 11 war der erste Schlüssel, der dann 10 gehasht wurde. Was ist mit dem Einfügen von 10 anstelle von 11? Das habe ich bekommen:
mysql> use test
Database changed
mysql> drop table if exists t;
Query OK, 0 rows affected (0.02 sec)
mysql> create table t(k int, v int,index k(k)) engine=memory;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into t values
-> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
-> (11, 1), (11, 2), (11, 3), (10, 1), (10, 2), (10, 3),
-> (11, 1), (11, 2), (11, 3), (10, 1), (10, 2), (10, 3),
-> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
-> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3);
Query OK, 30 rows affected (0.00 sec)
Records: 30 Duplicates: 0 Warnings: 0
mysql> select * from t;
+------+------+
| k | v |
+------+------+
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 11 | 1 |
| 11 | 2 |
| 11 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 11 | 1 |
| 11 | 2 |
| 11 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
| 10 | 1 |
| 10 | 2 |
| 10 | 3 |
+------+------+
30 rows in set (0.00 sec)
mysql>
Es ist einstimmig !!! ORDER OF INSERTION ist die Antwort.
Nebenbemerkungen zur Verwendung von Indizes für die MEMORY-Speicher-Engine
Die Reichweitensuche nach MEMORY hätte eine vergleichsweise schreckliche Leistung.
Beim Erstellen eines Index können Sie die Klausel USING BTREE
Zusammen mit der Definition des Index angeben. Dies würde die Dinge für Bereichsabfragen verbessern.
Die Suche nach einer bestimmten Zeile führt zu demselben Leistungsergebnis mit HASH
oder BTREE
.
UPDATE 2011-09-22 11:18 EDT
Ich habe heute etwas Interessantes gelernt. Ich habe den Link von @ Laurynas Biveinis von Percona gelesen: Der Percona-Link sagt etwas über MEMORY-Tabellen für MySQL 5.5.15:
Reihenfolge der Zeilen
Wenn ORDER BY nicht vorhanden ist, können Datensätze in einer anderen Reihenfolge als bei der vorherigen MEMORY-Implementierung zurückgegeben werden. Dies ist kein Fehler. Jede Anwendung, die sich auf eine bestimmte Bestellung ohne ORDER BY-Klausel stützt, kann unerwartete Ergebnisse liefern. Eine bestimmte Bestellung ohne ORDER BY ist ein Nebeneffekt einer Implementierung der Speicher-Engine und des Abfrageoptimierers, die sich zwischen kleineren MySQL-Versionen ändern kann und wird.
Dies war ein guter Link, den ich heute sehen konnte. Die Antwort, die ich gab, zeigte, dass die von mir geladene Tabelle in der Reihenfolge abgerufen wurde, die ich HEUTE in MySQL 5.5.12 erwartet hatte. Wie gerade von Percona und @ Laurynas Biveinis hervorgehoben, gibt es in einer anderen Nebenversion keine Garantie.
Anstatt zu versuchen, meine Antwort zu verteidigen, würde ich lieber die Antwort von @ Laurynas Biveinis bewerben, da dies die aktuellste Information ist. Ein großes Lob und Hut ab für @ Laurynas Biveinis . Ich möchte auch @ eevar dafür danken, dass er höflich darauf hingewiesen hat, keine versionenspezifischen Antworten auf Fragen zu fördern. Beide bekommen heute meine Gegenstimme.