У меня есть хранимая процедура, которая принимает несколько аргументов. Мне нужно вернуть результат, отсортированный в определенном порядке, в зависимости от значений аргументов, которые я получаю в качестве ввода. Проблема, с которой я столкнулся, если я попытаюсь написать один запрос с блоком case-case в порядке по запросу, запрос не будет использовать какой-либо индекс. Структура образца приведена нижеMySql: как обрабатывать условную сортировку
create table test_table(
f1 int,
f2 int,
f3 int,
key (f1),
key(f2)
);
-- now insert 2M rows in the table
-- query #1
mysql> explain select f1, f2 from test_table order by f1 desc limit 1000;
+----+-------------+------------+-------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | test_table | index | NULL | f1 | 5 | NULL | 1000 | NULL |
+----+-------------+------------+-------+---------------+------+---------+------+------+-------+
1 row in set (0.00 sec)
-- query #2
mysql> explain select f1, f2 from test_table order by f2 desc limit 1000;
+----+-------------+------------+-------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | test_table | index | NULL | f2 | 5 | NULL | 1000 | NULL |
+----+-------------+------------+-------+---------------+------+---------+------+------+-------+
1 row in set (0.00 sec)
set @a = 1, @b = 'd';
--query #3
mysql> explain select f1, f2 from test_table
order by
case when @a = 1 and @b = 'd' then f1
when @a = 2 and @b = 'd' then f2 end desc,
case when @a = 1 and @b = 'a' then f1
when @a = 2 and @b = 'a' then f2 end asc
limit 1000;
+----+-------------+------------+------+---------------+------+---------+------+---------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+---------+----------------+
| 1 | SIMPLE | test_table | ALL | NULL | NULL | NULL | NULL | 1995435 | Using filesort |
+----+-------------+------------+------+---------------+------+---------+------+---------+----------------+
1 row in set (0.00 sec)
Если вы видите запрос 1 или запрос 2, то выходы объяснения ожидаются. Но когда я пытаюсь решить столбец сортировки во время выполнения, он не может использовать какой-либо из индексов. Одна из альтернатив к достижению №3 будет записывать блоки if-else и писать отдельные запросы там, но она будет уродливой, если есть несколько возможностей. В приведенном выше примере это приведет к 4 подобным блокам с разным порядком в соответствии с разделом
Мой вопрос: Есть ли альтернативный способ получить запрос № 3 и какие его плюсы и минусы?
Нет, нет другого способа написать отдельные запросы там (или, по крайней мере, индивидуальные окончания, если вы сделаете это в php или динамическом sql). Я не думаю, что это выглядело бы более уродливым или нечитаемым, чем ваш текущий запрос. И дело не только в том, что ваш запрос не может использовать индексы и будет упорядочиваться по 2 столбцам вместо 1 (хотя 1 из них будет константой 'null', mysql все равно придется сортировать по нему), ваше условие' order by' будет оценивается для каждой строки, даже если она выглядит квазипостоянной. – Solarflare
Скажите 'NOT NULL', где это уместно. Имейте явный «ПЕРВЫЙ КЛЮЧ». Используйте 'INDEX (f1, f2)'. Но, если ваш SELECT не является _real_ select, этот совет может оказаться бесполезным. –
Предположительно, вы имели в виду 'когда @a = 2' ?? (Я сделал это изменение.) –