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

Интересно, как быстрее всего выполнить такую ​​задачу в PostgreSQL. Меня интересуют максимально быстрые решения.

Я нашел себе такое решение для MySQL, оно работает намного быстрее, чем просто усечение таблиц по одной. Но в любом случае, меня интересуют самые быстрые решения и для MySQL. Посмотрите мой результат здесь, конечно, только для MySQL: https://github.com/bmabey/database_cleaner/issues/126

У меня есть следующие предположения:

  • У меня 30-100 столов. Пусть будет 30.
  • Половина столов пустует.
  • Каждая непустая таблица имеет, скажем, не более 100 строк. Под этим я подразумеваю, что таблицы НЕ большие.
  • Мне нужна дополнительная возможность исключить из этой процедуры 2, 5 или N таблиц.

  • Я не могу! использовать транзакции.

Мне нужна самая быстрая стратегия очистки для такого случая, работающая на PostgreSQL как 8, так и 9.

Я вижу следующие подходы:

  1. Сократите каждую таблицу. Я думаю, что это слишком медленно, особенно для пустых таблиц.

  2. Проверять каждую таблицу на пустоту более быстрым способом, а затем, если она пуста, сбросить ее столбец уникального идентификатора (аналог AUTO_INCREMENT в MySQL) в исходное состояние (1), т.е. восстановить его last_value из последовательности обратно в 1, иначе запустить truncate в теме.

Я использую код Ruby для перебора всех таблиц, вызывая приведенный ниже код для каждой из них, я попытался настроить код SQL для каждой таблицы, например:

DO $$DECLARE r record;
BEGIN
  somehow_captured = SELECT last_value from #{table}_id_seq
  IF (somehow_captured == 1) THEN
    == restore initial unique identifier column value here ==
  END

  IF (somehow_captured > 1) THEN
    TRUNCATE TABLE #{table};
  END IF;
END$$;

Манипулируя этим кодом в различных аспектах, я не мог заставить его работать, потому что не знаком с функциями и блоками (и переменными) PostgreSQL.

Также я предполагаю, что EXISTS(SELECT something FROM TABLE) можно было бы каким-то образом использовать для хорошей работы в качестве одного из блоков «процедуры проверки», из которого должна состоять процедура очистки, но я этого не сделал.

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

ОБНОВИТЬ:

Все это мне нужно для запуска модульных и интеграционных тестов для проектов Ruby или Ruby on Rails. Каждый тест должен иметь чистую БД перед запуском или выполнять очистку после себя (т.н. разрыв). Транзакции — это очень хорошо, но они становятся непригодными для использования при тестировании определенных веб-драйверов, в моем случае необходимо переключиться на стратегию усечения. После того, как я обновил это со ссылкой на RoR, пожалуйста, не размещайте здесь ответы на тему «Очевидно, вам нужен DatabaseCleaner для PG» и так далее и тому подобное.

ОБНОВЛЕНИЕ 2:

Описанная здесь стратегия недавно была объединена с DatabaseCleaner, https://github.com/bmabey/database_cleaner как Опция :pre_count (см. README).


person Stanislav Pankevich    schedule 03.07.2012    source источник
comment
Меня интересуют самые быстрые решения из возможных. Отключить носитель? А если серьезно, чего именно вы пытаетесь достичь? Если это атомарность, выполняйте свои операции внутри транзакции.   -  person eggyal    schedule 03.07.2012
comment
Собственно, для запуска тестов. Эта процедура в основном будет служить в качестве хука перед или хуком разрыва для каждой выполняемой интеграции Capybara Ruby on Rails.   -  person Stanislav Pankevich    schedule 03.07.2012
comment
Почему усечение каждой таблицы происходит медленно? Пустые таблицы не займут много времени для усечения в Postgres (намного быстрее, чем подсчет строк раньше)   -  person a_horse_with_no_name    schedule 03.07.2012
comment
@a_horse_with_no_name, ваши утверждения очень короткие и твердые! Я надеялся, что мой вопрос заслуживает более подробного изложения. Не могли бы вы как-нибудь опубликовать здесь ссылку на официальную документацию или какие-нибудь тесты производительности. Как я могу полагаться на то, что вы мне говорите, публикуя это в коротких комментариях. Извините, если я вряд ли неправильно понимаю некоторые основы PG, но особенно тогда было бы неплохо получить хороший подробный ответ, написанный вами.   -  person Stanislav Pankevich    schedule 03.07.2012
comment
Это задокументировано в руководстве. Смотри мой ответ   -  person a_horse_with_no_name    schedule 03.07.2012
comment
Вы уже исключили транзакционный подход, который оказался очень быстрым в этом связанном вопросе. Это также полезно для чтения, потому что в нем упоминаются дополнительные параметры, такие как fsync, full_page_writes и RAM-диск.   -  person Erwin Brandstetter    schedule 16.07.2012


