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

PostgreSQLでのVACUUM処理の概要

    PostgreSQLはIN-PLACE更新メカニズムを使用しないため、DELETEおよびUPDATEコマンドの設計方法に従って

    • DELETE操作が実行されるたびに、既存のタプルを物理的に削除するのではなく、DEADとしてマークします。
    • 同様に、UPDATE操作が実行されるたびに、対応する既存のタプルをDEADとしてマークし、新しいタプルを挿入します(つまり、UPDATE操作=DELETE + INSERT)。

    したがって、各DELETEおよびUPDATEコマンドは、1つのDEADタプルになります。これは、(並列トランザクションがない限り)使用されることはありません。これらのデッドタプルは、有効なレコードの数が同じかそれより少ない場合でも、不要な余分なスペースの使用につながります。これは、PostgreSQLではスペースの肥大化とも呼ばれます。 PostgreSQLはOLTPの一種のリレーショナルデータベースシステムとして広く使用されており、INSERT、UPDATE、およびDELETE操作が頻繁に実行されるため、多くのDEADタプルが発生し、それに対応する結果が生じます。そのため、PostgreSQLには、これらのDEADタプルを処理するための強力なメンテナンスメカニズムが必要でした。 VACUUMは、VACUUMの動作を最適化するのに役立ついくつかのアクティビティとともに、DEADタプルの処理を処理するメンテナンスプロセスです。このブログの後半で使用されるいくつかの用語を理解しましょう。

    可視性マップ

    名前が示すように、すべてのアクティブなトランザクションに表示されることがわかっているタプルのみを含むページに関する表示情報を維持します。ページごとに、1ビットが使用されます。ビットが1に設定されている場合、対応するページのすべてのタプルが表示されていることを意味します。ビットを0に設定すると、特定のページに空きスペースがなく、すべてのトランザクションでタプルを表示できることを意味します。

    可視性マップはリレーション(テーブルとインデックス)ごとに維持され、メインのリレーションと一緒に関連付けられます。つまり、リレーションファイルのノード名が12345の場合、可視性ファイルは並列ファイル12345_vmに保存されます。

    空きスペースマップ リレーションで使用可能なスペースに関する詳細を含む空きスペース情報を保持します。これは、リレーションのメインファイルと並列にファイルにも保存されます。つまり、リレーションファイルのノード名が12345の場合、空き領域マップファイルは並列ファイルの12345_fsmに保存されます。

    タプルをフリーズ

    PostgreSQLはトランザクションIDの格納に4バイトを使用します。つまり、ラップアラウンドする前に最大20億のトランザクションを生成できます。ここで、現時点でまだいくつかのタプルに初期トランザクションID(たとえば100)が含まれていることを考慮してください。次に、新しいトランザクション(ラップアラウンドトランザクションを使用)(たとえば5)の場合、トランザクションID 100は将来を調べ、追加されたデータを確認できません。 /実際には過去のものでしたが、それによって変更されました。この特別なトランザクションIDを回避するために、FrozenTransactionId(2に等しい)が割り当てられます。この特別なトランザクションIDは常に過去のものと見なされ、すべてのトランザクションに表示されます。

    VACUUM

    VACUUMの主な仕事は、DEADタプルが占有していたストレージスペースを再利用することです。再利用されたストレージスペースはオペレーティングシステムに戻されるのではなく、同じページ内でデフラグされただけなので、同じテーブル内に将来データを挿入するときに再利用できます。 VACUUM操作が特定のテーブルで行われている間、他のREAD / WRITE操作は、特定のテーブルで排他ロックが取得されないため、同じテーブルで同時に実行できます。テーブル名が指定されていない場合、データベースのすべてのテーブルに対してVACUUMが実行されます。 VACUUM操作は、ShareUpdateExclusiveロック内の一連の操作の下で実行されます:

    • データベースのすべてのテーブル(または指定されたテーブル)のすべてのページをスキャンして、すべてのデッドタプルを取得します。
    • 必要に応じて古いタプルをフリーズします。 それぞれのDEADタプルを指すインデックスタプルを削除します。
    • 特定のテーブルに対応するページのDEADタプルを削除し、ページ内のライブタプルを再割り当てします。
    • 空き領域マップ(FSM)と可視性マップ(VM)を更新します。
    • 可能であれば最後のページを切り捨てます(解放されたDEADタプルがあった場合)。
    • 対応するすべてのシステムテーブルを更新します。

    VACUUMの上記の作業手順からわかるように、リレーションのすべてのページを処理する必要があるため、非常にコストのかかる操作であることは明らかです。したがって、バキュームする必要のない可能性のあるページをスキップすることが非常に必要です。可視性マップ(VM)は、空き領域がない場合に対応するページのバキュームが不要であり、したがってこのページを安全にスキップできるページの情報を提供するためです。

    VACUUMはとにかくすべてのページとそのすべてのタプルをトラバースするため、適格なタプルをフリーズするという他の重要なタスクを実行する機会があります。

    フルバキューム

    前のセクションで説明したように、VACUUMはすべてのDEADタプルを削除し、将来の使用のためにページを最適化しますが、スペースが実際には解放されないため、テーブルの全体的なストレージを削減するのに役立ちません。オペレーティング·システム。合計ストレージが1.5GBに達し、この1GBのうちデッドタプルが占有しているテーブルtbl1を想定すると、VACUUMの後、さらに約1GBがタプルの挿入に使用できるようになりますが、それでも合計ストレージは1.5GBのままになります。

    >

    Full VACUUMは、実際にスペースを解放してオペレーティングシステムに戻すことで、この問題を解決します。しかし、これにはコストがかかります。 VACUUMとは異なり、FULL VACUUMは、FULL VACUUMを取得する関係を排他的にロックするため、並列操作を許可しません。手順は次のとおりです。

      関係を排他的にロックします。 並列の空のストレージファイルを作成します。 すべてのライブタプルを現在のストレージから新しく割り当てられたストレージにコピーします。
    • 次に、元のストレージを解放します。
    • ロックを解除します。

    手順からも明らかなように、残りのデータにのみ必要なストレージがあります。

    自動掃除機

    VACUUMを手動で実行する代わりに、PostgreSQLはVACUUMを定期的に自動的にトリガーするデーモンをサポートしています。 VACUUMがウェイクアップするたびに(デフォルトでは1分)、複数の作業が呼び出されます(構成autovacuum_workerプロセスによって異なります)。

    自動バキュームワーカーは、指定されたそれぞれのテーブルに対して同時にVACUUMプロセスを実行します。 VACUUMはテーブルを排他的にロックしないため、他のデータベース作業に影響を与えません(または最小限に抑えます)。

    Auto-VACUUMの構成は、データベースの使用パターンに基づいて行う必要があります。頻度が高すぎたり(死んだタプルがないか少なすぎたりするため、作業者のウェイクアップが無駄になるため)、または遅延しすぎないようにする必要があります(死んだタプルが多数一緒になり、テーブルが肥大化する原因になります)。

    VACUUMまたはFullVACUUM

    理想的には、データベースアプリケーションは、全真空を必要としないように設計する必要があります。上で説明したように、FULL VACUUMはストレージスペースを再作成してデータを元に戻すため、デッドタプルが少ない場合は、すぐにストレージスペースが再作成され、すべての元のデータが元に戻されます。また、FULL VACUUMはテーブルを排他的にロックするため、対応するテーブルのすべての操作をブロックします。そのため、FULL VACUUMを実行すると、データベース全体の速度が低下する場合があります。

    要約すると、ストレージスペースの大部分が死んだタプルによるものであることがわかっていない限り、完全なVACUUMは避ける必要があります。 PostgreSQL拡張機能pg_freespacemapを使用して、空き領域に関する公正なヒントを得ることができます。

    説明されたVACUUMプロセスの例を見てみましょう。

    まず、テーブルデモ1を作成しましょう:

    postgres=# create table demo1(id int, id2 int);
    
    CREATE TABLE

    そしてそこにいくつかのデータを挿入します:

    postgres=# insert into demo1 values(generate_series(1,10000), generate_series(1,
    
    10000));
    
    INSERT 0 10000
    
    postgres=# SELECT count(*) as npages, round(100 * avg(avail)/8192 ,2) as average_freespace_ratio FROM pg_freespace('demo1');
    
     npages | average_freespace_ratio
    
    --------+-------------------------
    
      45 |                0.00
    
    (1 row)

    では、データを削除しましょう:

    postgres=# delete from demo1 where id%2=0;
    
    DELETE 5000

    そして手動掃除機を実行します:

    postgres=# vacuum demo1;
    
    VACUUM
    
    postgres=# SELECT count(*) as npages, round(100 * avg(avail)/8192 ,2) as average_freespace_ratio FROM pg_freespace('demo1');
    
     npages | average_freespace_ratio
    
    --------+-------------------------
    
      45 |               45.07
    
    (1 row)

    この空き領域はPostgreSQLで再利用できるようになりましたが、その領域をオペレーティングシステムに解放する場合は、次のコマンドを実行してください:

    postgres=# vacuum full demo1;
    
    VACUUM
    
    postgres=# SELECT count(*) as npages, round(100 * avg(avail)/8192 ,2) as average_freespace_ratio FROM pg_freespace('demo1');
    
     npages | average_freespace_ratio
    
    --------+-------------------------
    
      23 |                0.00
    
    (1 row)

    結論

    そして、これはVACUUMプロセスがどのように機能するかの短い例でした。幸いなことに、自動バキュームプロセスのおかげで、ほとんどの場合、一般的なPostgreSQL環境では、エンジン自体によって管理されているため、これについて考える必要はありません。


    1. Access2016で空白のフォームを作成する方法

    2. PostgreSQLを使用する1つのエンティティ用の複数のHibernateシーケンスジェネレータ

    3. SQLServerで「値をデータ型に変換するときに変換に失敗しました」を修正する方法

    4. パフォーマンスの驚きと仮定:DATEDIFF