Qual è l'ordine predefinito dei record per un'istruzione SELECT in MySQL?


66

Supponiamo di avere la tabella e i dati seguenti:

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

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

Quando si emette select * from t where k = 10senza order byclausola, come fa MySQL a ordinare i record per impostazione predefinita?

Risposte:


75

Ripubblicando la mia risposta a una domanda simile riguardante SQL Server:

Nel mondo SQL, l'ordine non è una proprietà intrinseca di un insieme di dati. Pertanto, non ricevi alcuna garanzia dal tuo RDBMS che i tuoi dati torneranno in un certo ordine - o anche in un ordine coerente - a meno che tu non li interroghi con una clausola ORDER BY.

Quindi, per rispondere alla tua domanda:

  • MySQL ordina i record come desidera senza alcuna garanzia di coerenza.
  • Se si intende fare affidamento su questo ordine per qualsiasi cosa, è necessario specificare l'ordine desiderato utilizzando ORDER BY. Fare qualsiasi altra cosa è prepararsi a sorprese indesiderate.

Questa è una proprietà di tutti gli SQL, non solo di MySQL. Il testo rilevante nelle specifiche SQL-92 è:

Se non viene specificata una <clausola order by>, l'ordinamento delle righe di Q dipende dall'implementazione.

Ci sono parti di testo simili nelle specifiche per i cursori.


26

L'ordine delle righe in assenza di ORDER BYclausola può essere:

  • diverso tra due motori di memorizzazione qualsiasi;
  • se si utilizza lo stesso motore di archiviazione, potrebbe essere diverso tra due versioni dello stesso motore di archiviazione; Esempio qui , scorrere fino a "Ordine delle righe".
  • se la versione del motore di archiviazione è la stessa, ma la versione di MySQL è diversa, potrebbe essere diversa a causa delle modifiche di Query Optimizer tra quelle versioni;
  • se tutto è uguale, potrebbe essere diverso a causa della fase lunare e va bene.

10

L'inserimento non è ordinato, caotico, all'arrivo. L'indice creato ha un ordine in cui gli elementi vengono inseriti nella posizione corretta nell'elenco collegato che è l'indice. Pensa a un elenco triplicamente collegato per un indice, in cui hai un collegamento che si sposta in avanti da un elemento di indice al successivo, un collegamento che guarda indietro per gli scopi di attraversamento e integrità e quindi una serie di puntatori ai record effettivi nella tabella che corrisponde all'elemento indicizzato in questione.

Dati effettivi, caotici nell'archiviazione. Indice associato ai dati, ordinato in conservazione e costruzione. Il pull effettivo dei dati, ordinato o non ordinato, dipende dalla query in questione.


4

Quando si tratta del motore di archiviazione MEMORY , mi aspetto che l'ordine sia in base all'ordine di inserimento perché il layout dell'indice predefinito è HASHinvece BTREEe non viene utilizzato nessuno degli aspetti del layout dell'indice. Dato che hai indicizzato k, e k ha lo stesso valore, tutte le chiavi entrano nello stesso bucket hash. Poiché non vi è alcun motivo per supporre una maggiore complessità nel popolare un bucket hash, l'ordine di inserimento ha più senso.

Ho preso la tua stessa tabella di esempio e dati INSERTe ho eseguito 30 secondi e ho ottenuto questo:

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>

Ho deciso di provare aggiungendo due diversi valori per k: 10 e 11 Ho ottenuto questo:

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>

Sembra un ordine di inserimento. k = 11 è stata la prima chiave con hash poi 10. Che ne dici di inserire prima 10 anziché 11? Questo è quello che ho ottenuto:

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>

È unanime !!! L'ORDINE DI INSERIMENTO è la risposta.

Non indica l'utilizzo degli indici per il motore di archiviazione MEMORY

Le ricerche di portata per MEMORY avrebbero prestazioni relativamente orribili.

Quando si crea un indice, è possibile specificare la USING BTREEclausola insieme alla definizione dell'indice. Ciò migliorerebbe le cose per le query sulla gamma.

La ricerca di una riga specifica produrrà lo stesso risultato nelle prestazioni con HASHo BTREE.

AGGIORNAMENTO 2011-09-22 11:18 EDT

Ho imparato qualcosa di interessante oggi. Ho letto il link fornito da @Laurynas Biveinis di Percona: il link Percona dice qualcosa sulle tabelle MEMORY per MySQL 5.5.15 :

Ordine delle file

In assenza di ORDER BY, i record possono essere restituiti in un ordine diverso rispetto all'implementazione MEMORY precedente. Questo non è un bug. Qualsiasi applicazione basata su un ordine specifico senza una clausola ORDER BY può fornire risultati imprevisti. Un ordine specifico senza ORDER BY è un effetto collaterale di un motore di archiviazione e dell'implementazione di Query Optimizer che può e cambierà tra le versioni minori di MySQL.

Questo è stato un buon collegamento per me da vedere oggi. La risposta che ho dato ha dimostrato che la tabella che ho caricato è stata recuperata come mi aspettavo OGGI in MySQL 5.5.12. Come appena sottolineato da Percona e @Laurynas Biveinis , non vi è alcuna garanzia in un'altra versione minore.

Quindi, piuttosto che cercare di difendere la mia risposta, preferirei promuovere la risposta di @Laurynas Biveinis perché sono le informazioni più aggiornate. Complimenti e cappello per @Laurynas Biveinis . Vorrei anche ringraziare @eevar per aver cortesemente sottolineato di non promuovere risposte specifiche alla versione alle domande. Entrambi ottengono il mio voto oggi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.