it-swarm-eu.dev

Was ist die Standardreihenfolge von Datensätzen für eine SELECT-Anweisung in MySQL?

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?

76
daisy

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:

  • MySQL sortiert die Datensätze nach Belieben ohne Garantie für Konsistenz.
  • Wenn Sie sich für irgendetwas auf diese Bestellung verlassen möchten , müssen Sie Ihre gewünschte Bestellung mit 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.

87
Nick Chammas

Die Reihenfolge der Zeilen in Abwesenheit von ORDER BY Klausel kann sein:

  • unterschiedlich zwischen zwei beliebigen Speicher-Engines;
  • wenn Sie dieselbe Speicher-Engine verwenden, kann dies zwischen zwei Versionen derselben Speicher-Engine unterschiedlich sein. Beispiel hier , scrollen Sie nach unten zu "Reihenfolge der Zeilen".
  • wenn die Version der Speicher-Engine identisch ist, die MySQL-Version jedoch unterschiedlich ist, kann dies aufgrund der Änderungen des Abfrageoptimierers zwischen diesen Versionen unterschiedlich sein.
  • wenn alles gleich ist, kann es aufgrund der Mondphase anders sein und das ist in Ordnung.
29

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.

11
James Pulley

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 INSERTs 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.

5
RolandoMySQLDBA