Как ORDER BY FIELD () в MySQL работает внутренне


37

Я понимаю, как ORDER BYработает пункт и как FIELD()работает функция. Что я хочу понять, так это то, как они оба работают вместе для сортировки. Как извлекаются строки и как получается порядок сортировки

+----+---------+
| id |  name   |
+----+---------+
|  1 | stan    |
|  2 | kyle    |
|  3 | kenny   |
|  4 | cartman |
+----+---------+ 

SELECT * FROM mytable WHERE id IN (3,2,1,4) ORDER BY FIELD(id,3,2,1,4)

Приведенный выше запрос приведет к

+----+---------+
| id |  name   |
+----+---------+
|  3 | kenny   |
|  2 | kyle    |
|  1 | stan    |
|  4 | cartman |
+----+---------+ 

что-то похожее на поговорку ORDER BY 3, 2, 1, 4

ВОПРОСОВ

  • Как это работает внутри?
  • Как MySQL получает строки и вычисляет порядок сортировки?
  • Откуда MySQL знает, что он должен сортировать по столбцу id?

1
попробуйте этот вариант вашего запроса: SELECT *, FIELD(id,3,2,1,4) AS f FROM mytable WHERE id IN (3,2,1,4);затем добавьте ORDER BY fили ORDER BY FIELD(id,3,2,1,4)и попробуйте снова.
ypercubeᵀᴹ

Ответы:


64

Для записи

SELECT * FROM mytable WHERE id IN (1,2,3,4) ORDER BY FIELD(id,3,2,1,4);

должно работать так же, потому что вам не нужно упорядочивать список в WHEREпункте

Что касается того, как это работает,

  • FIELD () - это функция, которая возвращает позицию индекса в списке с разделителями-запятыми, если искомое значение существует.

    • Если id = 1, то FIELD (id, 3,2,1,4) возвращает 3 (позиция, где 1 находится в списке)
    • Если id = 2, то FIELD (id, 3,2,1,4) возвращает 2 (позиция, где 2 находится в списке)
    • Если id = 3, то FIELD (id, 3,2,1,4) возвращает 1 (позиция, где 3 находится в списке)
    • Если id = 4, то FIELD (id, 3,2,1,4) возвращает 4 (позиция, где 4 находится в списке)
    • Если id = что-то еще, то FIELD (id, 3,2,1,4) возвращает 0 (нет в списке)
  • Эти ORDER BYзначения вычисляются по какому полю () возвращает

Вы можете создавать всевозможные модные заказы

Например, используя функцию IF ()

SELECT * FROM mytable
WHERE id IN (1,2,3,4)
ORDER BY IF(FIELD(id,3,2,1,4)=0,1,0),FIELD(id,3,2,1,4);

Это приведет к тому, что первые 4 идентификатора появятся вверху списка, в противном случае он появится внизу. Зачем?

В ORDER BY, вы либо получите 0 или 1.

  • Если первый столбец равен 0, отобразить любой из первых 4 идентификаторов
  • Если первый столбец равен 1, сделайте его появившимся потом

Давайте перевернем это с DESC в первом столбце

SELECT * FROM mytable
WHERE id IN (1,2,3,4)
ORDER BY IF(FIELD(id,3,2,1,4)=0,1,0) DESC,FIELD(id,3,2,1,4);

В ORDER BY, вы все равно либо получите 0 или 1.

  • Если первый столбец равен 1, сделайте что угодно, кроме первых 4 идентификаторов.
  • Если первый столбец равен 0, первые 4 идентификатора отображаются в исходном порядке.

ВАШ АКТУАЛЬНЫЙ ВОПРОС

Если вы серьезно хотите узнать об этом, перейдите на страницы 189 и 192 Книги.

MySQL Internals

для настоящего глубокого погружения.

По сути, существует класс C ++, который называется ORDER *order( ORDER BYДерево выражений). In JOIN::prepare, *orderиспользуется в вызываемой функции setup_order(). Почему в середине JOINкласса? Каждый запрос, даже запрос к одной таблице, всегда обрабатывается как JOIN (см. Мой пост. Есть ли разница в выполнении между условием JOIN и условием WHERE? )

Исходный код для всего этого sql/sql_select.cc

Очевидно, ORDER BYдерево собирается провести оценку FIELD(id,3,2,1,4). Таким образом, числа 0,1,2,3,4 являются значениями, сортируемыми при переносе ссылки на соответствующую строку.


1
Это превосходное объяснение. Используя эти методы, я смог получить 3 заказа: первичное первое значение, которое является максимумом набора, затем полем, затем другим столбцом для тех, которые не входят в набор поля. Что-то, о чем я не мечтал некоторое время назад. Спасибо, что нашли время, чтобы действительно объяснить, как это на самом деле работает.
Lizardx

Предположим, что есть Nзначения в обоих INи FIELD. В этом примере N=4. Правильно ли я понимаю, что этот запрос будет выполнять хотя бы ~N^2операции. Потому что каждое FIELDвычисление делает ~Nсравнения один раз для каждой строки. Если так, то это довольно медленно для большого. NМожет быть, это не очень хороший подход?
Герман

@Gherman FIELD()Функция должна быть O(1)операцией, потому что FIELD()имеет числовой индекс id. Так что я не вижу ничего другого, кроме как O(n)на основе строк. Я не вижу FIELD()выполнения какой-либо итерационной операции, такой как GREATEST()необходимо.
RolandoMySQLDBA

@RolandoMySQLDBA Моя точка зрения заключается в том, что если FIELDесть Nаргументы для сравнения, то он выполнит Nсравнения. Как еще можно сравнить одно число с Nдругими числами, если не делать O(N)? Единственная возможность, о которой я могу думать, - это какая-то оптимизация с помощью специальной структуры данных, такой как хеш или дерево аргументов. На самом деле я знаю, что INимеет такую ​​оптимизацию. Я не знаю о FIELD. Что вы подразумеваете под «числовым индексом»?
Герман

1
Привет @RaymondNijland, оператор CASE более понятен. Для этого случая синтаксический сахар просто меньше пишет.
RolandoMySQLDBA

1

Возможно, это будет слишком далеко от реального кода, поэтому недостаточно низкоуровневый, чем вы хотели:

Когда MySQL не может использовать индекс для извлечения данных в отсортированном порядке, он создает временную таблицу / набор результатов со всеми выбранными столбцами и некоторыми дополнительными данными - один из них является своего рода столбцом для хранения результатов значения выражения ORDER BY для каждой строки - затем он отправляет эту таблицу tmp в процедуру «файловой сортировки» с информацией, по какому столбцу сортировать. После этого строки располагаются в отсортированном порядке, поэтому он может выбрать их одну за другой и вернуть выбранные столбцы.


Это объяснение не учитывает, как FIELDфункция вычисляется. Боюсь, это может оказать существенное влияние на производительность.
Герман

@ Герман Я так не думаю, если только вы не используете очень длинный список аргументов (поскольку функция линейна по количеству аргументов . Доступ к данным на порядок медленнее, чем при простом сравнении.
jkavalik

Да, длинный список аргументов. В этом примере столько аргументов, сколько записей.
Герман

Я бы
назвал

почему не сотни результатов? Это много?
Герман
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.