У меня очень простое заявление об обновлении:
UPDATE W SET state='thing'
WHERE state NOT IN ('this','that') AND losttime < CURRENT_TIMESTAMP;
Таблица W имеет только 90 строк, хотя столбцы потерянного времени и состояния для каждой строки обновляются каждые ~ 10 секунд. Существуют индексы состояния и потерянного времени (а также первичный индекс).
Я заметил, что в больших базах данных (то есть в других таблицах много записей, а не в таблице W) в течение определенного периода времени запрос становится все медленнее и медленнее. После запуска в течение 48 часов я синхронизирую его, запустив в окне запросов PqAdminIII, и его выполнение заняло 17 минут!
У меня похожий запрос к другой таблице, в которой отображается та же проблема:
UPDATE H SET release='1'
WHERE a NOT IN (SELECT id from A WHERE state!='done') AND release!='1';
H не имеет индексов, но я попытался поместить и удалить индекс для H (выпуск) без изменений в поведении. Этот запрос, после того как база данных проработала 48 часов и таблица H имеет ~ 100 тыс. Строк, занимает 27 минут. На сервере Postgres поток будет полностью привязан (100% загрузка ЦП) на время выполнения запроса, поэтому не похоже, что существует конфликт между сетью, диском и т. Д.
Итак, в общих чертах поведение, которое я вижу, состоит в том, что моя база данных работает, как и ожидалось, в течение примерно 5 минут, затем постепенно все останавливается, поскольку выполнение базовых команд UPDATE, связанных с обслуживанием, начинает выполняться все дольше и дольше. Ко второму дню требуется час, чтобы выполнить простой цикл обслуживания (горстка ОБНОВЛЕНИЙ), который с самого начала работал ~ 100 мс. Мне кажется очевидным, что снижение производительности является суперлинейным с количеством информации в базе данных - возможно, N ^ 2 или что-то подобное.
Автовакуум включен по умолчанию. Я прочитал руководство (снова) и не увидел ничего, что выскочило на меня.
Я чешу голову здесь. Я не вижу каких-либо исправлений ошибок, которые кажутся актуальными в примечаниях к выпуску 9.0.1 и 9.0.2. Может ли кто-нибудь помочь мне понять, что происходит? Спасибо, М
-х-х-х-х
Хорошо, у меня тут две проблемы.
Первое обновление теперь работает быстро. Не уверен, что случилось, поэтому я буду исходить из того, что мне нужно чаще запускать VACUUM / ANALYZE или какую-то комбинацию - скажем, каждую минуту или около того. Я действительно хотел бы знать, почему автоочистка не делает это для меня.
Второе обновление продолжает работать медленно. План запроса предполагает, что индексы используются неэффективно, и что происходит пересечение 80k * 30k, что может объяснить суперлинейное время выполнения, которое я, похоже, наблюдаю. (Все ли согласны с такой интерпретацией плана?)
Я могу преобразовать ОБНОВЛЕНИЕ в ВЫБОР:
SELECT * from H
where a not in (SELECT id from A where state='done') AND release!='1';
с аналогичным временем выполнения (27 минут).
Если я не доверяю оптимизатору postgres и делаю это:
WITH r as (select id from A where state='done')
SELECT a from H
JOIN on H.a=r.id
WHERE H.released='0';
, тогда запрос выполняется за ~ 500 мс.
Как мне перевести эти знания обратно в ОБНОВЛЕНИЕ, которое работает с приемлемой скоростью?
Моя попытка:
UPDATE H SET release='1'
FROM A
where A.state!='done' AND release!='1' AND A.id=H.a;
работает примерно за 140 секунд, что быстрее, но все еще очень и очень медленно.
Куда я могу пойти отсюда?
-х-х-х-х
VACUUM ANALYZE был добавлен как часть "обычного обслуживания", когда приложение будет запускать его примерно раз в минуту или около того, независимо от того, какой автозапуск работает.
Кроме того, переписан второй запрос, чтобы исключить предложение NOT IN, которое будет медленным, заменив его на «Left Anti-Semi Join» (да?)
UPDATE H SET release='1'
WHERE release='0' AND NOT EXISTS (SELECT * FROM A WHERE id=H.a AND state!='done');