web-dev-qa-db-fra.com

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

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

Lors de l'émission select * from t where k = 10 sans order by clause, comment MySQL trie-t-il les enregistrements par défaut?

76
daisy

Republication 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, vous n'obtenez aucune garantie de votre SGBDR que vos données reviendront dans un certain ordre - ou même dans un ordre cohérent - sauf si vous interrogez vos données 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 pour quelque chose, , vous devez spécifier la commande souhaitée à l'aide de ORDER BY. Faire autre chose, c'est vous préparer à des surprises importunes.

C'est une propriété de tout SQL, pas seulement de MySQL. Le texte pertinent dans le 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 l'implémentation.

Il y a des morceaux de texte similaires dans la spécification pour les curseurs.

87
Nick Chammas

L'ordre des lignes en l'absence de ORDER BY la clause 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'à "Ordre des lignes".
  • si la version du moteur de stockage est la même, mais que la version de MySQL est différente, elle peut être différente en raison des changements de l'optimiseur de requête entre ces versions;
  • si tout est le même, cela pourrait être différent en raison de la phase de lune et c'est OK.
29
Laurynas Biveinis

L'insertion est désordonnée, chaotique, à l'arrivée. L'index qui est créé a l'ordre dans lequel les éléments sont insérés à l'emplacement approprié dans la liste chaînée qui est l'index. Pensez à une liste triplement liée pour un index, où vous avez un lien vers l'avant d'un élément d'index au suivant, un lien vers l'arrière pour les fins de traversée et d'intégrité, puis un ensemble de pointeurs vers les enregistrements réels dans le tableau qui correspondre à l'élément indexé en question.

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

11
James Pulley

En ce qui concerne le moteur de stockage MEMORY , je m'attendrais à ce que l'ordre soit par ordre d'insertion car l'index par défaut la disposition est HASH au lieu de BTREE et aucun des aspects de la disposition d'index n'est utilisé. Puisque vous avez indexé k et k est la même valeur, toutes les clés entrent dans le même compartiment de hachage. Puisqu'il n'y a aucune raison de supposer une complexité supplémentaire pour remplir un compartiment de hachage, l'ordre d'insertion est le plus logique.

J'ai pris votre même exemple de table et de données et j'ai exécuté 30 INSERTs et j'ai obtenu ceci:

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, j'ai obtenu ceci:

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 d'abord au lieu de 11? Voici ce que j'ai obtenu:

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 !!! ORDRE D'INSERTION est la réponse.

Sidenotes sur l'utilisation des index pour le moteur de stockage MEMORY

Les recherches de plage pour MEMORY auraient des performances horribles comparables.

Lors de la création d'un index, vous pouvez spécifier USING BTREE clause 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 HASH ou 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 dit quelque chose sur les tables MEMORY pour MySQL 5.5.15:

Ordre des lignes

En l'absence de ORDER BY, les enregistrements peuvent être retournés dans un ordre différent de celui de la précédente mise en œuvre de MEMORY. Ce n'est pas un bug. Toute application s'appuyant sur une commande spécifique sans clause ORDER BY peut fournir des résultats inattendus. Une commande spécifique sans ORDER BY est un effet secondaire d'une implémentation d'un moteur de stockage et d'un optimiseur de requête qui peut et va changer entre les versions mineures de MySQL.

Ce fut un bon lien pour moi de voir aujourd'hui. La réponse que j'ai donnée a démontré que la table que j'ai chargée a été récupérée dans l'ordre que j'attendais AUJOURD'HUI dans MySQL 5.5.12. Comme vient de le souligner 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ère promouvoir la réponse de @ Laurynas Biveinis car il s'agit des informations les plus récentes. Bravo et chapeau pour @ Laurynas Biveinis . Je voudrais également remercier @ eevar pour avoir poliment souligné de ne pas promouvoir les réponses spécifiques aux versions des questions. Ils ont tous les deux obtenu mon vote positif aujourd'hui.

5
RolandoMySQLDBA