Я хочу получить две строки из моей таблицы в базе данных MySQL. эти две строки должны быть первой и последней после того, как я их заказал. Для этого я сделал два запроса, эти два:

SELECT dateBegin, dateTimeBegin FROM worktime ORDER BY dateTimeBegin ASC LIMIT 1;";
SELECT dateBegin, dateTimeBegin FROM worktime ORDER BY dateTimeBegin DESC LIMIT 1;";

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

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

Любая помощь высоко ценится.

2
JRsz 4 Янв 2016 в 23:34

2 ответа

Лучший ответ

(Это и «ответ», и опровержение ошибок в некоторых комментариях.)

INDEX(dateTimeBegin)

Облегчит SELECT ... ORDER BY dateTimeBegin ASC LIMIT 1 и соответствующую строку с другого конца, используя DESC.

MAX(dateTimeBegin) найдет только максимальное значение для этого столбца; он не напрямую найдет остальные столбцы в этой строке. Для этого потребуется подзапрос или JOIN.

INDEX(... DESC) - DESC игнорируется MySQL. Это почти никогда не бывает недостатком, так как оптимизатор хочет пройти через индекс в любом направлении. Дело в том, что ORDER BY x ASC, y DESC нельзя использовать ни INDEX(x, y), ни INDEX(x ASC, y DESC). Это недостаток MySQL. (В остальном я согласен с «ответом» Гордона.)

( SELECT ... ASC )
UNION ALL
( SELECT ... DESC )

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

Практически всегда лучше иметь одно поле DATETIME (или TIMESTAMP), чем разделять DATE и / или TIME. SELECT DATE(dateTimeBegin), dateTimeBegin ... работает просто, и «достаточно быстро». См. Также функцию DATE_FORMAT(). Я рекомендую убрать столбец dateBegin и соответствующим образом скорректировать код. Обратите внимание, что сжатие таблицы может фактически ускорить обработку больше, чем затраты на DATE(). (Разница будет бесконечно малой.)

Без индекса, начинающегося с dateTimeBegin, любой из методов был бы медленным и становился все медленнее по мере увеличения размера таблицы. (Я почти уверен, что он может найти оба MIN() и MAX() всего за один полный проход и сделать это без сортировки. Пара ORDER BYs могла бы возьмите два полных прохода плюс две сортировки; 5.6 может иметь оптимизацию, которая почти исключает сортировки.)

Если есть две строки с одинаковым min dateTimeBegin, то какой из них вы получите, будет непредсказуемо.

2
Rick James 5 Янв 2016 в 00:12

Ваши запросы в порядке. Вам нужен указатель на worktime(dateTimeBegin). MySQL должен быть достаточно умен, чтобы использовать этот индекс как для сортировки ASC, так и для DESC. Если вы его протестируете, а это не так, вам понадобятся два индекса: worktime(dateTimeBegin asc) и worktime(dateTimeBegin desc).

Независимо от того, запускаете ли вы один или два запроса. Один запрос (связанный с помощью UNION ALL) немного более эффективен, потому что у вас есть только одно обращение к базе данных. Однако два могут легче вписаться в ваш код, и разница в производительности для большинства целей не имеет значения.

2
Gordon Linoff 4 Янв 2016 в 20:42