it-swarm.it

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

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

Durante l'emissione di select * from t where k = 10 senza order by clausola, in che modo MySQL ordina i record per impostazione predefinita?

76
daisy

Ripubblicazione 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 intendi fare affidamento su questo ordine per qualsiasi cosa, devi specificare l'ordine desiderato usando ORDER BY. Fare qualsiasi altra cosa è prepararsi a sorprese indesiderate.

Questa è una proprietà di tutti gli SQL, non solo di MySQL. Il testo rilevante nella specifica 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.

87
Nick Chammas

L'ordine delle righe in assenza di ORDER BY la clausola 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.
29

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.

11
James Pulley

Quando si tratta del motore di archiviazione MEMORY , mi aspetto che l'ordine sia nell'ordine di inserimento perché l'indice predefinito il layout è HASH invece di BTREE e non viene utilizzato nessuno degli aspetti del layout dell'indice. Dato che hai indicizzato k, e k ha lo stesso valore, tutte le chiavi inseriscono il bucket hash stesso . 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 e ho eseguito 30 INSERTs 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.

Sidenotes sull'uso 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 USING BTREE clausola insieme alla definizione dell'indice. Ciò migliorerebbe le cose per le query sulla gamma.

La ricerca di una riga specifica produce lo stesso risultato nelle prestazioni con HASH o BTREE.

AGGIORNAMENTO 2011-09-22 11:18 EDT

Ho imparato qualcosa di interessante oggi. Ho letto il link fornito da @ Laurynas Biveinis da 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 da @ Laurynas Biveinis perché sono le informazioni più aggiornate. Complimenti e cappello fuori 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.

5
RolandoMySQLDBA