2013-11-15 4 views
1

Я не могу понять, почему предложения `order by 'в Query2 ниже заставляют его занять минуту, пока первый возвращает результаты мгновенно. Есть ли лучший способ сделать это «заказ»Mysql Order By after Group По причинам очень медленный запрос

Быстро:

select c.id, max(date(a.sent)) as sent, 
    if(c.id in (select id from bin where (num=1 or num=2)),1,0) as done 
from test c, test2 a 
where c.id=a.id 
group by c.id 
limit 1; 

Slow

select c.id, max(date(a.sent)) as sent, 
    if(c.id in (select id from bin where (num=1 or num=2)),1,0) as done 
from test c, test2 a 
where c.id=a.id 
group by c.id 
order by done, sent 
limit 1; 

ответ

1

Это потому, что «колонна» в порядке по статье не являются реальными столбцами, но алиасы для расчетов в другом месте запроса. Таким образом, они не индексируются, и сервер должен заказывать их на лету. Использование соединения для вычисления done, а не подзапроса, скорее всего, ускорит это.

+0

С большинством современных СУБД, подзапросы на самом деле не хуже Joins. Это справедливо только для старшей СУБД, которая не могла понять, когда эти два эквивалента. Сегодня иногда подзапрос - лучший способ пойти ... все зависит. –

0

Если вы возвращали все записи, сортировка не должна занимать много времени, даже если они являются вычисленными/неиндексированными полями. Однако вы используете «Limit 1». Это изменяет подход оптимизатора.

В первом случае вы заказываете удостоверение личности. Поскольку у вас есть «предел 1», а идентификатор, вероятно, имеет индекс, оптимизатор может перейти по идентификатору по ID и когда он получит одну запись, которая соответствует предложению WHERE, которое она может вернуть.

Однако во втором запросе, хотя вам нужна только 1 запись, оптимизатор не знает, какой из них будет, если он не вычислит весь набор (как будто у вас не было «limit 1»), а затем возвращается только первый.

Снимите «LIMIT 1» и сравните два запроса. Если разница остается, это может быть другой проблемой.

Трудно сказать, что лучше всего подходит для ваших томов. Попробуйте этот запрос:

select id, max(date(sent)) as sent, 0 As done 
from test2 
where exists (select 1 from bin where bin.id=test2.id and num not in (1,2)) 
group by id 
union all 
select id, max(date(sent)) as sent, 1 As done 
from test2 
where exists (select 1 from bin where bin.id=test2.id and num in (1,2)) 
group by id 
order by done, sent 
limit 1 

SQL Fiddle is here, если вы хотите, чтобы настроить его.

Я оставил тестовый стол, потому что вы не возвращали ни одного поля, кроме ID, которое уже находится на test2. Если вам нужны другие поля из теста, вам придется настроить его.

+0

Вы правы. Я просто запускал оба запроса без Limit 1, а «быстрая» версия работала медленнее, чем «быстрый». Так ясно, что «предел 1» оказывает влияние. Да, я действительно хочу только вернуть одну запись. Что это лучший способ сделать это? – user2029890

+0

Спасибо. Определенно быстрее, но все еще не используется быстро. Мне нужны данные из таблицы «test». Я просто не включил его в пример. Одна таблица имеет около 300 тыс. Записей, а другая около 2 млн. – user2029890

+0

Хорошо, сколько записей в каждой из этих трех таблиц: test, test2, bin? –

Смежные вопросы