Каков порядок записей по умолчанию для оператора 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 порядок не является неотъемлемым свойством набора данных. Таким образом, вы не получите от вашей СУБД гарантии того, что ваши данные будут возвращаться в определенном порядке - или даже в согласованном порядке - если вы не запросите свои данные с помощью предложения ORDER BY.

Итак, чтобы ответить на ваш вопрос:

  • MySQL сортирует записи по своему усмотрению без какой-либо гарантии согласованности.
  • Если вы намерены полагаться на этот заказ в любом случае, вы должны указать желаемый заказ, используя ORDER BY. Делать что-либо еще - значит настраивать себя на неприятные сюрпризы.

Это свойство всего SQL, а не только MySQL. Соответствующий текст в спецификации SQL-92 :

Если <order by предложение> не указано, то порядок строк 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

Поиск диапазона для ПАМЯТИ имел бы сравнительно ужасную производительность.

При создании индекса вы можете указать USING BTREEпредложение вместе с определением индекса. Это улучшит вещи для запросов диапазона.

Поиск определенной строки даст тот же результат в производительности с либо HASHили BTREE.

ОБНОВЛЕНИЕ 2011-09-22 11:18 ПО ВОСТОЧНОМУ ВРЕМЕНИ

Я узнал кое-что интересное сегодня. Я прочитал ссылку, предоставленную @Laurynas Biveinis из Percona : ссылка Percona что-то говорит о таблицах MEMORY для MySQL 5.5.15 :

Упорядочение рядов

В отсутствие ORDER BY записи могут быть возвращены в другом порядке, чем предыдущая реализация MEMORY. Это не ошибка. Любое приложение, использующее конкретный заказ без предложения ORDER BY, может дать неожиданные результаты. Конкретный порядок без ORDER BY является побочным эффектом реализации механизма хранения и оптимизатора запросов, который может меняться и будет меняться между небольшими выпусками MySQL.

Это была хорошая ссылка для меня, чтобы увидеть сегодня. Ответ, который я дал, продемонстрировал, что загруженная таблица была получена в том порядке, в котором я ожидал СЕГОДНЯ в MySQL 5.5.12. Как только что указали Percona и @Laurynas Biveinis , нет никаких гарантий в другом небольшом выпуске.

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

RolandoMySQLDBA
источник