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

PostgreSQLクエリのパフォーマンスを理解する

    開発とテストでうまく機能するクエリが本番環境で爆発する理由を理解することは、時には困難な場合があります。クエリが本番環境でどのように機能するかについての洞察を提供できるいくつかの機能の詳細については、以下をお読みください。

    現在実行中のクエリ

    クライアントがPostgreSQLサーバーに接続すると、メインのPostgresサーバープロセス(歴史的には postmaster と呼ばれていました) )新しいプロセス(バックエンドと呼ばれる)を生成します )クライアントのクエリを処理します。したがって、各バックエンドは、クライアントがクエリを送信するのを待っているか、クエリを実行しようとしています。

    システムビューpg_stat_activity 現在実行されているすべてのバックエンドに関する情報を表示します。特に、バックエンドがアクティブな場合は現在実行しているクエリ、またはクライアントが別のクエリを送信するのを待っている場合は最後に実行したクエリを示します。

    データベースtestdbに接続されたクライアントにサービスを提供する2つのバックエンドを次に示します。 、両方とも積極的にクエリを実行しています:

    testdb=# select usename,datname,state,query from pg_stat_activity where datname='testdb';
    -[ RECORD 1 ]-----------------------------------------------------------------------------
    usename | postgres
    datname | testdb
    state   | active
    query   | SELECT pg_sleep(10);
    -[ RECORD 2 ]-----------------------------------------------------------------------------
    usename | postgres
    datname | testdb
    state   | active
    query   | select usename,datname,state,query from pg_stat_activity where datname='testdb';

    クエリがロックを待機している場合があり、これもinpg_stat_activityに表示されます。ここで、リレーションロックを待機しているINSERTを確認できます:

    testdb=# select wait_event_type, wait_event, left(query, 60) from pg_stat_activity where datname='testdb';
    -[ RECORD 1 ]---+-------------------------------------------------------------
    wait_event_type | Client
    wait_event      | ClientRead
    left            | lock table t in access exclusive mode;
    -[ RECORD 2 ]---+-------------------------------------------------------------
    wait_event_type |
    wait_event      |
    left            | select wait_event_type, wait_event, left(query, 60) from pg_
    -[ RECORD 3 ]---+-------------------------------------------------------------
    wait_event_type | Lock
    wait_event      | relation
    left            | insert into t values (1);

    pg_stat_activityの詳細については、ドキュメントを参照してください。

    このビューは、Postgresが現在行っていることを理解するのに役立ちますが、クエリ実行統計に関する情報や、実行が終了したクエリに関する情報は提供しません。

    すべてのクエリは過去に実行されました

    そのために、拡張機能 pg_stat_statements かけがえのないです。この拡張機能はコアPostgreSQLディストリビューションに含まれており、AWSRDSやGCPSQLなどのマネージドサービスでも利用できます。

    pg_stat_statements(PSS)はPostgreSQL用語の「拡張機能」であり、最初にインストールする必要があります:

    • Linuxディストリビューションのドキュメントを参照して、拡張機能がプレインストールされているかどうか、または別のパッケージのインストールが必要かどうかを確認してください。たとえば、Centos 7では、sudo yum install postgresql-contribを実行する必要があります。 。
    • メイン構成ファイルpostgresql.confを編集します(通常は/etcの下にあります 、like /etc/postgresql/10/main/postgresql.conf Debianの場合)、shared_preload_librariesの値を変更します 「pg_stat_statements」に。これは値のコンマ区切りのリストであるため、すでに何かがある場合は、コンマを追加してから「pg_stat_statements」を追加します。
    • AWS RDSの場合、アクティブなパラメータグループを変更して値を設定する必要があります。
    • 「shared_preload_libraries」を編集した後、PostgreSQLデーモンを再起動する必要があります。残念ながら、これを回避する方法はありません。 AWS RDSでは、RDSインスタンスを再起動する必要があります。
    • 再起動後、PostgreSQLサーバーは共有ライブラリをロードし、CREATE EXTENSION pg_stat_statementsを実行して拡張機能をインストールできます。 。このコマンドを実行するには、スーパーユーザーである必要があります。
    • 実際には任意のデータベースに拡張機能をインストールできますが、すべてのデータベースのクエリを表示できます。

    拡張機能がインストールされると、pg_stat_statementsというビューをクエリできます。 拡張機能がインストールされてから実行されたすべてのクエリに関する情報を取得します。

    クエリの実行にかかる時間などの数値は、合計として累積されます。クエリの実行時間のみについて、いくつかの統計(平均、最小、最大、標準偏差)が表示されます。これらの値は、関数pg_stat_statements_resetを使用してクリアできます。 。

    pg_stat_statementsの行は次のとおりです。 次のようになります:

    testdb=# select * from pg_stat_statements where query like '%pg_sleep%' and dbid=42548;
    -[ RECORD 1 ]-------+--------------------
    userid              | 10
    dbid                | 42548
    queryid             | 2649515222348904837
    query               | SELECT pg_sleep($1)
    calls               | 1
    total_time          | 10016.782625
    min_time            | 10016.782625
    max_time            | 10016.782625
    mean_time           | 10016.782625
    stddev_time         | 0
    rows                | 1
    shared_blks_hit     | 0
    shared_blks_read    | 0
    shared_blks_dirtied | 0
    shared_blks_written | 0
    local_blks_hit      | 0
    local_blks_read     | 0
    local_blks_dirtied  | 0
    local_blks_written  | 0
    temp_blks_read      | 0
    temp_blks_written   | 0
    blk_read_time       | 0
    blk_write_time      | 0

    パラメータ(ユーザー、データベース、クエリ)を特定する以外に、クエリに関する多くの興味深いことを理解できます。

    • 通常の実行にかかる時間(mean_time
    • 平均で返される行数(rows /calls
    • 共有バッファキャッシュから読み取られたデータの量、およびディスクから読み取られたデータの量(shared_blks_read クエリが読み取ったデータの合計量を示します。そのうちのshared_blks_hit キャッシュから来ました)
    • キャッシュプレッシャーのためにディスクに同期的に書き込む必要があったデータの量(shared_blks_written
    • タッチされたブロックの数として書き込まれたデータの量(shared_blks_dirtied
    • ディスクの読み取りと書き込みに費やされた時間(blk_{read,write}_time
    • temp_blks_{read,written}に書き込まれ、そこから読み取られる一時ファイル )
    • local_*に書き込まれ、そこから読み取られる一時テーブル )

    ディスクの読み取り時間と書き込み時間は、構成パラメーターtrack_io_timingの場合にのみ使用できます。 オンになっています。デフォルトでは、そうではありません。最近のほとんどのLinuxシステムでは、このパラメーターをオンにしても問題ありません。続きを読む。

    pg_stat_statementsのスナップショットを作成することは価値があります これらのパラメータがクエリごとにどのように傾向を示しているかを確認するために、定期的にデータを継続的に送信します。オープンソースツールのpgmetricsは、pg_stat_statementsを抽出して公開できます。 自動化を容易にするためのJSONとしてのデータ。

    クエリは時間範囲内に実行されます

    このようなシステムを導入すると、特定の時間枠で実行されたクエリを追跡することが容易になります。これにより、夜間のバッチジョブに予想よりも時間がかかった理由などの問題を簡単にデバッグできます。

    指定された2つのタイムスタンプ間のカウンターを差し引くことで、最小、最大、標準偏差を除いて、以前と同じようにほとんどの数値を見つけることができます。これは、時間範囲内に実行されたクエリとそれらが消費したリソースを識別するのに十分です。

    > 低速クエリのログ記録

    予想よりも時間がかかるクエリをすばやく特定するもう1つの方法は、ステートメントのログをオンにすることです。しきい値の期間を指定できます。クエリの完了にこれより長い時間がかかる場合は、ログに記録されます。 (通常のPostgreSQLログファイルには、低速クエリ用の個別のログファイルはありません。)

    この機能をオンにするには、次のように構成を編集します。

    log_min_duration_statement = 1000 # in milliseconds

    Postgresをリロードします。 ALTER SYSTEMを使用することもできます :

    ALTER SYSTEM SET log_min_duration_statement = 1000; -- in milliseconds

    これにより、終了までに1秒以上かかるステートメント(非DMLステートメントを含む)がログに記録されます:

    2019-12-02 16:57:05.727 UTC [8040] postgres@testdb LOG:  duration: 10017.862 ms  statement: SELECT pg_sleep(10);

    クエリにかかった実際の時間とSQLの全文がログに記録されます。

    ログ監視システムがあり、1時間あたり/ 1日あたりの低速クエリの数を追跡できる場合は、アプリケーションのパフォーマンスの優れた指標として役立ちます。

    クエリ実行計画

    より高速に実行する必要があると思われるクエリを見つけたら、次のステップはそのクエリプランを確認することです。通常、本番サーバーからの実際のクエリプランを使用する必要があります。本番サーバーでEXPLAINを実行できる場合は、auto_explainに依存する必要があります。 。

    auto_explain はもう1つのコアPostgreSQL拡張機能であり、すでにインストールされているか、ディストリビューションの「contrib」パッケージとして利用できます。 AWSRDSでも利用できます。 auto_explain pg_stat_statementsよりもインストールが少し簡単です :

    • postgres構成(またはRDSパラメーターグループ)を編集しますshared_preload_libraries auto_explainを含める 。
    • Postgresを再起動する必要はありませんが、代わりに次のコマンドを実行できます:LOAD 'auto_explain';
    • 少なくとも次の設定を構成する必要があります:
      • auto_explain.log_min_duration = 1000 # seconds

    基本的に、クエリにauto_explain.log_min_durationよりも時間がかかる場合は常に 完了するまでの秒数、auto_explainは、次のように、クエリとそのクエリ実行プランをログファイルに記録します。

    2019-12-04 09:23:05.130 UTC [12823] postgres@testdb LOG:  duration: 11025.765 ms  plan:
            Query Text: select pg_sleep(11);
            Result  (cost=0.00..0.01 rows=1 width=4) (actual time=11025.716..11025.718 rows=1 loops=1)
              Output: pg_sleep('11'::double precision)

    プランを処理できるスクリプトがある場合は、JSON形式でプランをログに記録することもできます:

    2019-12-02 17:30:53.676 UTC [8040] postgres@testdb LOG:  duration: 10000.230 ms  plan:
            {
              "Query Text": "SELECT pg_sleep(10);",
              "Plan": {
                "Node Type": "Result",
                "Parallel Aware": false,
                "Startup Cost": 0.00,
                "Total Cost": 0.01,
                "Plan Rows": 1,
                "Plan Width": 4,
                "Actual Startup Time": 10000.205,
                "Actual Total Time": 10000.206,
                "Actual Rows": 1,
                "Actual Loops": 1,
                "Output": ["pg_sleep('10'::double precision)"],
                "Shared Hit Blocks": 0,
                "Shared Read Blocks": 0,
                "Shared Dirtied Blocks": 0,
                "Shared Written Blocks": 0,
                "Local Hit Blocks": 0,
                "Local Read Blocks": 0,
                "Local Dirtied Blocks": 0,
                "Local Written Blocks": 0,
                "Temp Read Blocks": 0,
                "Temp Written Blocks": 0,
                "I/O Read Time": 0.000,
                "I/O Write Time": 0.000
              },
              "Triggers": [
              ]
            }

    Postgresでは、auto_explain以外に、すでに実行されたクエリの実行計画を確認する方法はありません。これにより、auto_explainはツールボックスの重要なツールになります。


    1. PythonはMySQLのプリペアドステートメントをサポートしていますか?

    2. MySQLエラー#1064を修正するにはどうすればよいですか?

    3. &のような特殊文字をOracleデータベースに入力する方法は?

    4. プログラムでPostgresJDBCの`DataSource`オブジェクトを生成します