1

PostgreSQLでこの種のタスクを実行するための最速の方法は何でしょうか。可能な限り最速のソリューションに興味があります。

私は自分自身がMySQLのためのそのような種類のソリューションであることに気づきました。それは、テーブルを1つずつ切り捨てるよりもはるかに高速に実行されます。しかしとにかく、私は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)は、「チェック手順」ユニットの1つとしてうまく機能するために使用できると思いました。クリーニング手順は構成されているはずですが、まだ達成されていません。

この手順をPostgreSQLネイティブの方法で実行する方法についてのヒントをいただければ幸いです。

アップデート:

RubyまたはRubyonRailsプロジェクトのユニットテストと統合テストを実行するには、これらすべてが必要です。各テストには、実行前にクリーンなDBが必要です。または、テスト自体の後にクリーンアップ(いわゆるティアダウン)を実行する必要があります。トランザクションは非常に優れていますが、特定のWebドライバーに対してテストを実行すると使用できなくなります。私の場合、切り捨て戦略への切り替えが必要です。RoRを参照して更新した後は、「明らかに、PG用のDatabaseCleanerが必要です」などの回答をここに投稿しないでください。

更新2:

ここで説明する戦略は、最近、DatabaseCleaner、https://github.com/bmabey/database_cleanerに:pre_countオプションとしてマージされました(READMEを参照)。

4

5 に答える 5

3

PostgreSQLは、1つの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はわかりません]

クリーンな状態から始めるための良い方法は、一時スキーマを作成して使用することです。

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

(これは私がSQLスニペットをテストするために使用するものです)。ただし、これにより空のスキーマが作成され、スキーマ、IFAIKをコピーすることはできません。

もう1つの方法は、データベース(空のテーブルを含む)を作成し、それをテストリグを構築するためのテンプレートとして使用することです。

DROP DATABASE testdb;
CREATE DATABASE testdb TEMPLATE my_spcial_template;

それに関する問題は、データベースへの接続(ドロッププロセス自体など)がまだある場合はデータベースをドロップできないことです。したがって、フロントエンドは、他のDB(などmy_spcial_template)に一時的に接続するのではなく、最初に切断する必要があります。 dropdb + createdbよりも、testdbに接続するよりも。パフォーマンスについてはわかりませんが、少なくとも堅牢なスキームです。

于 2012-07-04T11:21:16.363 に答える
1

誰かが現在の戦略に興味がある場合は、これを使用します。MySQLとPostgreSQLの両方について、このRubyベースのリポジトリhttps://github.com/stanislaw/truncate-vs-countを参照してください。

私の結果:

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

最初に空のテーブルをチェックすることで私のアイデアが正しいことを証明するユーザーフィードバックの収集を開始しました。

于 2012-07-13T08:02:43.903 に答える