Як функція 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 |
+----+---------+ 

щось подібне до того, щоб сказати ЗАМОВИТИ 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Дерево виразів). В JOIN::prepare, *orderвикористовується у функції під назвою setup_order(). Чому в середині JOINкласу? Кожен запит, навіть запит до однієї таблиці завжди обробляється як ПРИЄДНАЙТЕСЬ (Дивіться мій пост. Чи є різниця у виконанні між умовою JOIN та умовою WHERE? )

Вихідний код для всього цього є sql/sql_select.cc

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


1
Це надзвичайно чудове пояснення. Використовуючи ці методи, я зміг отримати 3 замовлення, основне перше значення, яке є максимумом набору, потім FIELD, потім іншим стовпцем для тих, які не є у наборі FIELD. Те, про що я б і не мріяв. Дякуємо, що знайшли час, щоб справді пояснити, як це насправді працює.
Лізардкс

Припустимо, що є 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 у програму "filesort" з інформацією, по якій стовпцю сортувати. Після цього рядки впорядковуються впорядкованому порядку, щоб він міг вибрати їх один за одним і повернути вибрані стовпці.


Це пояснення не враховує FIELDфункціонування в обчисленні. Боюся, що це може суттєво вплинути на продуктивність.
Герман

@Gherman Я не думаю, що якщо ви не використовуєте дуже довгий список аргументів (оскільки функція лінійна за кількістю аргументів . Доступ до даних на порядок
менший,

Так, довгий список аргументів. В цьому прикладі є стільки аргументів, скільки є записів.
Герман

Я б
мітлю

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