Ответы (5)


PostgreSQL может обрезать множество таблиц одним оператором TRUNCATE TABLE. Не утруждайте себя повторением и просто делайте

TRUNCATE TABLE table1,table2,table3,...,table30;
person Daniel Vérité    schedule 03.07.2012
comment
Опыт MySQL показывает мне, что два правильных выбора и одна основная функция mysql делают это намного быстрее, чем аналогичный запуск усечения. Я знал, что большинство ответов будут похожи на ваши, когда писал это. - person Stanislav Pankevich; 03.07.2012
comment
@Stanislaw: как именно правый выбор удаляет строки из таблицы? - person a_horse_with_no_name; 03.07.2012
comment
На самом деле я использую это множественное выражение усечения, подобное вашему, как отправную точку, чтобы начать настройку. - person Stanislav Pankevich; 03.07.2012
comment
@Stanislaw: не утруждайте себя проверкой, содержат ли таблицы строки в PostgreSQL. Это ничего не ускорит. - person a_horse_with_no_name; 03.07.2012
comment
@a_horse_with_no_name, извините, я забыл добавить, что они служат условием, по которому запускается усечение. Если условие не выполняется, усечение просто не запускается, в этом случае я вручную сбрасываю AUTO_INCREMENT. Я покажу это чуть позже. Поскольку SO ведет себя так, могут внезапно появиться некоторые блестящие решения. Я задал этот вопрос, надеясь, что они сделают. - person Stanislav Pankevich; 03.07.2012
comment
@Stanislaw: зачем сбрасывать AUTO_INCREMENT (или эквивалент PostgreSQL), когда вы не усекаете таблицу? Это определенно создаст проблемы со следующим сгенерированным идентификатором. Чем больше вы объясняете, тем более запутанными становятся вещи (по крайней мере, для меня). - person a_horse_with_no_name; 03.07.2012
comment
давайте продолжим обсуждение в чате - person Stanislav Pankevich; 03.07.2012
comment
@Stanislaw: какие бы предостережения TRUNCATE в MySQL ни были (а некоторые из них есть в соответствии с документацией и в зависимости от версии), у него нет причин быть такими же с PostgreSQL. Все DBM имеют свои особенности. Ваше утверждение № 1 о том, что усечение всего будет слишком медленным, необоснованно. - person Daniel Vérité; 03.07.2012
comment
Я не настаиваю на этом. Опять же, я вас спрашиваю, вы действительно пытались сделать это быстрее, или вы продвигаете здесь очень вероятный и, следовательно, определенный дефолт. Почему-то все эти единственные и единственные усеченные {таблицы} звучат для меня неубедительно. В любом случае, если я полностью ошибаюсь, мы могли бы просто подождать еще некоторое время. Или, может быть, среди авторов комментариев есть разработчики ядра PG - скажите погромче, пожалуйста! - person Stanislav Pankevich; 03.07.2012
comment
Mysql не позволяет использовать несколько таблиц таким образом - person Barry; 19.07.2016

Смотрите также:

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

для обсуждения того, почему усечение может быть медленнее на Pg и почему DELETE — это не одно и то же.

person Craig Ringer    schedule 14.07.2012

В соответствии с просьбой в комментарии
(хотя я не думаю, что это правильный ответ, но он слишком длинный для комментария)

Нет (заметной) разницы в производительности между усечением пустой таблицы и усечением большой таблицы.

