Скорость усечения Postgresql



мы используем Postgresql 9.1.4 как сервер БД. Я пытался ускорить свой тестовый набор, поэтому я немного посмотрел на профилирование БД, чтобы точно увидеть, что происходит. Мы используем database_cleaner для усечения таблиц в конце тестов. Да, я знаю, что транзакции быстрее, я не могу использовать их в определенных обстоятельствах, поэтому меня это не волнует.



что меня беспокоит, так это то, почему усечение занимает так много времени (дольше, чем использование DELETE) и почему оно занимает еще больше времени мой сервер CI.



прямо сейчас, локально (на Macbook Air) полный набор тестов занимает 28 минут. Следя за журналами, каждый раз мы усекаем таблицы... т. е.:



TRUNCATE TABLE table1, table2  -- ... etc


для выполнения усечения требуется более 1 секунды. Отслеживание журналов на нашем сервере CI (Ubuntu 10.04 LTS), занимает полные 8 секунд, чтобы усечь таблицы, а сборка занимает 84 минуты.



когда я переключился на :deletion стратегия, моя локальная сборка заняла 20 минут, и сервер CI опустился до 44 минут. Это же значительное разница, и я действительно потрясен, почему это может быть. У меня тюнингованныхthe DB на сервере CI, он имеет 16 ГБ оперативной памяти системы, 4 ГБ shared_buffers... и SSD. Все хорошие вещи. Как это возможно:



a. что это намного медленнее, чем мой MacBook Air с 2 ГБ оперативной памяти
b. это усечение намного медленнее, чем удалить, когда postgresql документыявно что это должно быть намного быстрее.



какие мысли?

685   4  

4 ответов:

это появилось несколько раз в последнее время, как в so, так и в списках рассылки PostgreSQL.

The TL; DR для последних двух пунктов:

(a)чем больше shared_buffers, тем медленнее усечение на сервере CI. Другая конфигурация fsync или использование вращательных носителей вместо твердотельных накопителей также могут быть виноваты.

(b)TRUNCATE имеет фиксированную стоимость, но не обязательно медленнее, чем DELETE, плюс он делает больше работы. Смотрите подробное объяснение, которое следует.

обновление: A значительная дискуссия по pgsql-performance из этого поста. Смотрите этой теме.

обновление 2: улучшения были добавлены в 9. 2beta3, которые должны помочь в этом, см. этот пост.

подробное описание TRUNCATE vs DELETE FROM:

пока не эксперт по этой теме, Мой понимание заключается в том, что TRUNCATE имеет почти фиксированную стоимость за стол, в то время как DELETE по крайней мере O(n) для n строк; хуже, если есть какие-либо внешние ключи, ссылающиеся на удаляемую таблицу.

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

TRUNCATE table; не более DELETE FROM table;

состояние базы данных после TRUNCATE table это почти то же самое, что если бы вы вместо этого побежали:

  • DELETE FROM table;
  • VACCUUM (FULL, ANALYZE) table; (только 9.0+, см. сноску)

... хотя конечно TRUNCATE фактически не достигает своих эффектов с помощью DELETE и VACUUM.

дело в том, что DELETE и TRUNCATE делайте разные вещи, поэтому вы не просто сравниваете две команды с одинаковыми результатами.

A DELETE FROM table; позволяет мертвым строкам и раздувать оставаться, позволяет индексам переносить мертвых записи, не обновляет статистику таблицы, используемую планировщиком запросов и т. д.

A TRUNCATE дает вам совершенно новые таблицы и указатели, как если бы они были просто CREATEed. Это как вы удалили все записи, переиндексировали таблицу и сделали VACUUM FULL.

Если вам все равно, если в таблице осталась грязь, потому что вы собираетесь снова ее заполнить, вам может быть лучше использовать DELETE FROM table;.

потому что ты не бежишь VACUUM вы найдете что мертвые строки и записи индекса накапливаются как вздутие, которое должно быть Отсканировано, а затем проигнорировано;это замедляет все ваши запросы. Если ваши тесты на самом деле не создают и не удаляют все эти данные, которые вы можете не заметить или не заботиться, и вы всегда можете сделать VACUUM или две части пути через ваш тестовый запуск, если вы это сделаете. Лучше, пусть агрессивные настройки автовакуума гарантируют, что автовакуум делает это за вас в фоновом режиме.

вы все еще можете TRUNCATE все ваши таблицы после весь

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

вопрос: 30 таблиц с несколькими строками-усечь самый быстрый способ очистить их и сбросить прикрепленные последовательности?

пожалуйста, Также посмотрите на эту проблему и эту тягу запрос:

https://github.com/bmabey/database_cleaner/issues/126

https://github.com/bmabey/database_cleaner/pull/127

также этот поток:http://archives.postgresql.org/pgsql-performance/2012-07/msg00047.php

Я сожалею, что написал это в качестве ответа, но я не нашел никаких ссылок на комментарии, возможно, потому, что там уже слишком много комментариев.

несколько альтернативных подходов к рассмотрению:

  • создайте пустую базу данных со статическими данными "fixture" в ней и запустите тесты в ней. Когда вы закончите, просто удалите базу данных, которая должна быть быстрой.
  • создайте новую таблицу с именем "test_ids_to_delete", которая содержит столбцы для имен таблиц и идентификаторов первичных ключей. Обновите логику удаления, чтобы вместо этого вставить идентификаторы / имена таблиц в эту таблицу, что будет намного быстрее, чем выполнение удалений. Потом написать сценарий для запуска "в автономном режиме", чтобы фактически удалить данные, либо после завершения всего тестового запуска, либо в одночасье.

первый-это подход "чистой комнаты", в то время как последний означает, что некоторые тестовые данные будут сохраняться в базе данных дольше. "Грязный" подход с автономным удалением - это то, что я использую для набора тестов с примерно 20 000 тестов. Да, иногда возникают проблемы из-за наличия "дополнительных" тестовых данных в базе данных dev, но иногда. Но иногда это " грязь" помог нам найти и исправить ошибку, потому что" беспорядок " лучше моделировал реальную ситуацию, таким образом, что подход чистой комнаты никогда не будет.

я столкнулся с подобной проблемой в последнее время, т. е.:

  1. время запуска тестового набора, который использовал DatabaseCleaner, широко варьировалось между различными системами с сопоставимым оборудованием,
  2. изменение стратегии DatabaseCleaner на :deletion при условии ~ 10x улучшение.

основной причиной медлительности была файловая система с журналированием (ext4), используемая для хранения базы данных. Во время операции усечения демон ведения журнала (jbd2) использовал ~90% дискового ввода-вывода вместимость. Я не уверен, что это ошибка, крайний случай или на самом деле нормальное поведение в этих обстоятельствах. Это объясняет, однако, почему усечение было намного медленнее, чем удаление - оно генерировало намного больше записей на диск. Как я не хочу, чтобы на самом деле использовать удалить, я обратился к установлению fsync=off и этого было достаточно, чтобы смягчить эту проблему (сохранность данных не важна в этом случае).

Comments

    Ничего не найдено.