2016-10-19 5 views
0

У меня есть хранимая процедура, которая принимает несколько аргументов. Мне нужно вернуть результат, отсортированный в определенном порядке, в зависимости от значений аргументов, которые я получаю в качестве ввода. Проблема, с которой я столкнулся, если я попытаюсь написать один запрос с блоком 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 и какие его плюсы и минусы?

+0

Нет, нет другого способа написать отдельные запросы там (или, по крайней мере, индивидуальные окончания, если вы сделаете это в php или динамическом sql). Я не думаю, что это выглядело бы более уродливым или нечитаемым, чем ваш текущий запрос. И дело не только в том, что ваш запрос не может использовать индексы и будет упорядочиваться по 2 столбцам вместо 1 (хотя 1 из них будет константой 'null', mysql все равно придется сортировать по нему), ваше условие' order by' будет оценивается для каждой строки, даже если она выглядит квазипостоянной. – Solarflare

+0

Скажите 'NOT NULL', где это уместно. Имейте явный «ПЕРВЫЙ КЛЮЧ». Используйте 'INDEX (f1, f2)'. Но, если ваш SELECT не является _real_ select, этот совет может оказаться бесполезным. –

+0

Предположительно, вы имели в виду 'когда @a = 2' ?? (Я сделал это изменение.) –

ответ

0

Лучшим способом обработки вариаций в SELECT является динамическое построение запроса в коде приложения.

Общим примером является то, когда конечный пользователь может указать (или нет) различные вещи. Приложение может создать предложение WHERE с указанными вещами. Он может даже построить статьи IN или BETWEEN и т. Д. В соответствии с пользовательскими вводами.

Ваш случай имеет отношение к ORDER BY. Опять же, код приложения может легко построить желаемый ORDER BY. Это приведет к эффективному запросу.

Увы, в SQL не существует конструкции для замены этого.