2009-04-10 7 views
5

저는 몇 년 동안 SQL을 사용해 왔지만 단순한 삽입 및 선택 등은 거의 없습니다. SQL 전문가는 아닙니다. PHP에서 PDO까지 SQLite에서 실행중인보다 복잡한 SQL 문을 최적화하는 데 도움이 될지 궁금합니다.SQLite 최적화 다중 선택 삽입

성명이 올바르게 작동하는 것으로 보입니다. 예상보다 오래 걸리는 것처럼 보입니다. (아니면 그냥 너무 많이 기대하고 있습니다.)

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') 
     ); 

내가있어하는 하나 개 이상의 그룹에 가입자의 목록입니다 :

는 SQL이다. 구독자를 메일 대기열에 추가하고 하나 이상의 그룹 (1,2,3)에 속한 그룹을 선택하지만 다른 그룹 (4,5,6) 그룹에있는 그룹은 제외 시키려고합니다.

첫째, 위의 SQL은 일반적인 방법입니까?

둘째,이 작업을 가능한 효율적으로 수행하기 위해 어떤 표시가 있어야합니까?

현재 평균 사양 LAMP에 약 5000 개의 가입자 레코드 (소수 그룹)를 얻는 데 약 30 초가 소요됩니다.

성능이 그다지 중요하지 않지만,이 내용을 더 잘 이해하고 싶으므로 통찰력이 크게 향상 될 것입니다.

브래드

답변

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

감사합니다. Matt, 훌륭합니다. 첫 번째 해결책은 30 초에서 약 5 또는 6까지 내려갔습니다. 두 번째 옵션을 시도하지 않았는데 실제로 이해하지 못했지만 문제가되는 경우이를 명심합니다. 감사합니다. –

3

빠르게 할 수있는 SQL을 작성하는 또 다른 방법 (I 테스트에 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

감사합니다. Tom, 인용 된 ID가 맞습니다. 왜 내가 거기에 있었는지 확신 할 수 없습니다.matt 's가 잘 작동하는 것 같고 당신의 것이 exclude 그룹 부분 (4,5,6)을 놓치고있는 것 같아서 나는 당신의 제안을 시도하지 않았습니다. 어쨌든 고마워! –

+0

실제로 더 자세히 보았을 때 ID 열 중 하나가 INTEGER로 선언되지 않아 따옴표가 필요하다는 것을 알았습니다. SQLite는 내가 놓친 이유에 대해 까다로운 타입이 아닙니다. 정수로 변경하고 따옴표를 제거하면 약 1/2 초 후에 실행됩니다. 감사! –

+0

광산에서 해당 배려 사항을 처리해야합니다. 테스트 해 봤어? 그것이 LEFT JOIN 전체에 관한 것입니다. WHERE 절의 조인 된 테이블에서 NOT NULL 열을 확인하고 NULL 인 경우 일치하는 것이 없다는 것을 알 수 있습니다. –