我有一個很難搞清楚如何做一個優化的查詢做下面列出,儘管這聽起來很簡單。查詢排除行的ID在另一個表
假設我有一個名爲promo的表(一列:ID),另一個表叫做promo_has_been_displayed_to_user(兩列:promo_id和user_id,而promo_id是引用promo.ID的外鍵)。我想要一個查詢,它將返回Promo中所有行,其中的ID字段在Promo_has_been_displayed_to_user中的任何行中都未提及,其中promo_has_been_displayed_to_user.user_id字段設置爲45.假設我在所有字段上都有索引。
(我的想法是,我有一個促銷廣告數據庫和一個用戶數據庫,每當我向用戶展示廣告時,我都會在promo_has_been_displayed_to_user中存儲它已經顯示給他們的內容。尚未顯示給用戶45)的新廣告
看來理論上最佳的方式做這將是如下:
1)獲取promo_has_been_displayed_to_user的一個子集,其中USER_ID = 45,並且在子集,維護user_id字段上的索引。 2)對於促銷中的每一行,取出ID並在索引的promo_id字段中查找步驟1中生成的子集。 3)返回宣傳片中的所有行,你沒發現在步驟2中
但如何匹配我的結構,反映了一個查詢?
現在,我至少有兩個查詢將返回正確的答案(我用測試數據驗證);問題是,我不認爲他們會最佳性能運行,有以下原因:
1)
select * from promo
where ID not in (select promo_id from promo_has_been_displayed_to_user
where user_id=45)
該查詢的麻煩是,一旦你必須返回ID列表「選擇從promo_has_been_displayed_to_user其中USER_ID = 45" PROMO_ID,我認爲這只是一個列表(沒有索引它身上),並認爲‘沒有’檢查是通過只檢查該列表一次一個實現。如果其中user_id = 45的promo_has_been_displayed_to_user的子集結果很大,那麼對於促銷中的每一行,我們都必須搜索一個沒有索引的巨大列表。
2)
select * from promo p
where not exists (select * from promo_has_been_displayed_to_user
where promo_id = p.ID and user_id=45)
這一次,我們正在做的索引PROMO_ID領域的查找。但是,對於促銷中的每一行,我正在查詢整個promo_has_been_displayed_to_user表。如果只有一小部分promo_has_been_displayed_to_user,其中user_id = 45,這是浪費的。
是否有一個單一的查詢將結合兩個世界的最佳 - 我首先將promo_has_been_displayed_to_user縮減到其中user_id = 45的子集,然後對於促銷中的每一行,我在promo_id上進行索引查找以查看是否子集中有匹配的行嗎?
(這是MySQL的5.0.95,雖然這聽起來像的東西是不是數據庫服務器特定的。)
嘗試左連接。可能會在MySQL上執行得更快。 – jarlh
這是一個簡單的排除加入 – Strawberry