Ускорение внутренних соединений и подзапросов при ограничении размера строки и членства в таблице - PullRequest
3 голосов
/ 14 марта 2010

Я разрабатываю программу чтения RSS-каналов, которая использует байесовский фильтр для фильтрации скучных сообщений в блоге.

Таблица Stream предназначена для работы в качестве буфера FIFO, из которого веб-приложение будет потреблять «записи». Я использую его для хранения временных отношений между записями, пользователями и классификациями байесовского фильтра.

После того, как пользователь пометит запись как прочитанную, она будет добавлена ​​в таблицу метаданных (чтобы пользователю не был представлен материал, который он уже прочитал) и удалена из таблицы потоков. Каждые три минуты фоновый процесс будет заново заполнять таблицу Stream новыми записями (т. Е. Всякий раз, когда демон добавляет новые записи после проверки RSS-каналов на наличие обновлений).

Проблема: запрос, который я предложил, является медленным. Что еще более важно, таблица Stream должна содержать только сотню непрочитанных записей одновременно; это уменьшит дублирование, ускорит обработку и даст мне некоторую гибкость при отображении записей.

Запрос (занимает около 9 секунд для 3600 элементов без индексов):

insert into stream (entry_id, user_id) 
select entries.id, subscriptions_users.user_id 
 from entries 
inner join subscriptions_users on subscriptions_users.subscription_id = entries.subscription_id 
where subscriptions_users.user_id = 1 
  and entries.id not in (select entry_id 
                           from metadata 
                          where metadata.user_id = 1) 
  and entries.id not in (select entry_id 
                          from stream where user_id = 1);

Запрос объяснил: вставьте в поток все записи из списка подписок пользователя (subscription_users), которые пользователь не прочитал (т.е. не существует в метаданных) и которые еще не существуют в потоке.

Попытка решения: добавление предела 100 в конец значительно ускоряет запрос, но при повторных выполнениях будет продолжать добавлять другой набор из 100 записей, которых еще нет в таблице (каждый успешный запрос занимает все больше и больше времени) ,

Это близко, но не совсем то, что я хотел сделать.

Есть ли у кого-нибудь совет (nosql?) Или знаете более эффективный способ составления запроса?

Ответы [ 3 ]

1 голос
/ 14 марта 2010

Использование:

INSERT INTO STREAM 
  (entry_id, user_id) 
   SELECT e.id, 
          su.user_id 
     FROM ENTRIES e
     JOIN SUBSCRIPTIONS_USERS su ON su.subscription_id = e.subscription_id 
                                AND su.user_id = 1 
LEFT JOIN METADATA md ON md.entry_id = e.id
                     AND md.user_id = 1
LEFT JOIN STREAM s ON s.entry_id = e.id
                  AND s.user_id = 1
    WHERE md.entry_id IS NULL
      AND s.entry_id IS NULL

В MySQL LEFT JOIN/IS NULL является наиболее эффективным средством получения данных, которые существуют в одной таблице, но не в другой. Ссылка

Проверьте производительность запроса перед просмотром индексов.

В Postgres:

  • NOT IN
  • NOT EXISTS
  • LEFT JOIN / IS NULL

... эквивалентны .

1 голос
/ 14 марта 2010

Запрос (занимает около 9 секунд 3600 наименований без индексов):

Тогда я бы попробовал начать с некоторых индексов ...

ИЛИ LEFT JOIN NULL (и индексы)

SELECT *
FROM TABLEA A LEFT JOIN
    TABLEB B ON A.ID = B. ID
WHERE B.ID IS NULL
0 голосов
/ 14 марта 2010

Одним из способов оптимизации выбора является замена подзапросов объединениями.

Что-то вроде:

select entries.id, subscriptions_users.user_id
from entries 
inner join subscriptions_users on subscriptions_users.subscription_id = entries.subscription_id 
left join metadata  md on (user_id,entry_id)
left join stream  str on (user_id, entry_id) 
where subscriptions_users.user_id = 1 and where md.user_id is null and str.user_id is null;

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

Также поможет добавление индексов.

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