Как MySQL обрабатывает ORDER BY и LIMIT в запросе?


251

У меня есть запрос, который выглядит так:

SELECT article FROM table1 ORDER BY publish_date LIMIT 20

Как работает ORDER BY? Будет ли он упорядочить все записи, затем получить первые 20 или 20 записей и упорядочить их по publish_dateполю?

Если это последний, вы не гарантированно получите последние 20 статей.


6
Обратите внимание, что если некоторые publish_dates одинаковы, их упорядочение не дает определенных результатов, а это означает, что если вы используете LIMITнумерацию страниц, вы можете получить одинаковые элементы на разных страницах!
Конрад Моравский

Ответы:


245

Сначала он закажет, затем получит первые 20. База данных также обработает все, что в WHEREпредложении ранее ORDER BY.


1
Значит, сроки одинаковы?
Ясар Арафат

7
Неправильно! LIMITперерывы ORDER BY. С LIMITв ORDER BYрезультате возвращает неправильный. LIMITкаким-то образом переупорядочивает набор результатов, возвращенныйORDER BY
Green

6
@ Green, ты ошибаешься. Прочитайте это для объяснения: dev.mysql.com/doc/refman/5.7/en/limit-optimization.html Когда столбец ORDER BY проиндексирован, он может возвращать записи в другом порядке, чем без LIMIT, когда есть больше чем 1 записи с одинаковым значением в этом столбце.
Yitwail

1
Одним из быстрых решений таких проблем является добавление еще одного столбца к порядку, предпочтительно с уникальными значениями, чтобы база данных получала согласованное правило для упорядочивания строк, когда значение первого порядка по столбцам одинаково для нескольких строк.
rineez

37

Предложение LIMIT может использоваться для ограничения количества строк, возвращаемых оператором SELECT. LIMIT принимает один или два числовых аргумента, которые должны быть неотрицательными целочисленными константами (кроме случаев использования подготовленных операторов).

С двумя аргументами первый аргумент задает смещение первой строки для возврата, а второй задает максимальное количество строк для возврата. Смещение начальной строки равно 0 (не 1):

SELECT * FROM tbl LIMIT 5,10; # Retrieve rows 6-15

Чтобы извлечь все строки от определенного смещения до конца результирующего набора, вы можете использовать некоторое большое число для второго параметра. Этот оператор извлекает все строки от 96-й строки до последней:

SELECT * FROM tbl LIMIT 95,18446744073709551615;

С одним аргументом значение указывает количество строк, возвращаемых из начала набора результатов:

SELECT * FROM tbl LIMIT 5; # Retrieve first 5 rows

Другими словами, LIMIT row_count эквивалентно LIMIT 0, row_count.

Все подробности на: http://dev.mysql.com/doc/refman/5.0/en/select.html


Разве это не восстановить строки 5-14?
Адонис К. Какулидис

@adonis Нет, это не так. Пример прямо из документации
dcaswell

№ 5 - 6-й ряд. 5 строк (от 0 до 4) игнорируются.
Фил Перри

1
Но использование LIMIT без ORDER BY может привести к противоречивым результатам! К сожалению, весь набор результатов должен быть упорядочен до применения LIMIT, или СУБД может произвольно упорядочить результат, а затем OFFSET и LIMIT для этого набора. Я читал, что это может быть связано с тем, что СУБД выбрала альтернативный план запроса на основе OFFSET и LIMIT, таким образом, в произвольном порядке.
Бартон

4
вопрос задает лимит и порядок по. Но ответ на этот вопрос не имеет
Шен Лян,

9

Как говорит @James, он упорядочит все записи, а затем получит первые 20 строк.

Так как это так, вы гарантированно получите 20 первых опубликованных статей, более новые не будут показаны.

В вашей ситуации я рекомендую добавить descк order by publish_date, если вы хотите , то самые новые статьи, то новейшая статья будет первой.

Если вам нужно сохранить результат в порядке возрастания, и при этом вам нужны только 10 самых новых статей, вы можете попросить mysql отсортировать результаты два раза.

Приведенный ниже запрос сортирует результат по убыванию и ограничивает результат 10 (это запрос в скобках). Он все равно будет отсортирован в порядке убывания, и мы не удовлетворены этим, поэтому мы просим mysql отсортировать его еще раз. Теперь у нас самый новый результат в последнем ряду.

select t.article 
from 
    (select article, publish_date 
     from table1
     order by publish_date desc limit 10) t 

order by t.publish_date asc;

Если вам нужны все столбцы, это делается так:

select t.* 
from 
    (select * 
     from table1  
     order by publish_date desc limit 10) t 

order by t.publish_date asc;

Я использую эту технику, когда пишу запросы вручную, чтобы исследовать базу данных на предмет различных вещей. Я не использовал его в производственной среде, но теперь, когда я его отмечал, дополнительная сортировка не влияет на производительность.


2
Ваша дополнительная сортировка может практически не оказывать какого-либо измеримого влияния на производительность, поскольку она ограничена только 10 строками / элементами :-). В общем случае сортировка таблицы в памяти (которую производит подвыбор) выполняется очень быстро и едва поддается измерению, если только у вас нет миллионов строк или если СУБД не подает страницу с набором результатов на диск, поскольку она не умещается в памяти (в этом случае в зависимости от СУБД также может прервать запрос).
Мартин Керстен,

7

Если имеется подходящий индекс, в данном случае на publish_dateполе, MySQL не нужно сканировать весь индекс, чтобы получить 20 запрошенных записей - 20 записей будут найдены в начале индекса. Но если подходящего индекса нет, потребуется полное сканирование таблицы.

Об этом есть статья в MySQL Performance Blog за 2009 год.


7

Вы можете добавить [asc] или [desc] в конце заказа, чтобы получить самые ранние или последние записи

Например, это даст вам последние записи в первую очередь

ORDER BY stamp DESC

Добавить LIMITпункт послеORDER BY


3
Добро пожаловать в stackoverflow. Я думаю, что вы, возможно, неправильно поняли вопрос. Я считаю, что они спрашивали о порядке операций, а не о том, «как сортировать». (Но это спорный вопрос, поскольку на этот вопрос уже был дан ответ;)
Ли

5

Вы можете использовать этот код, SELECT article FROM table1 ORDER BY publish_date LIMIT 0,10 где 0 - начальный предел записи и 10 номеров записи.


8
Нет, это не обязательно . LIMIT 10это сокращение для LIMIT 0,10.
Лоуренс Дол

2
да, не требуется для LIMIT 0,10, но вы можете требовать Like This Limit 10,20
gaurangkathiriya

3

LIMIT обычно применяется в качестве последней операции, поэтому результат будет сначала отсортирован, а затем ограничен 20. Фактически сортировка остановится, как только будут найдены первые 20 отсортированных результатов.


11
Ваше второе предложение идет вразрез с вашим первым. Сортировка не может быть остановлена, когда найдены первые 20 результатов, потому что, как вы сказали, сортировка будет выполнена до того, как результаты будут возвращены. MySQL может знать только, каковы первые 20 результатов после завершения сортировки.
Том

@ На самом деле это возможно, если упорядочить по индексируемому столбцу. Это объясняется здесь: dev.mysql.com/doc/refman/5.7/en/limit-optimization.html
yitwail

-3

Также синтаксис LIMIT отличается в зависимости от базы данных, например:

mysql - ПРЕДЕЛ 1, 2

postgres - ПРЕДЕЛ 2 ОФСЕТ 1

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