![](/img/trans.png)
[英]MySQL: Find records matching in two tables A & B where B is massive
[英]Given two tables A and B with a common field F, how do I efficiently find all F in A that are not present in B?
我有一个投票系统,我正在尝试为MySQL写一个查询,该查询将检测完成的投票,以便将电子邮件发送给投票的创建者。 当(1)他们的时间用完(已经很容易解决)时,或(2)当所有选民都投票时,投票就完成了。
有两个与此相关的表。 第一个表是“投票”,其中描述了每个投票并具有唯一的“ vote_id”。 第二张表是“门票”。 在投票创建时,每个参与者都会创建一个票证(其中包含一些身份验证信息)。 每个票证都有一个“ vote_id”字段,该字段与“ votes”表中的字段相对应。 因此,基本上,随着人们的投票,他们相应的票证将从票证表中删除。 这意味着给定“ vote_id”的“票证”中的行数对应于未投票的人数。
首先,我去做这样的事情:
SELECT votes.vote_id
FROM votes, tickets
WHERE votes.vote_id=tickets.vote_id
AND (votes.completion_timestamp < NOW())
HAVING (COUNT(tickets.vote_id) = 0)
但是后来我意识到...由于“ votes.vote_id = tickets.vote_id”这一行...我想这意味着那些没有未付票证的票将被忽略。 我可以想到许多效率低下的方法来执行此操作,但是我想在MySQL中有一种方法可以执行此操作?
问题的概括:给定两个具有共同字段F的表A和B,我如何找到A中所有B中不存在的F?
为了在MySQL中有效地做到这一点,需要一个技巧:
select v.*
from votes v
where votes.completion_timestamp < NOW() and
not exists (select 1 from tickets t where t.vote_id = v.vote_id)
您拥有的SQL不太正确。 以下版本应该工作:
SELECT distinct votes.vote_id
FROM votes left outer join
tickets
on votes.vote_id=tickets.vote_id
where votes.completion_timestamp < NOW()) and
tickets.vote_id is null
MySQL文档(http://dev.mysql.com/doc/refman/5.0/en/subquery-optimization-with-exists.html)中广泛讨论了EXISTS与IN结合使用子查询的问题。 与左外部连接的区别在于两点。 加入策略并增加I / O。
我不知道JOIN策略对于左外部联接是否有所不同。 我推测它不应该比EXISTS版本更糟。 不过,第二点是,左外部联接创建了一个输出集,该输出集可能使行数成倍增加。 EXISTS版本无法执行此操作。
阅读文档后,以下操作可能会更有效:
select v.*
from votes v
where votes.completion_timestamp < NOW() and
not exists (select 1 from tickets t where t.vote_id = v.vote_id limit 1)
该限制应该使遇到的第一行以外的任何评估短路。
这样的事情将返回您期望的结果:
select votes.vote_id
from votes
left outer join tickets on votes.vote_id = tickets.vote_id
where tickets.ticket_id is null or votes.completion_timestamp < NOW()
假定tickets.ticket_id
是tickets
表的主键,并且不能为NULL。
该查询通过在票证与票证之间进行左外部tickets.ticket_id
并在其中票证tickets.ticket_id
必须为NULL的条件下利用了这一事实。 只有在tickets
表中没有该票证的票证时,才会发生这种情况。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.