2009-04-10 69 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