2009-06-15 94 views
1

因此,假設我正在構建該聯繫人管理系統。有一個USER表和一個CONTACT_INFO表。 對於每個USER,我可以有零個或多個CONTACT_INFO記錄。按照我定義它的方式,我在CONTACT_INFO表中設置了一個外鍵以指向相關的USER記錄。創建最佳查詢來查找僅在一個表中的記錄

我想要搜索所有沒有CONTACT_INFO記錄的USER記錄。

我希望可以這樣做:

SELECT * FROM user u WHERE u.user_id NOT IN (SELECT DISTINCT c.user_id FROM CONTACT_INFO); 

我擔心的是,隨着表增長,這個查詢的性能可以顯著降低。

我在玩的一個想法是在USER表中添加一列,表明它是否有任何CONTACT_INFO記錄。另外,我想知道,如果在向CONTACT_INFO中插入任何記錄時,DBMS必須驗證記錄是否存在,那麼爲了驗證和更新它,已經訪問該記錄,當我更新CONTACT_INFO記錄時不應該成本高昂,性能明智。

一如既往,讚賞反饋。

+1

您應該嘗試下面的幾個選項,然後確定每個選項的查詢計劃和性能,並選擇最好的一個。 – 2009-06-16 16:51:26

+0

我們在談論哪些DBMS? – AakashM 2009-06-16 16:55:07

回答

2

從我的測試,以下是比BradC的方法更快:

select (...) 
from user u 
where not exists (select null from CONTACT_INFO c where u.user_id = c.user_id) 

這可能是因爲編譯器要做的轉換本身,我不知道。儘管如此:如果你已經在數據庫中設置了索引(即兩個user_id列都應該被索引),那麼你的答案和這裏的大部分答案都會非常快,不管您的數據庫中有多少條記錄。

順便說一下,如果你正在尋找一種方式來獲得一個查詢,列出用戶提供了「HasContactInfo」布爾值一起,你可以做這樣的事情:

select u.(...), 
    (case when exists (select null from CONTACT_INFO c where c.user_id = u.user_id) then 1 
     else null 
     end) has_contact_info 
from user u 

第二方案可能不在你的情況下很有用,但我發現它比我假設的一些更簡單的查詢會自動優化更快。

3

最簡單方法是:

SELECT (...) 
FROM user u 
LEFT OUTER JOIN CONTACT_INFO c 
ON u.user_id = c.user_id 
WHERE c.user_id IS NULL 

它看起來更臃腫,但應更好地擴展。

+0

我測試過的優化器把這個同樣地看作是一個簡單的NOT EXISTS。(但是對於很多情況來說,這是一個很棒的技術,而且稍微更便攜,這意味着它可以在老版本的MySQL中工作。) – dkretz 2009-06-15 22:42:41

1

你有什麼理由認爲性能會下降嗎?這是SQL中最高效的查詢類型之一。但放棄DISTINCT。

1

至少在Oracle中,我獲得使用

其中0 =(SELECT COUNT(*)從CONTACT_INFO C,其中...)

代替NOT IN子句中更好的性能。

相關問題