我有一个很难搞清楚如何做一个优化的查询做下面列出,尽管这听起来很简单。查询排除行的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