1

我想知道,在 PostgreSQL 中完成此类任务的最快方法是什么。我对最快的解决方案感兴趣。

我发现自己有这样一种 MySQL 解决方案,它的执行速度比一张一张地截断表要快得多。但无论如何,我也对最快的 MySQL 解决方案感兴趣。在这里查看我的结果,当然它仅适用于 MySQL:https ://github.com/bmabey/database_cleaner/issues/126

我有以下假设:

  • 我有 30-100 张桌子。让他们30岁。
  • 一半的桌子是空的。
  • 例如,每个非空表的行数不超过 100 行。我的意思是,桌子并不大。
  • 我需要一个可选的可能性来从这个过程中排除 2 个或 5 个或 N 个表。

  • 我不能!使用事务。

对于在 PostgreSQL 8 和 9 上工作的这种情况,我需要最快的清理策略。

我看到以下方法:

  1. 截断每个表。我认为这太慢了,尤其是对于空桌子。

  2. 用更快的方法检查每个表是否为空,如果为空,则将其唯一标识符列(类似于 MySQL 中的 AUTO_INCREMENT)重置为初始状态(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 项目运行单元和集成测试。每个测试在运行之前都应该有一个干净的数据库,或者在其自身之后进行清理(所谓的拆卸)。事务非常好,但是在针对特定 web 驱动程序运行测试时它们变得不可用,在我的情况下,需要切换到截断策略。一旦我参考 RoR 进行了更新,请不要在此处发布有关“显然,您需要 DatabaseCleaner for PG”等的答案。

更新 2:

最近这里描述的策略被合并到 DatabaseCleaner,https ://github.com/bmabey/database_cleaner 作为 :pre_count 选项(参见那里的自述文件)。

4

5 回答 5

3

PostgreSQL 可以在一条TRUNCATE TABLE语句中截断许多表。不要打扰迭代,只需做

TRUNCATE TABLE table1,table2,table3,...,table30;
于 2012-07-03T12:50:13.163 回答
2

也可以看看:

Postgresql 截断速度

讨论为什么在 Pg 上截断会变慢,以及为什么 DELETE 不是一回事。

于 2012-07-14T09:22:01.100 回答
1

按照评论中的要求
(虽然我觉得这不是正确的答案 - 但评论太长了)

截断空表或截断大表之间没有(明显的)性能差异。

如手册中所述(http://www.postgresql.org/docs/current/static/sql-truncate.html)“它实际上并不扫描表

因此,如果您首先检查表中是否有任何行,您扫描该表。如果您只是发布truncate而不考虑是否

于 2012-07-03T13:28:17.483 回答
1

[我不知道ROR]

一个从零开始的好方法是创建和使用临时 SCHEMA:

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。我不知道性能,但至少它是一个强大的方案。

于 2012-07-04T11:21:16.363 回答
1

如果有人对当前策略感兴趣,我会使用此策略,请参阅此基于 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,仅删除比仅 TRUNCATION(甚至多个)快得多。
  • 对于 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

我们开始收集用户反馈,证明我的想法是先检查空表是正确的。

于 2012-07-13T08:02:43.903 回答