Який порядок записів за замовчуванням для оператора SELECT в MySQL?


66

Припустимо, у вас є така таблиця та дані:

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

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

Як видавати select * from t where k = 10без order byзастережень, як MySQL сортує записи за замовчуванням?

Відповіді:


75

Повторюючи свою відповідь на аналогічне запитання щодо SQL Server:

У світі SQL порядок не є притаманною властивістю набору даних. Таким чином, ви не отримуєте жодних гарантій від RDBMS, що ваші дані повернуться в певному порядку - або навіть у послідовному порядку - якщо ви не запитаєте свої дані за допомогою порядку ЗАМОВЛЕННЯ.

Отже, щоб відповісти на ваше запитання:

  • MySQL сортує записи, проте бажані, без гарантій послідовності.
  • Якщо ви плануєте покластися на це замовлення будь-що, ви повинні вказати бажане замовлення, використовуючи ORDER BY. Робити що-небудь інше - це налаштувати себе на непрошені сюрпризи.

Це властивість усіх SQL, а не тільки MySQL. Відповідний текст у специфікації SQL-92 :

Якщо <порядок за пунктом> не вказаний, то впорядкування рядків Q залежить від реалізації.

У специфікації для курсорів є аналогічні шматочки тексту.


26

Порядок рядків за відсутності ORDER BYпункту може бути:

  • різний між будь-якими двома двигунами зберігання;
  • якщо ви використовуєте один і той же механізм зберігання даних, він може відрізнятися між будь-якими двома версіями одного і того ж двигуна зберігання; Наприклад , прокрутіть униз до "Впорядкування рядків".
  • якщо версія двигуна зберігання однакова, але версія MySQL інша, вона може бути різною через зміни оптимізатора запитів між цими версіями;
  • якщо все те саме, це може бути різним через фазу місяця, і це нормально.

10

Вставлення не впорядковано, хаотично, після прибуття. Індекс, який створюється, має порядок, коли елементи вставляються у правильне розташування у пов'язаному списку, який є індексом. Придумайте потрійно зв'язаний список для індексу, де у вас є пряме рухоме посилання від одного елемента індексу до іншого, зворотнє посилання для цілей переходу та цілісності, а потім набір покажчиків на фактичні записи в таблиці, які збігаються з індексованим елементом.

Фактичні дані, хаотичні у зберіганні. Індекс, пов'язаний з даними, упорядкований для зберігання та побудови. Фактичний витяг даних, упорядкований чи не упорядкований, залежить від запиту.


4

Що стосується двигуна пам’яті MEMORY , я б очікував, що порядок буде в порядку вставки, оскільки HASHзамість цього макет індексу є замість, BTREEі жоден аспект макета індексу не використовується. Оскільки ви індексували k, і k - це одне і те ж значення, всі ключі вводять одне і те ж хеш-відро. Оскільки немає причин вважати додаткові складності для заповнення хеш-відра, порядок вставки має найбільш сенс.

Я взяв ту саму вибіркову таблицю та дані і пробіг 30 INSERTс, і я отримав це:

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>

Я вирішив перевірити, додавши два різних значення для k: 10 та 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>

Схоже на порядок вставки. k = 11 було першим хешеваним ключем, то 10. Що робити вставлення 10 спочатку замість 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.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>

Це одностайно !!! ПОРЯДОК ВСТАВКИ - це відповідь.

Бачить використання індексів для двигуна пам'яті MEMORY

Пошук за діапазоном MEMORY мав би порівняно жахливі показники.

Створюючи індекс, ви можете вказати USING BTREEпункт разом із визначенням індексу. Це покращило б питання для діапазону запитів.

Пошук конкретного рядка дасть однаковий результат у продуктивності з будь-яким HASHабо BTREE.

ОНОВЛЕННЯ 2011-09-22 11:18 EDT

Я дізнався щось цікаве сьогодні. Я читаю посилання, яке надає @Laurynas Biveinis з Percona: Посилання Percona говорить щось про таблиці MEMORY для MySQL 5.5.15 :

Впорядкування рядків

У разі відсутності ORDER BY, записи можуть бути повернуті в іншому порядку, ніж попереднє виконання MEMORY. Це не помилка. Будь-яка програма, що покладається на певне замовлення без пункту ЗАМОВЛЕННЯ ПО БУДЬ, може дати неочікувані результати. Конкретне замовлення без ORDER BY - це побічний ефект реалізації механізму зберігання даних та оптимізатора запитів, який може і змінюватись між незначними випусками MySQL.

Це було гарним посиланням для мене сьогодні. Відповідь, яку я дав, продемонструвала, що завантажену я таблицю була отримана для того, щоб я очікував, що сьогодні в MySQL 5.5.12. Як тільки вказували Перкона та @Laurynas Biveinis , жодної гарантії в другому незначному звільненні немає.

Отже, замість того, щоб намагатися захистити свою відповідь, я б краще просувати відповідь від @Laurynas Biveinis, тому що це найновіша інформація. Кудо і шапки зняті для @Laurynas Biveinis . Я також хотів би подякувати @eevar за ввічливий вказівку на те, щоб не поширювати відповіді на запитання, що стосуються версії. Вони обидва сьогодні отримують мою підсумку.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.