2009-04-10 71 views
5

我一直在使用SQL多年,但很少有更多的简单插入和选择等......所以我不是SQL专家。我想知道是否可以通过PDO优化我在SQLite上执行的更复杂的SQL语句,从而获得一些帮助。SQLite优化多选插入

该声明似乎工作正常,似乎需要更长的时间,我会预期(或许我只是期待太多)。

这是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典型的如何做到这一点?

其次,我应该做些什么来尽可能有效地完成这项工作?

目前大约需要30秒才能在平均规格LAMP上获得大约5000个用户记录(以及少数几组)。

在一天结束时,表现并不是那么重要,但我想更好地理解这个东西,所以任何见解都非常感谢。

布拉德

回答

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,组ID)

我的猜测是,订户已经拥有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 
+0

谢谢马特,那太好了。你的第一个解决方案从30秒减少到5或6,这足够好。我没有尝试第二种选择,因为我不太了解它,但是如果它成为问题,我会记住它。再次感谢 – 2009-04-10 23:52:00

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

+0

谢谢汤姆,你说的是正确的ID ......不知道为什么我让他们在那里。我没有尝试你的建议,因为马特似乎运作良好,你的似乎错过了排除组(4,5,6)。不管怎么说,还是要谢谢你! – 2009-04-10 23:53:59