クエリ処理コンポーネントを識別する

完了

クエリの実行には、4 つの異なるステージがあります。 これらのステージは、実行の順序で次のとおりです。

  1. 解析
  2. 変換 (リライター)
  3. 計画
  4. 実行

パーサー

パーサーは、クエリ文字列で有効な構文を確認する役割を担います。 パーサーには、次の 2 つの主要な部分があります。

  • 文法規則と対応するアクションのセットで構成される gram.y
  • scan.1 は、識別子と SQL キー ワードを認識する lexer です。 すべてのキーワードまたは識別子によって、作成されるトークンがトリガーされ、パーサーに渡されます。

パーサーはクエリ ツリーを構築し、クエリを識別可能な部分に分割して、関連するテーブル、適用されたフィルターなどを理解します。クエリ ツリーの部分は次のとおりです。

  • コマンドの種類 - SELECT、INSERT、UPDATE、または DELETE。
  • 範囲テーブル エントリ (RTE) - リレーション、 ie テーブル、サブクエリ、結合の結果などのリスト。SELECT ステートメントでは、これらの項目は FROM キーワードの後に表示されます。
  • 結果の関係 - INSERT、UPDATE、DELETE コマンドの結果の関係は、変更を有効にするテーブルまたはビューです。
  • ターゲット リスト - クエリの結果。キーワード SELECT と FROM の間で識別されます。 DELETE コマンドは結果を生成しないため、プランナーは、Executor が削除する行を見つけられるように特別なエントリを追加します。 INSERT コマンドは、結果の関係に入る必要がある新しい行を識別します。 UPDATE コマンドの場合、ターゲット リストには、古い行を置き換える必要がある新しい行が記述されます。
  • 修飾 - 最終的な結果行の操作を実行するかどうかを指定するブール値。 これは、SQL ステートメントの WHERE 句に対応します。
  • 結合ツリー - このツリーは FROM 項目のリストである可能性があります。 結合は、任意の順序で実行することも、外部結合などの特定の順序で実行することもできます。
  • その他 - ORDER BY 句など、この段階では関係のない項目。

リライター

パーサーの出力は、エラー メッセージが返された場合にエラーが見つからない限り、 変換または書き換え プロセスに渡されます。

クエリ リライターは、 ルール を適用してクエリ テキストを書き換える。 リライターはルールを考慮に入れ、変更されたクエリをクエリ プランナーに渡します。 行レベルのセキュリティは、この段階で実装されます。

たとえば、SELECT のルールは、INSERT、UPDATE、DELETE クエリなど、常に最後の手順として適用されます。 ルールは、UPDATE クエリが既存の行を上書きせず、代わりに新しい行が挿入され、古い行が非表示になっていることを意味します。 トランザクションのコミット後、バキューム プロセスは非表示行を削除できます。

プランナー

プランナーの仕事は、クエリ ルールを取得し、クエリを実行できるさまざまな方法のうち、どれが最も速いかを理解することです。

プランナーは、データに対する物理的な操作を表すノードを含むプラン ツリーを作成します。

PostgreSQL では、コストベースのクエリ オプティマイザーを使用して、クエリに最適なプランを見つけます。 プランナーは、さまざまな実行プランを評価し、必要なリソース (CPU サイクル、I/O 操作など) の量を見積もります。この見積もりは、 計画コストと呼ばれる単位に変換されます。 コストが最も低いプランが選択されます。

ただし、結合の数が増えると、可能なプランの数が指数関数的に増加します。 可能なすべてのプランを評価することは、比較的単純なクエリでも不可能になります。 ヒューリスティックとアルゴリズムは、使用可能なプランの数を制限するために使用されます。 その結果、選択したプランが最適なプランではない可能性があります。 ただし、最適に近く、妥当な時間内に選択されます。

コストはプランナーの最適な見積もりです。 コスト見積もりの目的は、同じ条件で同じクエリに対して異なる実行プランを比較することです。 プランナーは、テーブルと行で収集された統計を使用して、クエリのコスト見積もりを生成します。 コスト見積もりを正確にするには、統計が最新である必要があります。

最新の統計

クエリ オプティマイザーの Planner コンポーネントは、テーブルと行に関する統計を使用して正確なコスト見積もりを生成します。

ANALYZE は、データベース テーブルに関する統計を収集し、 結果をpg_statistic システム カタログに格納します。 次の場合は、ANALYZE を実行する必要があります。

  • 自動バキュームを無効にしました (通常はテーブルが自動的に分析されます)
  • 自動バキュームを無効にし、最近 ANALYZE を実行していない
  • 上記のいずれかであり、INSERT、UPDATES、または DELETE ステートメントの多くがあります。

コストの見積もりは、up-to-date 統計に依存しており、統計が古い場合には、非効率的なプランが選ばれる可能性があります。 ANALYZE にパラメーターが渡されない場合、データベース内のすべてのテーブルが調べられます。

ANALYZE の構文は次のとおりです。

ANALYZE [ VERBOSE ] [ ***table*** [ ( ***column*** [, ...] ) ] ]

VERBOSE では、進行状況メッセージが表示され、分析対象のテーブルと一部の統計情報が表示されます。

VACUUM と ANALYZE をスケジュールして、使用時間が少ない間に毎日実行されるようにします。 ANALYZE は、ターゲット テーブルに対する読み取りロックのみが必要であるため、他のアクティビティと並列で実行できます。

実行者

このフェーズでは、プランナーによって作成されたプランを受け取り、それを再帰的に処理して、必要な行のセットを抽出します。 プラン ノードが呼び出されるたびに、Executor は行を配信するか、完了したことを報告で知らせる必要があります。

Executor は、次の 4 つの SQL クエリの種類をすべて評価します。

  • SELECT
  • INSERT
  • 更新
  • 削除

SELECT の場合、Executor は結果セットとして各行をクライアントに返します。

INSERT の場合、返される各行は指定されたテーブルに挿入されます。 このタスクは、ModifyTable と呼ばれる特別な最上位レベルのプラン ノードで実行されます。

UPDATE の場合、計算された各行には、更新されたすべての列値と、ターゲット行の行 ID が含まれます。 データは ModifyTable ノードに送信され、更新された行が作成され、古い行が削除済みとしてマークされます。

DELETE の場合、プランによって返される列は行 ID だけです。 ModifyTable ノードは、行 ID を使用して行を削除済みとしてマークします。