2013-05-09 73 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; 

這需要很長的時間來運行,我認爲它與在WHERE語句選擇做(有大量的ID),但我不能想出一個方法來改善它。

首先,這可能是查詢速度如此之慢的原因,其次是如何改進它的建議?

編輯:

數據庫系統:MySQL的

標識被索引,但是卻並不在此表的主鍵;它是一個外鍵。

+1

你的表有多大,'type'有索引? – nacholibre 2013-05-09 19:59:03

+1

'WHERE type ='email''和'WHERE type ='letter''似乎是多餘的。你基本上說類型必須是「電子郵件」,但是再次檢查它不是「字母」。你不能只拿出嵌套的SELECT? – 2013-05-09 19:59:36

+4

整個'不在'位似乎是多餘的。如果你用'type ='email''找到了一條記錄,那麼它怎麼可能在'type ='letter''的記錄列表中呢? – 2013-05-09 20:00:17

回答

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; 

編寫這種類型的查詢的三種主要方式是不是,不存在(相關)或左連接/空。 Quassnoi將它們比作MySQL(上面的鏈接),SQL ServerOraclePostgreSQL

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 

這將獲得市場營銷中'email'類型的所有行,並且不存在與類型'letter'匹配的id。如果你想要另一個集合,使用IS NOT NULL。在id列上的正確索引是您最大執行速度所需的全部內容,其中type爲覆蓋列。

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執行排序。