2013-05-09 3 views
3

Я пытаюсь сделать простой SQL-запрос:Улучшения запроса

SELECT DISTINCT id 
FROM marketing 
WHERE type = 'email' 
    AND id NOT IN (
       SELECT id 
       FROM marketing 
       WHERE type = 'letter' 
       ) 
ORDER BY id; 

Это занимает очень много времени, чтобы бежать, и я предполагаю, что он должен делать с выбором в где заявлении (Есть целые большое количество идентификаторов), но я не могу придумать способ улучшить его.

Во-первых, это может быть причиной столь медленного запроса, и во-вторых, любое предложение о том, как его улучшить?

Edit:

системы баз данных: MySql

Id индексируется, но, но не является первичным ключом в таблице; это внешний ключ.

+1

Насколько велика ваша таблица и «тип» имеет ли она индекс? – nacholibre

+1

'WHERE type = 'email'' и 'WHERE type = 'letter'' кажется излишним. Вы в основном сказали, что тип должен быть «электронной почтой», но затем дважды проверьте, что это не «письмо». Вы не можете просто вынуть вложенный SELECT? –

+4

Весь бит 'not in' кажется излишним. Если вы нашли запись с 'type = 'email'', то как она может быть в списке записей с типом = буквой? –

ответ

1

Вот альтернатива вашему запросу, хотя согласно Quassnoi here (MySQL) он должен работать аналогичным образом.

select email.id 
    from marketing email 
left join marketing letter on letter.type='letter' and letter.id=email.id 
    where email.type='email' and letter.id is null 
group by email.id 
order by email.id; 

Три основных способа написания этого типа запроса являются NOT IN, NOT EXISTS (коррелируют) или LEFT JOIN/IS NULL. Quassnoi сравнивает их для MySQL (ссылка выше), SQL Server, Oracle и PostgreSQL.

2

Существует известный шаблон для запросов такого типа: получите все строки, которые не соответствуют другому набору.

select id from marketing m1 
left outer join marketing m2 on m1.id = m2.id and m2.type = 'letter' 
where m1.type = 'email' and m2.id IS NULL 

Это позволит получить все строки в области маркетинга, которые типа «электронная почта», и не существует идентификатора с «буквой» типа, чтобы соответствовать. Если вы хотите другой набор, используйте IS NOT NULL. Правильный индекс в столбце id - это все, что вам нужно для максимальной скорости выполнения, с типом в качестве закрытого столбца.

2
select distinct id 
from marketing a 
where type = 'email' 
and not exists (
      select 'X' 
      from marketing b 
      where a.id = b.id 
      and type = 'letter') 
order by id 
1

Вы также можете сформулировать этот запрос как запрос агрегации. Условия вы ищете что id имеет по крайней мере одну строку, в которой type = 'email' и ни одной строки, где type = 'letter':

select id 
from marketing m 
group by id 
having SUM(case when type = 'letter' then 1 else 0 end) = 0 and 
     SUM(case when type = 'email' then 1 else 0 end) > 0 

Вполне возможно, что этот запрос будет работать быстрее с индексом на marketing(id, type). order by id избыточен в MySQL, потому что group by делает заказ.

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