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

66

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);

Wie sortiert MySQL die Datensätze standardmäßig, wenn select * from t where k = 10keine order byKlausel ausgegeben wird?

Gänseblümchen
quelle

Antworten:

75

Reposting meine Antwort auf eine ähnliche Frage zu SQL Server:

In der SQL-Welt ist die Reihenfolge keine inhärente Eigenschaft einer Datenmenge. Daher erhalten Sie von Ihrem RDBMS keine Garantie dafür, dass Ihre Daten in einer bestimmten Reihenfolge - oder sogar in einer konsistenten Reihenfolge - zurückkehren, es sei denn, Sie fragen Ihre Daten mit einer ORDER BY-Klausel ab.

Um Ihre Frage zu beantworten:

  • MySQL sortiert die Datensätze so, wie es möchte, ohne Gewähr für Konsistenz.
  • Wenn Sie sich für irgendetwas auf diese Bestellung verlassen möchten, müssen Sie Ihre gewünschte Bestellung mit angeben ORDER BY. Um etwas anderes zu tun, müssen Sie sich auf unerwünschte Überraschungen einstellen.

Dies ist eine Eigenschaft von SQL, nicht nur von MySQL. Der relevante Text in der SQL-92-Spezifikation lautet:

Wenn keine <order by clause> angegeben ist, ist die Reihenfolge der Zeilen von Q von der Implementierung abhängig.

Es gibt ähnliche Textteile in der Spezifikation für Cursor.

Nick Chammas
quelle
26

Die Reihenfolge der Zeilen in Abwesenheit von ORDER BYKlausel kann sein:

  • zwischen zwei Speicher-Engines unterschiedlich sein;
  • Wenn Sie dasselbe Speichermodul verwenden, kann es zwischen zwei Versionen desselben Speichermoduls unterschiedlich sein. Beispiel hier , scrollen Sie nach unten zu "Reihenfolge der Zeilen".
  • Wenn die Speicher-Engine-Version identisch ist, die MySQL-Version jedoch unterschiedlich ist, kann dies daran liegen, dass sich das Abfrageoptimierungsprogramm zwischen diesen Versionen ändert.
  • Wenn alles gleich ist, könnte es aufgrund der Mondphase anders sein, und das ist in Ordnung.
Laurynas Biveinis
quelle
10

Insertion ist ungeordnet, chaotisch, bei der Ankunft. Der erstellte Index weist eine Reihenfolge auf, in der Elemente an der richtigen Stelle in der verknüpften 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ärtsgerichteten Link von einem Indexelement zum nächsten, einen rückwärtsgerichteten Link für Traversal- 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. Zu den Daten gehöriger Index, sortiert nach Lagerung und Konstruktion. Der tatsächliche Abruf von Daten, geordnet oder ungeordnet, hängt von der jeweiligen Abfrage ab.

James Pulley
quelle
4

Wenn es um die Speicher-Engine MEMORY geht , würde ich erwarten, dass die Reihenfolge nach Einfügereihenfolge erfolgt, da HASHstattdessen das Standard-Index-Layout verwendet wird BTREEund keiner der Aspekte des Index-Layouts verwendet wird. 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, zusätzliche Komplexität beim Auffüllen eines Hash-Buckets anzunehmen, ist die Reihenfolge des Einfügens am sinnvollsten.

Ich habe dieselbe Probentabelle und dieselben Daten genommen und 30 INSERTSekunden lang ausgeführt.

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 dazu entschlossen, zwei verschiedene Werte für k: 10 und 11 zu addieren.

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 Reihenfolge der Einfügung. k = 11 war der erste Schlüssel gehasht dann 10. Was ist mit dem Einfügen von 10 zuerst 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 !!! INSERTIONSORDNUNG ist die Antwort.

Anmerkungen zur Verwendung von Indizes für die MEMORY-Speicher-Engine

Die Reichweitensuche nach MEMORY hätte eine vergleichsweise horrende Leistung.

Beim Erstellen eines Index können Sie eine USING BTREEKlausel zusammen mit der Definition des Index angeben . Dies würde Dinge für Bereichsabfragen verbessern.

Wenn Sie nach einer bestimmten Zeile suchen, erhalten Sie mit HASHoder dasselbe Ergebnis bei der Leistung BTREE.

UPDATE 2011-09-22 11:18 EDT

Ich habe heute etwas Interessantes gelernt. Ich habe den Link von @Laurynas Biveinis aus Percona gelesen: Der Percona-Link sagt etwas über MEMORY-Tabellen für MySQL 5.5.15 aus :

Reihenbestellung

Ohne ORDER BY können Datensätze in einer anderen Reihenfolge als in der vorherigen MEMORY-Implementierung zurückgegeben werden. Dies ist kein Fehler. Jede Anwendung, die auf eine bestimmte Bestellung ohne ORDER BY-Klausel angewiesen ist, kann unerwartete Ergebnisse liefern. Eine bestimmte Reihenfolge ohne ORDER BY ist ein Nebeneffekt einer Implementierung einer Speicher-Engine und eines Abfrageoptimierers, der sich zwischen kleineren MySQL-Versionen ändern kann und wird.

Dies war ein guter Link für mich, um ihn heute zu sehen. Die Antwort, die ich gegeben habe, hat gezeigt, dass die von mir geladene Tabelle abgerufen wurde, damit ich HEUTE in MySQL 5.5.12 rechne. Wie von Percona und @Laurynas Biveinis bereits erwähnt , gibt es in einer anderen kleineren Version keine Garantie.

Anstatt zu versuchen, meine Antwort zu verteidigen, möchte ich lieber die Antwort von @Laurynas Biveinis bewerben, da dies die aktuellste Information ist. Ein großes Lob und einen Hut ab für @Laurynas Biveinis . Ich möchte @eevar auch dafür danken, dass er höflich darauf hingewiesen hat, keine versionsspezifischen Antworten auf Fragen zu veröffentlichen. Sie beide bekommen heute meine Zustimmung.

RolandoMySQLDBA
quelle