Quel est l'ordre par défaut des enregistrements pour une instruction SELECT dans MySQL?


66

Supposons que vous ayez le tableau et les données suivants:

create table t (
    k int,
    v int,
    index k(k)
    ) engine=memory;

insert into t (k, v)
values (10, 1),
       (10, 2),
       (10, 3);

Comment MySQL trie-t-il les enregistrements par défaut lors de l’émission select * from t where k = 10sans order byclause?

Réponses:


75

Republier ma réponse à une question similaire concernant SQL Server:

Dans le monde SQL, l'ordre n'est pas une propriété inhérente d'un ensemble de données. Ainsi, votre SGBDR ne garantit pas que vos données vont revenir dans un certain ordre - ni même dans un ordre cohérent - à moins que vous ne les interrogiez avec une clause ORDER BY.

Donc, pour répondre à votre question:

  • MySQL trie les enregistrements comme il le souhaite sans aucune garantie de cohérence.
  • Si vous avez l'intention de vous fier à cette commande, vous devez spécifier votre commande souhaitée à l'aide de ORDER BY. Faire autre chose, c'est vous préparer à de mauvaises surprises.

C'est une propriété de tout le SQL, pas seulement de MySQL. Le texte pertinent dans la spécification SQL-92 est:

Si une clause <order by>> n'est pas spécifiée, l'ordre des lignes de Q dépend de la mise en œuvre.

Il existe des bits de texte similaires dans les spécifications pour les curseurs.


26

L'ordre des lignes en l'absence de ORDER BYclause peut être:

  • différent entre deux moteurs de stockage;
  • Si vous utilisez le même moteur de stockage, il peut être différent entre deux versions du même moteur de stockage. Exemple ici , faites défiler jusqu'à "Commande de rangées".
  • si la version du moteur de stockage est la même, mais que la version de MySQL est différente, il est possible que cela soit différent en raison des modifications apportées par l'optimiseur de requête entre ces versions;
  • si tout est pareil, cela pourrait être différent en raison de la phase de lune et c'est OK.

10

L'insertion est non ordonnée, chaotique, à l'arrivée. L'index créé a un ordre dans lequel les éléments sont insérés à l'emplacement approprié dans la liste liée qui est l'index. Pensez à une liste triplement liée pour un index, dans laquelle vous avez un lien aller-retour d’un élément d’index à l’autre, un lien en arrière pour les objectifs de parcours et d’intégrité, puis un ensemble de pointeurs sur les enregistrements réels de la table qui correspondre à l'élément indexé en question.

Données réelles, chaotiques dans la mémoire. Index associé aux données, ordonné en stockage et en construction. L'extraction réelle des données, ordonnées ou non, dépend de la requête impliquée.


4

En ce qui concerne le moteur de stockage MEMORY , je m'attendrais à ce que l'ordre soit classé par ordre d'insertion, car la disposition d'index par défaut est HASHremplacée par BTREEaucun élément de la disposition d'index n'est utilisé. Puisque vous avez indexé k et que k a la même valeur, toutes les clés entrent dans le même panier de hachage. Comme il n’ya aucune raison d’assumer une complexité supplémentaire lors du remplissage d’un panier de hachage, l’ordre d’insertion a plus de sens.

J'ai pris votre même exemple de table et de données INSERTet ai couru pendant 30 secondes.

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>

J'ai décidé de tester en ajoutant deux valeurs différentes pour k: 10 et 11.

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>

Ressemble à l'ordre d'insertion. k = 11 était la première clé hachée puis 10. Qu'en est-il d'insérer 10 en premier au lieu de 11? C'est ce que j'ai eu:

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>

C'est unanime !!! ORDER OF INSERTION est la réponse.

Notes de bas de page sur l'utilisation des index pour le moteur de stockage MEMORY

Les recherches de plage pour MEMORY auraient des performances comparables.

Lors de la création d'un index, vous pouvez spécifier une USING BTREEclause avec la définition de l'index. Cela améliorerait les choses pour les requêtes de plage.

La recherche d'une ligne spécifique produira le même résultat en termes de performances avec HASHou BTREE.

MISE À JOUR 2011-09-22 11:18 EDT

J'ai appris quelque chose d'intéressant aujourd'hui. J'ai lu le lien fourni par @Laurynas Biveinis de Percona: Le lien Percona en dit long sur les tables MEMORY pour MySQL 5.5.15 :

Commande de rangées

En l'absence de ORDER BY, les enregistrements peuvent être renvoyés dans un ordre différent de celui de l'implémentation précédente de MEMORY. Ce n'est pas un bug. Toute application reposant sur un ordre spécifique sans clause ORDER BY peut générer des résultats inattendus. Un ordre spécifique sans ORDER BY est l’effet secondaire de l’implémentation d’un moteur de stockage et de l’optimiseur de requêtes qui peut et va changer entre les versions mineures de MySQL.

C'était un bon lien pour moi à voir aujourd'hui. La réponse que j'ai donnée montre que la table que j'ai chargée a été récupérée dans l'ordre que je prévoyais aujourd'hui dans MySQL 5.5.12. Comme l'ont souligné Percona et @Laurynas Biveinis , il n'y a aucune garantie dans une autre version mineure.

Donc, plutôt que d'essayer de défendre ma réponse, je préférerais promouvoir la réponse de @Laurynas Biveinis parce que c'est l'information la plus récente. Bravo et chapeau pour @Laurynas Biveinis . Je tiens également à remercier @eevar d’ avoir fait remarquer poliment de ne pas promouvoir les réponses aux questions par version. Ils ont tous deux mon vote positif aujourd'hui.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.