Как указано в руководстве (http://www.postgresql.org/docs/current/static/sql-truncate.html), "фактически он не сканирует таблицы"

Поэтому, если вы сначала проверите, есть ли в таблице строки, вы проверите таблицу. Что-то, чего не произойдет, если вы просто выдадите truncate, не беспокоясь о том,

person a_horse_with_no_name    schedule 03.07.2012

[Я не знаю РоР]

Хороший способ начать с чистого листа — создать и использовать временную СХЕМУ:

DROP SCHEMA fuzz CASCADE;
CREATE SCHEMA fuzz;
SET search_path='fuzz';

(это то, что я использую для тестирования фрагментов sql). Но это создаст пустую схему, и вы не можете копировать схемы, IFAIK.

Другой способ — создать базу данных (включая пустые таблицы) и использовать ее в качестве шаблона для построения тестовой установки:

DROP DATABASE testdb;
CREATE DATABASE testdb TEMPLATE my_spcial_template;

Проблема в том, что вы не можете удалить базу данных, если к ней все еще есть подключения (например, сам процесс удаления). Таким образом, ваш интерфейс должен сначала отключиться, а затем временно подключиться к какой-либо другой БД (например, my_spcial_template) , чем dropdb+createdb, чем подключить testdb. Я не знаю о производительности, но, по крайней мере, это надежная схема.

person wildplasser    schedule 04.07.2012
comment
Спасибо за предложение. Я не могу его использовать, потому что мне нужно иметь возможность пропустить и, таким образом, сохранить любую из заданных таблиц при запуске тестов. - person Stanislav Pankevich; 13.07.2012
comment
Пропустил ваш ответ и только что опубликовал аналогичный. Удалил как дубль. База данных шаблонов тоже была бы моей первой идеей. - person Erwin Brandstetter; 16.07.2012
comment
@Stanislaw: Вы можете чередовать две (или более) базы данных для своих тестов. Когда вам нужно сохранить таблицу, вы можете скопировать содержимое с помощью dblink, что тоже довольно быстро. Это также устранит необходимость подключения к другой базе данных, прежде чем вы сможете DROP / CREATE. - person Erwin Brandstetter; 16.07.2012
comment
Проблема в том, что эти молодые приложения слишком заняты скоростью и производительностью ;-) - person wildplasser; 16.07.2012
comment
@wildplasser: Назовите меня юношей, но я и сам не против небольшого выступления. :) То есть - пока раствор твердый. - person Erwin Brandstetter; 16.07.2012
comment
Проблема в том, что я не хочу сравнивать это, но я чувствую, что DROP + CREATE (с использованием настроенного шаблона) будет стоить одну (возможно, несколько) секунд. Это решает все проблемы с предварительно заполненными таблицами, последовательностями, правами доступа и т. д. - person wildplasser; 16.07.2012

Если кого-то интересует текущая стратегия, которую я использую для этого, см. этот репозиторий на основе Ruby https://github.com/stanislaw/truncate-vs-count для MySQL и PostgreSQL.

Мои результаты:

MySQL: самая быстрая стратегия очистки баз данных — усечение со следующими модификациями:

if table is not empty
  truncate. 
else 
  if AUTO_INCREMENT is not 0
    truncate.
  end
end
  • Для MySQL просто усечение намного быстрее, чем просто удаление. Единственный случай, когда DELETE побеждает TRUNCATE, это выполнение на пустой таблице.
  • Для MySQL усечение с пустыми проверками намного быстрее, чем просто многократное усечение.
  • Для MySQL удаление с пустыми проверками намного быстрее, чем просто DELETE для каждой таблицы.

PostgreSQL: самая быстрая стратегия очистки баз данных — удаление с теми же пустыми проверками, что и для MySQL, но вместо этого полагаться на currval:

if table is not empty
  delete table
else 
  if currval is not 0
    delete table
  end
end
  • Для PostgreSQL просто удаление выполняется намного быстрее, чем просто ОБРЕЗ (даже многократное).
  • Для PostgreSQL несколько TRUNCATE, выполняющих пустые проверки перед, немного быстрее, чем просто несколько TRUNCATE.
  • Для PostgreSQL удаление с пустыми проверками происходит немного быстрее, чем просто удаление PostgreSQL.

Вот с чего все началось: https://github.com/bmabey/database_cleaner/issues/126< /а>

Это код результата и долгое обсуждение: https://github.com/bmabey/database_cleaner/pull/ 127

Это обсуждение списка рассылки pgsql-performance: http://archives.postgresql.org/pgsql-performance/2012-07/msg00047.php

Мы начали собирать отзывы пользователей, доказывая, что моя идея с первой проверкой пустых таблиц верна.

person Stanislav Pankevich    schedule 13.07.2012