Postgres 8.4.4 (x32 на Win7 x64) очень медленное ОБНОВЛЕНИЕ на маленьком столе - PullRequest
5 голосов
/ 24 декабря 2010

У меня очень простое заявление об обновлении:

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

Ответы [ 3 ]

2 голосов
/ 24 декабря 2010

PostgreSQL реализует MVCC.

Это означает, что при каждом обновлении создается новая копия строки, а старая помечается как удаленная (но не удаляется физически).

Это замедляет запросы.

Вы должны запустить VACUUM своевременно.

PostgreSQL 8.4.4 запускает autovacuum демон, чтобы сделать это, но у него могут быть некоторые проблемы при установке.

Улучшается ли ситуация, когда вы запускаете VACUUM вручную?

2 голосов
/ 24 декабря 2010

Проверьте с помощью pg_total_relation_size('tablename'), не раздуты ли ваши таблицы.В этом случае вам может понадобиться настроить конфигурацию автоочистки.

Другой альтернативой является блокировка таблиц.Загляните в pg_stat_activity или pg_locks, чтобы узнать.

1 голос
/ 24 декабря 2010

Я думаю, вы не правильно закрываете транзакции.

...