我已经使用SQL多年了,但很少有简单的插入和选择等等......所以我不是SQL专家。我想知道我是否可以帮助优化我在SQLite上执行的更复杂的SQL语句,从PHP到PDO。
声明似乎工作正常,似乎需要更长的时间,我预期(或者我可能只是期待太多)。
这是SQL:
INSERT OR IGNORE INTO MailQueue(SubscriberID, TemplateID)
SELECT Subscribers.ID, '1' AS TemplateID
FROM Subscribers
INNER JOIN SubscriberGroups ON Subscribers.ID=SubscriberGroups.SubscriberID
WHERE SubscriberGroups.GroupID IN ('1', '2', '3')
AND Subscribers.ID NOT IN
(
SELECT Subscribers.ID FROM Subscribers
INNER JOIN SubscriberGroups ON Subscribers.ID=SubscriberGroups.SubscriberID
WHERE SubscriberGroups.GroupID IN ('4', '5', '6')
);
我所获得的是一个或多个组中的订阅者列表。我想将订阅者添加到邮件队列中,选择属于一个或多个组的用户(1,2,3),但排除那些也在另一组组中的用户(4,5,6)。
首先,上面的SQL是典型的如何做到这一点的?其次,我应该尽可能高效地开展这项工作?
目前,在平均规格LAMP上通过大约5000个订阅者记录(以及少数几个群组)需要大约30秒。
在一天结束时,表现并不是那么重要,但我想更好地了解这些内容,以便深刻理解任何见解。
布拉德
答案 0 :(得分:6)
可能会有额外的连接杀死你。如果你这样做了:
SELECT Subscribers.ID, '1' AS TemplateID
FROM Subscribers
WHERE EXISTS( SELECT *
FROM SubscriberGroups
WHERE Subscribers.ID=SubscriberGroups.SubscriberID
AND SubscriberGroups.GroupID IN ('1', '2', '3') )
AND NOT EXISTS( SELECT *
FROM SubscriberGroups
WHERE Subscribers.ID=SubscriberGroups.SubscriberID
AND SubscriberGroups.GroupID IN ('4', '5', '6')
);
您还需要确保在SubscriberGroups(SubscriberID,GroupID)上有索引
我的猜测是订阅者已经拥有ID索引,对吗?
编辑: 另一种选择,可能会或可能不会更快。查看每个查询计划,看看......
这个可能是单个索引扫描,可能比两个索引搜索快,但它取决于SQLite的优化器......
SELECT Subscribers.ID, '1' AS TemplateID
FROM Subscribers
INNER JOIN( SELECT SUM( CASE WHEN GroupID IN('1', '2', '3') THEN 1 ELSE 0 END ) AS inGroup,
SUM( CASE WHEN GroupID IN('4', '5', '6') THEN 1 ELSE 0 END ) AS outGroup,
SubscriberID
FROM SubscriberGroups
WHERE SubscriberGroups.GroupID IN ('1', '2', '3', '4', '5', '6' )
) SubscriberGroups
ON Subscribers.ID=SubscriberGroups.SubscriberID
AND inGroup > 0
AND outGroup = 0
答案 1 :(得分:3)
编写可能更快的SQL的另一种方法(我没有要测试的SQLite):
SELECT
S.ID,
'1' AS TemplateID -- Is this really a string? Does it need to be?
FROM
Subscribers S
LEFT OUTER JOIN SubscriberGroups SG ON
SG.SubscriberID = S.ID
WHERE
SG.SubscriberID IS NULL AND
EXISTS
(
SELECT
*
FROM
SubscriberGroups SG2
WHERE
SG2.SubscriberID = S.ID AND
SG2.GroupID IN ('1', '2', '3') -- Again, really strings?
)
马特的方法也应该运作良好。这一切只取决于SQLite如何决定创建查询计划。
另外,请注意我的评论。如果在数据库中将它们真正定义为INT数据类型,则会有一些额外的处理来在两种不同的数据类型之间进行转换。如果它们是数据库中的字符串,是否有原因?这些列中是否包含非数字值?