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

PostgreSQLでのキャッシング

    キャッシング…!!、1つの記事で簡単に説明するのは少し難しいです。しかし、 Heikki / Robert Haas / Bruce Momjianから学んだ私の知識を共有しようとします 要するに。 PostgreSQLには、PG共有バッファーとOSページキャッシュの2つのレイヤーがあり、読み取り/書き込みはすべてOSキャッシュを通過する必要があります(これまでバイパスはありません)。 PostgresはOSページキャッシュにデータを書き込み、ディスクに書き込んだときにユーザーに確認します。その後、OSキャッシュは自分のペースで物理ディスクに書き込みます。 PG共有バッファはOSページキャッシュを制御できず、OSキャッシュに何があるかさえわかりません。そのため、Postgres DBA / Professionalが提供する推奨事項のほとんどは、より高速なDISK/より優れたキャッシュを備えています。

    PostgreSQLのキャッシュ/バッファは、他のデータベースと同様に強力で、高度に洗練されています。オラクルのバックグラウンド(マインドセットも…:))からのように、データベースバッファキャッシュ、固定バッファ、データベースバッファキャッシュのフラッシュ、データベースのプリロードなどに関して、どのように、いつ、何を、なぜかなどを学びました。私は彼らからすべての答えを得ました、しかし、アプローチは少し異なります。私の質問はバグだらけでしたが、彼らは非常に忍耐強く答え、私をかなり明確にしてくれたので、結果としてあなたはこのブログを読んでいます…。 :) ..

    いくつかの学習(まだ学習中)について、Postgresのメモリからディスクへのデータフローと、 Robert Haas(pg_prewarm)によるいくつかの重要なツールと新しいパッチの概要を描きました。 。

    pg_buffercache
    PostgreSQLバッファキャッシュの内容を通知するcontribモジュール。以下のインストール:-

    postgres=# CREATE EXTENSION pg_buffercache;

    pgfincore
    OSページキャッシュ内のデータに関する情報を提供する機能があります。 Pgfincore、モジュールはpg_buffercacheと組み合わせて使用​​すると非常に便利になり、PGバッファキャッシュとOSページキャッシュの情報を一緒に取得できるようになりました。 CerdicVillemainに感謝します。 Pgfincore、バックボーンはfadvise、fincoreはLinuxftoolsです。 sourceをインストールしてfincore/fadviseを使用することもできます。 2つは、pgfincorecontribモジュールまたはftoolsを使用して両方の結果が同じになることです。私は両方を試しました、彼らは単に素晴らしいです。

    Installation:
    Download the latest version: http://pgfoundry.org/frs/download.php/3186/pgfincore-v1.1.1.tar.gz
    As root user:
    export PATH=/usr/local/pgsql91/bin:$PATH //Set the path to point pg_config.
    tar -xvf pgfincore-v1.1.1.tar.gz
    cd pgfincore-1.1.1
    make clean
    make
    make install

    Now connect to PG and run below command

    postgres=# CREATE EXTENSION pgfincore;

    pg_prewarm
    リレーション/インデックスをPGバッファキャッシュにプリロードします。 PostgreSQLで可能ですか?はい、 Robert Haasに感謝します 、最近コミュニティにパッチを提出した人は、PG9.2またはPG9.3で利用できるようになることを願っています。ただし、PG9.1でのテストにパッチを使用できます。

    pg_prewarmには3つのモードがあります:

    1. プリフェッチ: データブロックを非同期でOSキャッシュにフェッチし、PGバッファにはフェッチしません(OSキャッシュのみにヒットします)
    2. 読む: すべてのブロックをダミーバッファに読み込み、OSキャッシュに強制します。 (OSキャッシュのみにヒットします)
    3. バッファ: すべてのブロックまたはブロックの範囲をデータベースバッファキャッシュに読み込みます。

    インストール:
    PGソースインストールにpg_prewarmパッチを適用しています。セットアップに従って、微調整する必要があります。

    1. PGソースのUntarロケーション:/usr/local/src/postgresql-9.1.3
    2. PGインストール場所:/ usr / local / pgsql91
    3. すべてのダウンロード場所:/ usr / local / src

    注:pg_prewarmパッチを適用する前にPGをインストールしてください。

    1.パッチを/usr/ local /src/の場所にダウンロードします
    http://archives.postgresql.org/pgsql-hackers/2012-03/binRVNreQMnK4.bin
    添付メールのパッチ:
    http://archives.postgresql.org/message-id/CA+TgmobRrRxCO+t6gcQrw_dJw+Uf9ZEdwf9beJnu+RB5TEBjEw@mail.gmail.com
    2。ダウンロード後、PGソースの場所に移動し、手順に従います。

    # cd /usr/local/src/postgresql-9.1.3
    # patch -p1 < ../pg_prewarm.bin         (I have renamed after download)
    # make -C contrib/pg_prewarm
    # make -C contrib/pg_prewarm install

    3.上記のコマンドは、$ PGPATH / contrib/extensionの下にファイルを作成します。これで、contribモジュールを追加する準備が整いました。

    postgres=# create EXTENSION pg_prewarm;
    CREATE EXTENSION
    postgres=# dx
    List of installed extensions
    Name | Version | Schema | Description
    ----------------+---------+------------+----------------------------------------
    pg_buffercache | 1.0 | public | examine the shared buffer cache
    pg_prewarm | 1.0 | public | prewarm relation data
    pgfincore | 1.1.1 | public | examine and manage the os buffer cache
    plpgsql | 1.0 | pg_catalog | PL/pgSQL procedural language
    (4 rows)

    Documentation:
    /usr/local/src/postgresql-9.1.3/doc/src/sgml
    [root@localhost sgml]# ll pgpre*
    -rw-r--r-- 1 root root 2481 Apr 10 10:15 pgprewarm.sgml

    dstat
    vmstat、iostat、netstat、topなどのツールを1つの「dstat」Linuxコマンドに組み合わせたもの。データベースが異常に動作する場合、OSレベルから原因を知るために、いくつかの端末を開いて、プロセス、メモリ、ディスクの読み取り/書き込み、ネットワーク情報をプルします。これは、ウィンドウ間でシャッフルするのに少し苦労します。そのため、dstatにはサーバーオプションがあり、すべてのコマンドを1つの出力1つのウィンドウに表示するのに役立ちます。

    Installation:
    Dstat download link: (RHEL 6)
    wget http://pkgs.repoforge.org/dstat/dstat-0.7.2-1.el6.rfx.noarch.rpm
    or
    yum install dstat
    Documentation: http://dag.wieers.com/home-made/dstat/

    Linux ftools
    mincore、fallocate、fadviseなどの最新のLinuxシステムコールで動作するように設計されています。Ftoolsは、OSキャッシュにあるファイルを把握するのに役立ちます。 perl / pythonスクリプトを使用すると、オブジェクトファイル(pg_class.relfilenode)のOSページキャッシュ情報を取得できます。 pg_fincoreはこれに基づいています。 pgfincoreまたはftoolsスクリプトを使用できます。

    Installation:
    Download the tar.gz from the link.
    https://github.com/david415/python-ftools

    cd python-ftools
    python setup.py build
    export PYTHONPATH=build/lib.linux-x86_64-2.5
    python setup.py install

    Note: You need to have python & psycopg2 installed before installing python-ftools.

    これで、ツールとユーティリティを確認するための例に進む準備が整いました。私の例では、テーブルがあり、100MB以上のデータを含む1つのインデックスとシーケンスがあります。

    postgres=# d+ cache
    Table "public.cache"
    Column | Type | Modifiers | Storage | Description
    --------+---------+-----------------------------------------+----------+-------------
    name | text | | extended |
    code | integer | | plain |
    id | integer | default nextval('icache_seq'::regclass) | plain |
    Indexes:
    "icache" btree (code)
    Has OIDs: no

    テーブル、シーケンス、およびそのインデックスが占めるサイズを知るためにクエリを実行します。

    postgres=# SELECT c.relname AS object_name,
    CASE when c.relkind='r' then 'table'
    when c.relkind='i' then 'index'
    when c.relkind='S' then 'sequence'
    else 'others'
    END AS type,pg_relation_size(c.relname::text) AS size, pg_size_pretty(pg_relation_size(c.relname::text)) AS pretty_size
    FROM pg_class c
    JOIN pg_roles r ON r.oid = c.relowner
    LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
    WHERE (c.relkind = ANY (ARRAY['r'::"char", 'i'::"char", 'S'::"char",''::"char"])) AND n.nspname = 'public';

    object_name | type | size | pretty_size
    -------------+----------+----------+-------------
    icache_seq | sequence | 8192 | 8192 bytes
    cache | table | 83492864 | 80 MB
    icache | index | 35962880 | 34 MB
    (3 rows)

    Total object size 'cache'

    postgres=# select pg_size_pretty(pg_total_relation_size('cache'));
    pg_size_pretty
    ----------------
    114 MB
    (1 row)

    pgfincoreとpg_buffercacheをクラブして、PGバッファーとOSページのキャッシュから情報を取得することで小さなクエリを作成しました。このクエリの出力のみを貼り付けて、例全体でこのクエリを使用します。

    select rpad(c.relname,30,' ') as Object_Name,
    case when c.relkind='r' then 'Table' when c.relkind='i' then 'Index' else 'Other' end as Object_Type,
    rpad(count(*)::text,5,' ') as "PG_Buffer_Cache_usage(8KB)",
    split_part(pgfincore(c.relname::text)::text,','::text,5) as "OS_Cache_usage(4KB)"
    from pg_class c inner join pg_buffercache b on b.relfilenode=c.relfilenode
    inner join pg_database d on (b.reldatabase=d.oid and d.datname=current_database() and c.relnamespace=(select oid from pg_namespace where nspname='public'))
    group by c.relname,c.relkind
    order by "PG_Buffer_Cache_usage(8KB)"
    desc limit 10;

    object_name | object_type | PG_Buffer_Cache_usage(8KB) | OS_Cache_usage(4KB)
    -------------+-------------+----------------------------+---------------------
    (0 rows)

    Note: I have bounced the cluster to flush PG buffers & OS Page Cache. So, no data in any Cache/buffer.

    pg_prewarmを使用したリレーション/インデックスのプリロード:
    クラスターをバウンスする前に、「キャッシュ」テーブルに対してフルテーブルシーケンシャルスキャンクエリを実行し、リレーション/インデックスをウォームアップする前の時間を記録しました。

    postgres=# explain analyze select * from cache ;
    QUERY PLAN
    ------------------------------------------------------------------------------------------------------------------
    Seq Scan on cache (cost=0.00..26192.00 rows=1600000 width=19) (actual time=0.033..354.691 rows=1600000 loops=1)
    Total runtime: 427.769 ms
    (2 rows)

    pg_prewarmを使用してリレーション/インデックス/シーケンスをウォームし、クエリプランを確認します。

    postgres=# select pg_prewarm('cache','main','buffer',null,null);
    pg_prewarm
    ------------
    10192
    (1 row)
    postgres=# select pg_prewarm('icache','main','buffer',null,null);
    pg_prewarm
    ------------
    4390
    (1 row)

    Output of combined buffers:
    object_name | object_type | PG_Buffer_Cache_usage(8KB) | OS_Cache_usage(4KB)
    -------------+-------------+----------------------------+---------------------
    icache | Index | 4390 | 8780
    cache | Table | 10192 | 20384
    (2 rows)

    pgfincore出力:

    postgres=# select relname,split_part(pgfincore(c.relname::text)::text,','::text,5) as "In_OS_Cache" from pg_class c where relname ilike '%cache%';
    relname | In_OS_Cache
    ------------+-------------
    icache_seq | 2
    cache | 20384
    icache | 8780
    (3 rows)

    or for each object.

    postgres=# select * from pgfincore('cache');
    relpath | segment | os_page_size | rel_os_pages | pages_mem | group_mem | os_pages_free | databit
    ------------------+---------+--------------+--------------+-----------+-----------+---------------+---------
    base/12780/16790 | 0 | 4096 | 20384 | 20384 | 1 | 316451 |
    (1 row)

    python-ftoolsスクリプトを使用して同様の情報を取得するには、オブジェクトのrelfilenode番号を知る必要があります。以下を確認してください。

    postgres=# select relfilenode,relname from pg_class where relname ilike '%cache%';
    relfilenode | relname
    -------------+----------------
    16787 | icache_seq /// you can exclude sequence.
    16790 | cache /// table
    16796 | icache /// index
    (3 rows)

    python-ftoolsスクリプトを使用する

    面白くないですか…。!!!!。
    テーブルをバッファに温めた後、説明プランを比較してください。

    postgres=# explain analyze select * from cache ;
    QUERY PLAN
    ------------------------------------------------------------------------------------------------------------------
    Seq Scan on cache (cost=0.00..26192.00 rows=1600000 width=19) (actual time=0.016..141.804 rows=1600000 loops=1)
    Total runtime: 215.100 ms
    (2 rows)

    OSキャッシュのリレーション/インデックスをフラッシュ/プリウォームする方法は?
    pgfadviseを使用すると、OSキャッシュからリレーションをプリロードまたはフラッシュできます。詳細については、pgfadviseに関連するすべての機能について、ターミナルにdfpgfadvise*と入力してください。以下は、OSキャッシュをフラッシュする例です。

    postgres=# select * from pgfadvise_dontneed('cache');
    relpath | os_page_size | rel_os_pages | os_pages_free
    ------------------+--------------+--------------+---------------
    base/12780/16790 | 4096 | 20384 | 178145
    (1 row)
    postgres=# select * from pgfadvise_dontneed('icache');
    relpath | os_page_size | rel_os_pages | os_pages_free
    ------------------+--------------+--------------+---------------
    base/12780/16796 | 4096 | 8780 | 187166
    (1 row)
    postgres=# select relname,split_part(pgfincore(c.relname::text)::text,','::text,5) as "In_OS_Cache" from pg_class c where relname ilike '%cache%';
    relname | In_OS_Cache
    ------------+-------------
    icache_seq | 0
    cache | 0
    icache | 0
    (3 rows)

    これらのことが1つのウィンドウで行われている間、dstatを使用して読み取り/書き込み比率を確認できます。その他のオプションについては、dstat –list
    dstat -s –top-io –top-bio –top-mem

    を使用してください。

    pg_prewarm範囲機能を使用してブロックの範囲をプリロードします。
    何らかの理由でクラスターをバウンスしたいが、バッファー内にある大きなテーブルの1つが正常に機能していると仮定します。バウンス時に、テーブルがバッファに存在しなくなり、バウンス前の元の状態に戻るには、バッファに存在するテーブルブロックの数を確認し、pg_prewarmrangeオプションを使用してそれらをプリロードする必要があります。

    pg_buffercacheを照会してテーブルを作成し、後でブロック範囲情報をpg_prewarmに送信しました。これにより、共有バッファは以前にロードされたテーブルに戻ります。例を参照してください。

    select c.relname,count(*) as buffers from pg_class c 
    inner join pg_buffercache b on b.relfilenode=c.relfilenode and c.relname ilike '%cache%'
    inner join pg_database d on (b.reldatabase=d.oid and d.datname=current_database())
    group by c.relname
    order by buffers desc;
    relname | buffers
    ---------+---------
    cache | 10192
    icache | 4390
    (2 rows)
    Note: These are the blocks in buffer.

    postgres=# create table blocks_in_buff (relation, fork, block) as select c.oid::regclass::text, case b.relforknumber when 0 then 'main' when 1 then 'fsm' when 2 then 'vm' end, b.relblocknumber from pg_buffercache b, pg_class c, pg_database d where b.relfilenode = c.relfilenode and b.reldatabase = d.oid and d.datname = current_database() and b.relforknumber in (0, 1, 2);
    SELECT 14716

    クラスタをバウンスし、テーブルに関連するブロックの範囲を「blocks_in_buff」からバッファにプリロードします。

    postgres=# select sum(pg_prewarm(relation, fork, 'buffer', block, block)) from blocks_in_buff;
    sum
    -------
    14716
    (1 row)

    postgres=# select c.relname,count(*) as buffers from pg_class c
    inner join pg_buffercache b on b.relfilenode=c.relfilenode and c.relname ilike '%cache%'
    inner join pg_database d on (b.reldatabase=d.oid and d.datname=current_database())
    group by c.relname
    order by buffers desc;
    relname | buffers
    ---------+---------
    cache | 10192
    icache | 4390
    (2 rows)

    ほら、私のshared_bufferが復活しました。

    楽しみ…!!!もっと面白いもので戻ってきます。コメントを投稿してください。


    1. PostgreSQLでテーブルのリスト列名とデータ型を取得するにはどうすればよいですか?

    2. 例外が発生した場合のOracleでの挿入の継続

    3. Postgres9.4でJSONBタイプの列に対して更新操作を実行する方法

    4. SQLServer2008および2008R2のサポートの終了