SQLite优化多选插入

SQLite优化多选插入,sql,sqlite,Sql,Sqlite,我已经使用SQL很多年了,但很少有比简单的插入和选择等更简单的了。。。所以我不是SQL专家。我想知道我是否可以得到一些帮助来优化我在SQLite上执行的更复杂的SQL语句,从PHP到PDO 这句话似乎是正确的,只是似乎比我预期的要花更长的时间(或者我只是期望太多) 这是SQL: INSERT OR IGNORE INTO MailQueue(SubscriberID, TemplateID) SELECT Subscribers.ID, '1' AS TemplateID FRO

我已经使用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是典型的如何做到这一点的

第二,我应该具备哪些指标才能使这项工作尽可能有效

目前,在avg spec LAMP上浏览大约5000条订户记录(和少数组)需要大约30秒

一天结束时,性能并不是那么关键,但我想更好地理解这一点,因此任何见解都会受到极大的赞赏


Brad

额外的加入很可能会让你丧命。如果您这样做:

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

编写SQL的另一种方法可能更快(我没有要测试的SQLite):

马特的方法也应该很有效。这完全取决于SQLite决定如何创建查询计划


另外,请注意我的评论。如果这些数据类型在数据库中定义为INT数据类型,那么在这两种不同的数据类型之间需要进行一些额外的转换处理。如果它们是数据库中的字符串,有什么原因吗?这些列中有非数值吗?

谢谢Matt,太好了。您的第一个解决方案将时间从30秒减少到大约5或6秒,这就足够了。我没有尝试第二种选择,因为我并不真正理解它,但如果它成为一个问题,我会记住它。再次感谢Hanks Tom,你在引用的ID上是对的。。。不知道我为什么把它们放在那里。我没有尝试你的建议,因为马特的似乎很好,而你的似乎错过了排除组部分(4,5,6)。无论如何谢谢你!实际上更仔细地看,我意识到其中一个ID列没有声明为整数,这就是我需要引号的原因。SQLite对类型并不挑剔,这就是我错过它的原因。更改为整数并删除引号,它现在运行约1/2秒。谢谢我的孩子应该照顾孩子。你测试过了吗?这就是整个左联的意义所在。在WHERE子句中检查联接表中的NOTNULL列,如果该列为NULL,则知道不存在匹配项。
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?
     )