sql >> データベース >  >> RDS >> PostgreSQL

Postgresqlの切り捨て速度

    これは最近、SOとPostgreSQLメーリングリストの両方で数回発生しています。

    TL; DR 最後の2つのポイント:

    (a)shared_buffersが大きいことが、CIサーバーでTRUNCATEが遅い理由である可能性があります。異なるfsync構成またはSSDの代わりに回転メディアを使用することも原因である可能性があります。

    (b)TRUNCATE 固定費がかかりますが、必ずしもDELETEより遅いとは限りません。 、さらにそれはより多くの仕事をします。次の詳細な説明を参照してください。

    更新: pgsql-performanceに関する重要な議論は、この投稿から生じました。このスレッドを参照してください。

    更新2: これに役立つ改善が9.2beta3に追加されました。この投稿を参照してください。

    TRUNCATEの詳細な説明 vs DELETE FROM

    このトピックの専門家ではありませんが、私の理解では、TRUNCATE DELETEはテーブルあたりのコストがほぼ固定されていますが、 n行に対して少なくともO(n)です。削除されるテーブルを参照する外部キーがある場合はさらに悪化します。

    私はいつもTRUNCATEの固定費を想定していました DELETEのコストよりも低かった ほぼ空のテーブルにありますが、これはまったく当てはまりません。

    TRUNCATE table; DELETE FROM table;以上のことを行います

    TRUNCATE table後のデータベースの状態 代わりに実行する場合とほとんど同じです:

    • DELETE FROM table;
    • VACCUUM (FULL, ANALYZE) table; (9.0以降のみ、脚注を参照)

    ...もちろんTRUNCATE DELETEでは実際にはその効果を達成しません およびVACUUM

    重要なのは、DELETE およびTRUNCATE 異なることを行うので、同じ結果の2つのコマンドを比較しているだけではありません。

    DELETE FROM table; デッドローとブロートを残すことを許可し、インデックスがデッドエントリを運ぶことを許可し、クエリプランナーによって使用されるテーブル統計を更新しません。

    TRUNCATE まるでCREATEであるかのように完全に新しいテーブルとインデックスを提供します ed。これは、すべてのレコードを削除し、テーブルのインデックスを再作成して、VACUUM FULLを実行したようなものです。 。

    テーブルにクラッドが残っているかどうかを気にしない場合は、DELETE FROM table;を使用した方がよい場合があります。 。

    VACUUMを実行していないため デッドローとインデックスエントリは、スキャンして無視する必要のある肥大化として蓄積されることがわかります。これにより、すべてのクエリが遅くなります。テストで実際に多くのデータが作成および削除されない場合は、気付かない、または気にしない可能性があり、いつでもVACUUMを実行できます。 または、テスト実行の途中で2回実行します。より良いのは、積極的な自動真空設定により、自動真空がバックグラウンドで確実に実行されるようにすることです。

    引き続きTRUNCATE 全体以降のすべてのテーブル テストスイートを実行して、多くの実行で効果が蓄積されないことを確認します。 9.0以降では、VACUUM (FULL, ANALYZE); 世界的には、少なくとも同じくらい良いとは言えませんが、はるかに簡単です。

    IIRC Pgにはいくつかの最適化があります。つまり、テーブルを表示してブロックをすぐに空きとしてマークできるのはトランザクションだけである場合に気付く可能性があります。テストでは、膨張を作成したいとき、それを行うために複数の同時接続が必要でした。しかし、私はこれに頼りません。

    DELETE FROM table; f/k参照のない小さなテーブルには非常に安い

    DELETEへ 外部キー参照のないテーブルからのすべてのレコード。すべてのPgは、順次テーブルスキャンを実行し、xmaxを設定する必要があります。 遭遇したタプルの。これは非常に安価な操作です。基本的に、線形読み取りと半線形書き込みです。 AFAIKは、インデックスに触れる必要はありません。後でVACUUMによってクリーンアップされるまで、死んだタプルを指し続けます。 また、死んだタプルのみを含むテーブル内のブロックを空きとしてマークします。

    DELETE たくさんある場合にのみ高価になります レコードの数、チェックする必要のある外部キー参照がたくさんある場合、または後続のVACUUM (FULL, ANALYZE) table; TRUNCATEと一致する必要があります DELETEのコスト内での効果 。

    ここでの私のテストでは、DELETE FROM table; 通常、TRUNCATEより4倍高速でした 0.5ms対2msで。これはSSD上のテストDBであり、fsync=offで実行されます。 このデータをすべて失ってもかまわないからです。もちろん、DELETE FROM table; はすべて同じ作業を行っているわけではなく、VACUUM (FULL, ANALYZE) table; 21ミリ秒かかるので、DELETE 私が実際にテーブルの手付かずを必要としない場合にのみ勝利です。

    TRUNCATE table; DELETEよりもはるかに多くの固定費の作業とハウスキーピングを行います

    対照的に、TRUNCATE 多くの仕事をしなければなりません。テーブル、TOASTテーブル(存在する場合)、およびテーブルが持つすべてのインデックスに新しいファイルを割り当てる必要があります。ヘッダーはこれらのファイルに書き込む必要があり、システムカタログも更新する必要がある場合があります(その点についてはよくわかりませんが、チェックしていません)。次に、古いファイルを新しいファイルに置き換えるか、古いファイルを削除する必要があります。また、通常はすべてのバッファーをディスクにフラッシュする同期操作(fsync()など)を使用して、ファイルシステムが変更に追いついていることを確認する必要があります。 。 (データを食べる)オプションfsync=offを使用して実行している場合、同期がスキップされるかどうかはわかりません 。

    最近、TRUNCATEであることを知りました また、古いテーブルに関連するすべてのPostgreSQLのバッファをフラッシュする必要があります。これは、巨大なshared_buffersを使用すると、取るに足らない時間がかかる可能性があります。 。これが、CIサーバーで低速になる理由だと思います。

    バランス

    とにかく、TRUNCATE TOASTテーブルが関連付けられているテーブル(ほとんどの場合)といくつかのインデックスには、少し時間がかかる場合があります。長くはありませんが、DELETEより長くなります ほぼ空のテーブルから。

    したがって、DELETE FROM table;を実行した方がよい場合があります。 。

    -

    注:9.0より前のDBでは、CLUSTER table_id_seq ON table; ANALYZE table; またはVACUUM FULL ANALYZE table; REINDEX table; TRUNCATEとほぼ同等になります 。 VACUUM FULL implは9.0ではるかに優れたものに変更されました。



    1. 2つの日付の間のすべての日付を一覧表示する方法

    2. LIKE演算子がSQLiteでどのように機能するか

    3. SQLServerで結果をページ分割するための最良の方法は何ですか

    4. T-SQL日時データ型