从SQL查询中排除可能结果的最有效方法是什么?

时间:2016-02-29 23:01:39

标签: sql

我有一个包含Customers,Subscriptions和Publications表的订阅数据库。

Subscriptions表包含所有订阅记录,每条记录都有三个标记状态的标志:isActive,isExpire和isPending。这些是布尔值,只有一个标志可以为True - 这由应用程序处理。

我需要确定所有未续订过他们之前订阅的杂志的客户,并且我不确定我是否编写过最有效的SQL查询。如果我发现已失效的订阅,我需要忽略它,如果他们已经有特定杂志的有效或待定订阅。

以下是我所拥有的:

SELECT DISTINCT Customers.id, Subscriptions.publicationName
FROM Subscriptions
LEFT JOIN Customers
ON Subscriptions.id_Customer = Customers.id
LEFT JOIN Publications
ON Subscriptions.id_Publication = Publications.id
WHERE Subscriptions.isExpired = 1
AND NOT EXISTS
( SELECT * FROM Subscriptions s2
WHERE s2.id_Publication = Subscriptions.id_Publication
AND s2.id_Customer = Subscriptions.id_Customer
AND s2.isPending = 1 )
AND NOT EXISTS
( SELECT * FROM Subscriptions s3
WHERE s3.id_Publication = Subscriptions.id_Publication
AND s3.id_Customer = Subscriptions.id_Customer
AND s3.isActive = 1 )

我有超过50,000个订阅记录,这个查询需要大约一个小时才能运行,这告诉我有很多循环或者正在发生的事情,每个记录的SQL引擎必须再次搜索才能找到' isPending'和' isActive'记录。

这是我的第一篇文章,所以如果我错过了我的问题中的任何信息,请保持温柔:)谢谢。

1 个答案:

答案 0 :(得分:0)

我没有完整的数据库结构,因此我无法测试以下查询,但可能包含一些优化。我会留给你测试,但会解释为什么我改变了,我改变了什么。

select Distinct Customers.id, Subscriptions.publicationName 
from Subscriptions 
join Customers on Subscriptions.id_Customer = Customer.id
join Publications
ON Subscriptions.id_Publication = Publications.id
Where Subscriptions.isExpired = 1
And Not Exists
(select * from Subscriptions s2
join Customers on s2.id_Customer = Customer.id
join Publications
ON s2.id_Publication = Publications.id
where s2.id_Customer = s2.id_customer and 
(s2.isPending = 1 or s2.isActive = 1))

如果您在客户或出版物数据库中没有结果数据,那么订阅信息不是很有用,所以我取消了LEFT加入,转而只是加入。合并两个Exists子查询。如果我记得这些是非常密集的,那么越少越好。最后我没有在上面列出但可能值得研究的事情是,您是否可以运行返回特定数据字段的子查询并在Exists子句中使用它?使用Select *将返回所有数据字段,这会减慢处理速度。我不确定你是否可以限制你的结果,因为我没有可用的等效数据库我可以测试(谷歌可能知道)。

我怀疑可以对此查询进行进一步优化。消除存在条款以支持' IN'条款可能有所帮助,但我现在无法想到一种方法,看看你如何匹配两个独特的领域(客户ID和相关订阅)。如果这有帮助,请告诉我。

使用50k行的表,您应该能够在几秒钟内运行这样的查询。