MySQL → Как MySQL оптимизирует ORDER BY, LIMIT и DISTINCT

Предположим, имеется некоторые сущности А и Б, связанные между собой по принципу One-to-Many. Количество экземпляров данных сущностей достаточно велико. При отображении сущностей для пользователя необходимо применить ряд независимых критериев, как для сущности А так и для сущности Б. Причем результатом применения критериев являются множества достаточно большой мощности — порядка нескольких миллионов записей. Критерии фильтрации и принцип сортировки задается пользователем. Как (я бы ещё спросил: Зачем им миллионы записей на одном экране? — но говорят надо) показать все это пользователю за время 0 секунд?
Решать такие задачи всегда интересно, но их решение сильно зависит от СУБД, под управлением которой крутится твоя база данных. Если у тебя в рукаве козырной туз в виде Oracle, то есть шанс, что эти костыли он подставит сам. Но спустимся на землю — у нас есть только MySQL, так что придется почитать теорию.
MySQL → Задача на сортировку
Персональные блоги → MySQL rownum
Постановка задачи
Есть таблица меню в БД с полем порядка order_id, но порядок неправильный и надо порядок обновить по алфавиту другого поля title. Сортировка по полю title исключается, потому что таблица представляет из себя иерархическое меню, где порядок может менять пользователь устанавливая order_id. Использовать отдельно серверную обработку (php) тоже невыгодно - лишнее разделение бизнес логики если это можно сделать в БД, да и на случай больших объемов данных это займёт больше ресурсов.
Решение
В MySQL к сожалению отсутсвует такая возможность ROWNUM, RANK(), ROW_NUMBER() как в ORACLE или MSSQL. Присутсвие _rowid никак не влияет на ситуацию. В нашем случае можно использовать переменные, введённые с пятой версии (или раньше):
SET @rank=0;
SELECT @rank:=@rank+1 AS rank, id FROM menu;
Для обновления такой таблицы через саму себя у меня не получилось, поэтому я просто скопировал таблицу под другим именем и выполнил такой запрос:
SET @rank=0;
UPDATE `menu` SET order_id=(
SELECT @rank:=@rank+1 FROM `menu2` WHERE `menu`.id=`menu2`.id LIMIT 1
) WHERE parentID=0 ORDER BY `title` ASC;
Оригинал