SQLite优化多选插入

时间:2009-04-10 14:43:18

标签: sql sqlite

我已经使用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秒。

在一天结束时,表现并不是那么重要,但我想更好地了解这些内容,以便深刻理解任何见解。

布拉德

2 个答案:

答案 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数据类型,则会有一些额外的处理来在两种不同的数据类型之间进行转换。如果它们是数据库中的字符串,是否有原因?这些列中是否包含非数字值?