Qual é a ordem padrão dos registros para uma instrução SELECT no MySQL?

66

Suponha que você tenha a seguinte tabela e dados:

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

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

Ao emitir select * from t where k = 10sem order bycláusula, como o MySQL classifica os registros por padrão?

margarida
fonte

Respostas:

75

Reposicionando minha resposta para uma pergunta semelhante sobre o SQL Server:

No mundo SQL, a ordem não é uma propriedade inerente a um conjunto de dados. Assim, você não recebe garantias do seu RDBMS de que seus dados retornarão em uma determinada ordem - ou mesmo em uma ordem consistente - a menos que você os consulte com uma cláusula ORDER BY.

Então, para responder sua pergunta:

  • O MySQL classifica os registros da maneira que desejar, sem nenhuma garantia de consistência.
  • Se você pretende confiar nesse pedido para qualquer coisa, deve especificar o pedido desejado usando ORDER BY. Fazer qualquer outra coisa é se preparar para surpresas indesejadas.

Esta é uma propriedade de todo o SQL, não apenas do MySQL. O texto relevante na especificação SQL-92 é:

Se uma <ordem por cláusula> não for especificada, a ordem das linhas de Q depende da implementação.

Existem bits de texto semelhantes nas especificações dos cursores.

Nick Chammas
fonte
26

A ordem das linhas na ausência de ORDER BYcláusula pode ser:

  • diferente entre dois mecanismos de armazenamento;
  • se você usar o mesmo mecanismo de armazenamento, poderá ser diferente entre duas versões do mesmo mecanismo de armazenamento; Exemplo aqui , role para baixo até "Ordenação de linhas".
  • se a versão do mecanismo de armazenamento for a mesma, mas a versão do MySQL for diferente, poderá ser diferente devido às alterações do otimizador de consulta entre essas versões;
  • se tudo estiver igual, pode ser diferente devido à fase da lua e está tudo bem.
Laurynas Biveinis
fonte
10

A inserção é desordenada, caótica, à chegada. O índice que é criado tem ordem em que os elementos são inseridos no local apropriado na lista vinculada que é o índice. Pense em uma lista triplamente vinculada a um índice, onde você tem um link de avanço de um elemento de índice para o próximo, um link de retrospectiva para propósitos de travessia e integridade e, em seguida, um conjunto de indicadores para os registros reais da tabela que corresponde ao elemento indexado em questão.

Dados reais, caóticos no armazenamento. Índice associado aos dados, ordenados em armazenamento e construção. A atração real de dados, ordenada ou não, depende da consulta envolvida.

James Pulley
fonte
4

Quando se trata do mecanismo de armazenamento MEMORY , eu esperaria que a ordem fosse pela ordem de inserção, porque o layout de índice padrão está em HASHvez de BTREEe nenhum aspecto do layout de índice está sendo usado. Como você indexou k, ek é o mesmo valor, todas as chaves entram no mesmo intervalo de hash. Como não há motivo para assumir complexidade adicional ao preencher um hash bucket, a ordem de inserção faz mais sentido.

Peguei sua mesma tabela de amostra e dados e executei 30 se INSERTobtive o seguinte:

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>

Decidi testar adicionando dois valores diferentes para k: 10 e 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>

Parece ordem de inserção. k = 11 foi o primeiro hash da chave, em seguida, 10. Que tal inserir 10 primeiro em vez de 11? Isto é o que eu tenho:

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>

É unânime !!! ORDEM DE INSERÇÃO é a resposta.

Notas de rosto sobre o uso de índices para o mecanismo de armazenamento MEMORY

As pesquisas por intervalo de MEMORY teriam um desempenho comparativamente horrível.

Ao criar um índice, você pode especificar a USING BTREEcláusula junto com a definição do índice. Isso melhoraria as coisas para consultas de intervalo.

Procurar uma linha específica produzirá o mesmo resultado no desempenho com HASHou BTREE.

ATUALIZAÇÃO 22-09-2011 11:18 EDT

Eu aprendi algo interessante hoje. Eu li o link fornecido por @Laurynas Biveinis da Percona: O link Percona diz algo sobre as tabelas MEMORY para MySQL 5.5.15 :

Ordenação de linhas

Na ausência de ORDER BY, os registros podem ser retornados em uma ordem diferente da implementação anterior de MEMORY. Isso não é um bug. Qualquer aplicativo que confie em um pedido específico sem uma cláusula ORDER BY pode fornecer resultados inesperados. Uma ordem específica sem ORDER BY é um efeito colateral da implementação de um mecanismo de armazenamento e otimizador de consultas que pode e irá mudar entre versões menores do MySQL.

Este foi um bom link para eu ver hoje. A resposta que eu dei demonstrou que a tabela que eu carregava foi recuperada na ordem que eu esperava HOJE no MySQL 5.5.12. Como apontado por Percona e @Laurynas Biveinis , não há garantia em outro lançamento menor.

Portanto, em vez de tentar defender minha resposta, prefiro promover a resposta de @Laurynas Biveinis porque é a informação mais atual. Parabéns e elogios para @Laurynas Biveinis . Também gostaria de agradecer à @eevar por educadamente apontar para não promover respostas específicas a versões para perguntas. Ambos recebem meu voto hoje.

RolandoMySQLDBA
fonte