¿Cuál es el orden predeterminado de registros para una instrucción SELECT en MySQL?

66

Supongamos que tiene la siguiente tabla y datos:

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

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

Cuando se emite select * from t where k = 10sin order bycláusula, ¿cómo ordena MySQL los registros por defecto?

margarita
fuente

Respuestas:

75

Volviendo a publicar mi respuesta a una pregunta similar con respecto a SQL Server:

En el mundo SQL, el orden no es una propiedad inherente de un conjunto de datos. Por lo tanto, no obtiene garantías de su RDBMS de que sus datos volverán en un cierto orden, o incluso en un orden consistente, a menos que consulte sus datos con una cláusula ORDER BY.

Entonces, para responder a su pregunta:

  • MySQL ordena los registros como quiera sin ninguna garantía de coherencia.
  • Si tiene la intención de confiar en este pedido para cualquier cosa, debe especificar su pedido deseado utilizando ORDER BY. Hacer cualquier otra cosa es prepararse para sorpresas no deseadas.

Esta es una propiedad de todos los SQL, no solo MySQL. El texto relevante en la especificación SQL-92 es:

Si no se especifica un <orden por cláusula>, el orden de las filas de Q depende de la implementación.

Hay fragmentos de texto similares en la especificación para cursores.

Nick Chammas
fuente
26

El orden de las filas en ausencia de ORDER BYcláusula puede ser:

  • diferente entre dos motores de almacenamiento;
  • si usa el mismo motor de almacenamiento, puede ser diferente entre dos versiones del mismo motor de almacenamiento; Ejemplo aquí , desplácese hacia abajo hasta "Ordenar filas".
  • si la versión del motor de almacenamiento es la misma, pero la versión de MySQL es diferente, podría ser diferente debido a los cambios del optimizador de consultas entre esas versiones;
  • Si todo es igual, podría ser diferente debido a la fase lunar y eso está bien.
Laurynas Biveinis
fuente
10

La inserción es desordenada, caótica, a la llegada. El índice que se crea tiene un orden en el que los elementos se insertan en la ubicación adecuada en la lista vinculada que es el índice. Piense en una lista de enlaces triplicados para un índice, donde tiene un enlace de avance hacia adelante de un elemento de índice al siguiente, un enlace que mira hacia atrás para propósitos de recorrido e integridad, y luego un conjunto de punteros a los registros reales en la tabla que coincide con el elemento indexado en cuestión.

Datos reales, caóticos en el almacenamiento. Índice asociado a los datos, ordenados en almacenamiento y construcción. La extracción real de datos, ordenados o no ordenados, depende de la consulta involucrada.

James Pulley
fuente
4

Cuando se trata del motor de almacenamiento MEMORY , esperaría que el orden sea por el orden de inserción porque el diseño de índice predeterminado es en HASHlugar de BTREEy no se está utilizando ningún aspecto del diseño de índice. Como indizó k, y k es el mismo valor, todas las claves ingresan al mismo depósito de hash. Dado que no hay ninguna razón para suponer una complejidad adicional para llenar un cubo de hash, el orden de inserción tiene más sentido.

Tomé su misma tabla de muestra y datos y corrí 30 INSERTsy obtuve esto:

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>

Decidí probar agregando dos valores diferentes para k: 10 y 11 Obtuve esto:

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>

Parece el orden de inserción. k = 11 fue el primer hash de clave y luego 10. ¿Qué hay de insertar 10 primero en lugar de 11? Esto es lo que conseguí:

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 unánime! ORDEN DE INSERCIÓN es la respuesta.

Notas al margen sobre el uso de índices para el motor de almacenamiento MEMORY

Las búsquedas de rango para MEMORY tendrían un rendimiento comparablemente horrible.

Al crear un índice, puede especificar una USING BTREEcláusula junto con la definición del índice. Esto mejoraría las cosas para las consultas de rango.

La búsqueda de una fila específica arrojará el mismo resultado en el rendimiento con HASHo BTREE.

ACTUALIZACIÓN 2011-09-22 11:18 EDT

Aprendí algo interesante hoy. Leí el enlace proporcionado por @Laurynas Biveinis de Percona: el enlace de Percona dice algo sobre las tablas de MEMORIA para MySQL 5.5.15 :

Orden de filas

En ausencia de ORDER BY, los registros pueden devolverse en un orden diferente al de la implementación de MEMORIA anterior. Esto no es un error. Cualquier aplicación que se base en un pedido específico sin una cláusula ORDER BY puede generar resultados inesperados. Un pedido específico sin ORDER BY es un efecto secundario de un motor de almacenamiento y una implementación del optimizador de consultas que puede cambiar y cambiará entre versiones menores de MySQL.

Este fue un buen enlace para ver hoy. La respuesta que di demostró que la tabla que cargué se recuperó en el orden que esperaba HOY en MySQL 5.5.12. Como acaban de señalar Percona y @Laurynas Biveinis , no hay garantía en otro lanzamiento menor.

Entonces, en lugar de tratar de defender mi respuesta, prefiero promover la respuesta de @Laurynas Biveinis porque es la información más actualizada. Felicitaciones y felicitaciones para @Laurynas Biveinis . También me gustaría agradecer a @eevar por señalar cortésmente que no promueva respuestas a preguntas específicas de la versión. Ambos reciben mi voto positivo hoy.

RolandoMySQLDBA
fuente