it-swarm.dev

Jaka jest domyślna kolejność rekordów dla instrukcji SELECT w MySQL?

Załóżmy, że masz następującą tabelę i dane:

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

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

Wydając select * from t where k = 10 z nie order by klauzula, w jaki sposób MySQL domyślnie sortuje rekordy?

76
daisy

Przekazanie moja odpowiedź na podobne pytanie dotyczące programu SQL Server:

W świecie SQL porządek nie jest nieodłączną właściwością zestawu danych. W ten sposób nie otrzymujesz żadnych gwarancji z RDBMS, że twoje dane wrócą w określonej kolejności - lub nawet w spójnej kolejności - chyba że zapytasz o swoje dane klauzulą ​​ORDER BY.

Tak więc, aby odpowiedzieć na twoje pytanie:

  • MySQL sortuje rekordy, jak chce, bez żadnej gwarancji spójności.
  • Jeśli zamierzasz cokolwiek polegać na tym zamówieniu, musisz określić żądane zamówienie za pomocą ORDER BY. Robienie czegokolwiek innego to przygotowywanie się na niepożądane niespodzianki.

Jest to właściwość całego SQL, nie tylko MySQL. Odpowiedni tekst w specyfikacja SQL-92 to:

Jeśli nie podano <kolejność według klauzuli>, kolejność wierszy Q zależy od implementacji.

W specyfikacji kursorów znajdują się podobne fragmenty tekstu.

87
Nick Chammas

Kolejność wierszy przy braku ORDER BY klauzula może być:

  • różni się między dowolnymi dwoma silnikami pamięci;
  • jeśli używasz tego samego silnika pamięci masowej, może on różnić się między dowolnymi dwoma wersjami tego samego silnika pamięci masowej; Przykład tutaj , przewiń w dół do „Zamawianie rzędów”.
  • jeśli wersja silnika pamięci jest taka sama, ale wersja MySQL jest inna, może być inna z powodu zmian optymalizatora zapytań między tymi wersjami;
  • jeśli wszystko jest takie samo, może być inaczej z powodu fazy księżyca i to jest OK.
29

Wstawienie jest nieuporządkowane, chaotyczne, po przyjeździe. Utworzony indeks ma kolejność, w której elementy są wstawiane w odpowiedniej lokalizacji na połączonej liście, która jest indeksem. Pomyśl o potrójnie połączonej liście indeksu, w której masz ruchome łącze do przodu z jednego elementu indeksu do następnego, link do tyłu do celów przejścia i integralności, a następnie zestaw wskaźników do rzeczywistych rekordów w tabeli, które dopasuj indeksowany element, o którym mowa.

Rzeczywiste dane, chaotycznie w pamięci. Indeks powiązany z danymi, uporządkowany w pamięci i konstrukcji. Rzeczywiste pobieranie danych, uporządkowane lub nieuporządkowane, zależy od danego zapytania.

11
James Pulley

Jeśli chodzi o silnik pamięci MEMORY , oczekiwałbym, że kolejność będzie zgodna z kolejnością wstawianie, ponieważ domyślny układ indeksu to HASH zamiast BTREE i żaden aspekt układu indeksu nie jest używany. Ponieważ zaindeksowałeś k, a k jest tej samej wartości, wszystkie klucze wpisują to samo wiadro mieszające. Ponieważ nie ma powodu, aby zakładać dodatkową złożoność wypełniania segmentu mieszania, kolejność wstawiania jest najbardziej sensowna.

Wziąłem twoją przykładową tabelę i dane i uruchomiłem 30 INSERTs i otrzymałem to:

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>

Postanowiłem przetestować, dodając dwie różne wartości dla k: 10 i 11. Otrzymałem to:

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>

Wygląda na kolejność wstawiania. k = 11 to był pierwszy klucz zaszyfrowany, a następnie 10. Co powiesz na wstawienie 10 zamiast 11? Oto co mam:

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>

To jednogłośne !!! ZAMÓWIENIE WSTAWIANIA jest odpowiedzią.

Sidenotes na temat używania indeksów dla silnika pamięci MEMORY

Wyszukiwania MEMORY w zakresie zakresu miałyby porównywalnie przerażającą skuteczność.

Podczas tworzenia indeksu można określić USING BTREE klauzula wraz z definicją indeksu. Poprawiłoby to zakres zapytań o zakres.

Wyszukiwanie określonego wiersza da ten sam wynik pod względem wydajności z HASH lub BTREE.

AKTUALIZACJA 22.09.2011 11:18 EDT

Nauczyłem się dziś czegoś ciekawego. Czytam link podany przez @ Laurynas Biveinis z Percona: Link Percona mówi coś o tabelach MEMORY dla MySQL 5.5.15:

Zamawianie rzędów

W przypadku braku ORDER BY rekordy mogą zostać zwrócone w innej kolejności niż poprzednia implementacja MEMORY. To nie jest błąd. Każda aplikacja oparta na konkretnym zamówieniu bez klauzuli ORDER BY może dawać nieoczekiwane wyniki. Konkretne zamówienie bez ORDER BY jest efektem ubocznym implementacji silnika pamięci i implementacji optymalizatora zapytań, który może i będzie się zmieniać między mniejszymi wersjami MySQL.

To był dla mnie dobry link do zobaczenia dzisiaj. Udzielona przeze mnie odpowiedź wykazała, że ​​tabela, którą załadowałem, została pobrana w kolejności, której oczekiwałem DZIŚ w MySQL 5.5.12. Jak właśnie wskazali Percona i @ Laurynas Biveinis , nie ma gwarancji w innym mniejszym wydaniu.

Zamiast więc bronić mojej odpowiedzi, wolę promować odpowiedź od @ Laurynas Biveinis , ponieważ jest to najbardziej aktualna informacja. Wyrazy uznania i czapki z głów dla @ Laurynas Biveinis . Chciałbym również podziękować @ eevar za grzeczne zwrócenie uwagi na nie promowanie odpowiedzi na pytania dotyczące konkretnych wersji. Obaj otrzymali dziś moje poparcie.

5
RolandoMySQLDBA