SQLite оптимизирует множественный выбор вставки - PullRequest
5 голосов
/ 10 апреля 2009

Я использую SQL уже много лет, но редко что-либо большее, чем простые вставки, выбор и т. Д., Поэтому я не эксперт по SQL. Мне интересно, могу ли я получить некоторую помощь в оптимизации более сложного оператора SQL, который я выполняю на SQLite, от 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 типичен для этого?

Во-вторых, по каким признакам я должен сделать эту работу максимально эффективной?

В настоящее время требуется около 30 секунд, чтобы просмотреть около 5000 записей о подписчиках (и нескольких группах) в LAMP спецификации avg.

В конце концов, производительность не так уж критична, но я бы хотел лучше понять этот материал, чтобы любая оценка была высоко оценена.

Бред

Ответы [ 2 ]

6 голосов
/ 10 апреля 2009

Скорее всего, дополнительные соединения убивают вас. Что делать, если вы делаете:

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, верно?

EDIT: Другой вариант, который может быть или не быть быстрее. Посмотрите на планы запросов каждого, чтобы увидеть ...

Это может быть сканирование по одному индексу, которое может быть быстрее, чем два поиска по индексу, но это зависит от оптимизатора 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
3 голосов
/ 10 апреля 2009

Другой способ написать 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 в вашей базе данных, потребуется дополнительная обработка для преобразования между двумя различными типами данных. Если они являются строками в базе данных, есть ли причина для этого? У вас есть нечисловые значения в этих столбцах?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...