More Related Content Similar to YugabyteDBの実行計画を眺める(NewSQL/分散SQLデータベースよろず勉強会 #3 発表資料)
Similar to YugabyteDBの実行計画を眺める(NewSQL/分散SQLデータベースよろず勉強会 #3 発表資料) (20) More from NTT DATA Technology & Innovation
More from NTT DATA Technology & Innovation (20) YugabyteDBの実行計画を眺める(NewSQL/分散SQLデータベースよろず勉強会 #3 発表資料)1. © 2023 NTT DATA Corporation
© 2023 NTT DATA Corporation
NewSQL/分散SQLデータベース よろず勉強会 #3
YugabyteDBの実行計画を眺める
2023年2月16日
NTTデータ 笠原辰仁
2. © 2023 NTT DATA Corporation 2
自己紹介
• 笠原 辰仁 (@kasa_zip)
• 長年PostgreSQLの検証や周辺ツールの開発、サポートなどに従事
• 最近はNewSQLや分散データベースに属するOSSプロダクトの調査や検証、
適用領域の見極めなど
• 本日は、分散データベースのOSSプロダクトであるYugabyteDBの実行計画の取得方法や
情報の見方を解説
3. © 2023 NTT DATA Corporation 3
実行計画とは
発行されたクエリをどのように実行するかをDBMSが生成する情報。一般的にはDBMSのPlannerやOptimizerと呼ばれる機能
が生成する。
通常、あまりユーザ(クエリを発行する人)が実行計画を意識することは無いが、思ったような性能が出ない場合の原因解析やクエ
リチューニングを行った効果などを調査したい時に、とても有用なもの。
SELECT * FROM t1 JOIN t2 ON t1.c1 = t2.c1 WHERE t1.c1 < 10;
QUERY PLAN
--------------------------------------
Nested Loop
Join Filter: (t1.c1 = t2.c1)
-> Index Scan using t1_pkey on t1
Index Cond: (c1 < 10)
-> Seq Scan on t2
YugabyteDB
(のPlanner)
4. © 2023 NTT DATA Corporation 4
実行計画の取得方法
YugabyteDBでは他のDBMSと同様にEXPLAINという句をクエリの先頭に付与することで実行計画を取得できる。
クエリは実際には実行されない。出力される情報はPostgreSQLとほぼ同じ。
yugabyte=# EXPLAIN SELECT * FROM r_t1 WHERE c1 < 100;
QUERY PLAN
-----------------------------------------------------------------------
Index Scan using r_t1_pkey on r_t1 (cost=0.00..4.11 rows=1 width=52)
Index Cond: (c1 < 100)
(2 rows)
yugabyte=# EXPLAIN SELECT * FROM r_t1;
QUERY PLAN
----------------------------------------------------------
Seq Scan on r_t1 (cost=0.00..100.00 rows=1000 width=52)
(1 row)
yugabyte=# EXPLAIN SELECT * FROM r_t1 r JOIN h_t1 h ON r.c1 = h.c1 WHERE r.c1 < 100;
QUERY PLAN
-------------------------------------------------------------------------------
Nested Loop (cost=0.00..8.23 rows=1 width=104)
-> Index Scan using r_t1_pkey on r_t1 r (cost=0.00..4.11 rows=1 width=52)
Index Cond: (c1 < 100)
-> Index Scan using h_t1_pkey on h_t1 h (cost=0.00..4.11 rows=1 width=52)
Index Cond: (c1 = r.c1)
(5 rows)
5. © 2023 NTT DATA Corporation 5
実行計画の取得方法
EXPLAINではオプションをいくつか付与することで様々な情報を出力できる。
オプション 説明
ANALYZE 指定したクエリを実行し、実際の所要時間や消費した各種リソース(IOやメモリなど)の情報を出力する。
VERBOSE SELECT列の射影対象や中間処理での出力対象を出力する。
COSTS 実行計画のコスト情報を出力する。デフォルト有効。
TIMING 実行時の所要時間を出力する。ANALYZEの指定が必須でデフォルト有効。
BUFFERS 実行過程における巨大なハッシュやソート処理の一時ファイル書き出しで使用されたバッファサイズを出力す
る。ANALYZEの指定が必須。
SUMMARY 実行計画の末尾にプラン作成時間、実行時間、総メモリ消費量などを出力する。デフォルト有効。
FORMAT 実行計画情報の出力形式を指定する。TEXT、JSON、YAML、XMLから選択できデフォルトはTEXT。
DIST ストレージ層のDocDBへの読み書きリクエスト数やDocDBでの所要時間を出力する。
ANALYZEオプションを付与することで実際の所要時間が分かるため多用することが多い。ただし実際にクエリが実行されるため更
新系の処理を対象にするときは注意。(BEGIN; ABORT;で囲うなど工夫がいる)
COSTSやTIMING、SUMMARYについては変動要素の強い出力情報になるので、リグレッションテストなどの出力と期待のdiff
を取るときなどのノイズ除去として用いられたり、実行計画を簡潔に出力したい場合などに用いる。
6. © 2023 NTT DATA Corporation 6
EXPLAINの文法
EXPLAINでは複数のオプションを組み合わせて使用できる。以下のようにEXPLAIN (オプション [,..]) の形で指定する。
EXPLAIN (ANALYZE, BUFFERS, VERBOSE) SELECT …
上記はANALYZE、BUFFERS、VERBOSEを有効にしている。オプション [on | off] の形を取ることもできる。
EXPLAIN (ANALYZE on, BUFFERS on, COSTS off) SELECT …
上記はANALYZE、BUFFERSを有効にし、COSTSを無効にしている。
EXPLAINは通常のSELECTやUPDATEなどのクエリの他、カーソルのDECLARE、準備文(Prepared Statement)に対する
EXECUTEにも使用することができる。
PREPARE p1(int) AS SELECT … WHERE c1 = $1;
EXPLAIN (ANALYZE on, BUFFERS on) EXECUTE p1(10);
EXPLAIN (ANALYZE on, BUFFERS on) DECLARE cur FOR SELECT …
7. © 2023 NTT DATA Corporation 7
実行計画の見方
=> EXPLAIN SELECT * FROM r_t1 r JOIN h_t1 h ON r.c1 = h.c1 WHERE h.c1 < 10;
QUERY PLAN
-------------------------------------------------------------------------------
Nested Loop (cost=0.00..216.39 rows=1000 width=104)
-> Seq Scan on h_t1 h (cost=0.00..102.50 rows=1000 width=52)
Filter: (c1 < 10)
-> Index Scan using r_t1_pkey on r_t1 r (cost=0.00..0.11 rows=1 width=52)
Index Cond: (c1 = h.c1)
(5 rows)
赤字部分はノードタイプとも呼ばれ、実行されるスキャン、
結合、集計等の各処理の種別を表す。
基本的にネストの深い方(右の方)から順次実行されていく
代表的なノードタイプには以下がある。
• スキャン:Seq Scan/Index Scan/Index Only Scan
• 結合:Nested Loop/Merge Join/Hash Join (Semi/Anti)
• 集計:HashAggregate/GroupAggregate
• 更新:Insert/Update/Delete
• その他:Sort/Limit/Result/Append… など。
ちなみにPostgreSQLにあるBitmapScanは無い
まず計画そのものとなるノード情報。
8. © 2023 NTT DATA Corporation 8
実行計画の見方
=> EXPLAIN SELECT * FROM r_t1 r JOIN h_t1 h ON r.c1 = h.c1 WHERE h.c1 < 10;
QUERY PLAN
-------------------------------------------------------------------------------
Nested Loop (cost=0.00..216.39 rows=1000 width=104)
-> Seq Scan on h_t1 h (cost=0.00..102.50 rows=1000 width=52)
Filter: (c1 < 10)
-> Index Scan using r_t1_pkey on r_t1 r (cost=0.00..0.11 rows=1 width=52)
Index Cond: (c1 = h.c1)
(5 rows)
赤字部分はコストに関する情報で、N.NN .. M.MMはそれぞれ
スタートアップコスト(そのノードを開始するための準備コスト)と
トータルコスト(ノード処理を一通り完了するまでの総コスト)。
rowsは各ノードで取得する予想行数。
widthは各ノードで取得する列幅の総サイズ。
コストの計算式はPostgreSQLと同様のロジックだが、
YugabyteDB特有の要素がいくつかある。(異なるゾーン
やリージョンへの問い合わせコストは別途追加するなど)
src/backend/access/yb_access/yb_scan.cの
ybcCostEstimate()
Plannerが実行計画の作成の根拠とした見積情報。
9. © 2023 NTT DATA Corporation 9
実行計画の見方
=> EXPLAIN (ANALYZE on, COSTS off) SELECT r.c1, r.c4 FROM r_t1 r JOIN h_t1 h ON r.c1 = h.c1 WHERE h.c1 < 100;
QUERY PLAN
---------------------------------------------------------------------------------------
Nested Loop (actual time=12.706..1979.256 rows=99 loops=1)
-> Seq Scan on h_t1 h (actual time=7.545..1669.513 rows=99 loops=1)
Filter: (c1 < 100)
Rows Removed by Filter: 599901
-> Index Scan using r_t1_pkey on r_t1 r (actual time=3.108..3.108 rows=1 loops=99)
Index Cond: (c1 = h.c1)
Planning Time: 0.127 ms
Execution Time: 1979.423 ms
Peak Memory Usage: 30 kB
(9 rows)
赤字部分は実際にかかった時間や取得した行数情報。
actual timeのNN.NN .. MM.MMは各ノードで最初の1行を取得す
るまでの時間(ms)と最後の行を取得するまでの時間(ms)。
rowsは各ノードで取得された件数。
loopsは各ノードが繰り返された回数。
Rows Removed by Filterはスキャンした件数のうち条件により除去
された件数。
loopsが2以上の場合、実際にかかる時間は
「actual time」 * 「loops回数」となる。
loopsが多いものはactual timeが短くても注意すると良い。
実際にクエリを実行した場合の所要時間や取得した件数などの情報。
10. © 2023 NTT DATA Corporation 10
実行計画の見方
=> EXPLAIN (ANALYZE on, COSTS off) SELECT r.c1, r.c4 FROM r_t1 r JOIN h_t1 h ON r.c1 = h.c1 WHERE h.c1 < 100;
QUERY PLAN
---------------------------------------------------------------------------------------
Nested Loop (actual time=12.706..1979.256 rows=99 loops=1)
-> Seq Scan on h_t1 h (actual time=7.545..1669.513 rows=99 loops=1)
Filter: (c1 < 100)
Rows Removed by Filter: 599901
-> Index Scan using r_t1_pkey on r_t1 r (actual time=3.108..3.108 rows=1 loops=99)
Index Cond: (c1 = h.c1)
Planning Time: 0.127 ms
Execution Time: 1979.423 ms
Peak Memory Usage: 30 kB
(9 rows)
赤字部分はサマリ情報。
Planning Timeはプラン作成にかかった時間。
Execution Timeはクエリ処理にかかった総時間。
Peak Memory Usageはクエリ処理中の最もメモリを消費していた際
の利用量(Tserver上のpostgresバックエンドでの消費量)。
Execution TimeはYugabyteDB内での所要時間となり、
クライアントへ結果を返すなどの通信時間などは含まれない
ので注意。
実際にクエリを実行した場合のサマリ情報。
11. © 2023 NTT DATA Corporation 11
実行計画の見方
=> EXPLAIN (ANALYZE on, DIST on, COSTS off) SELECT r.c1, r.c4 FROM r_t1 r JOIN h_t1 h ON r.c1 = h.c1 WHERE h.c1 < 100;
QUERY PLAN
---------------------------------------------------------------------------------------
Nested Loop (actual time=20.376..1765.325 rows=99 loops=1)
-> Seq Scan on h_t1 h (actual time=6.409..1478.253 rows=99 loops=1)
Filter: (c1 < 100)
Rows Removed by Filter: 599901
Storage Table Read Requests: 588
Storage Table Execution Time: 1424.985 ms
-> Index Scan using r_t1_pkey on r_t1 r (actual time=2.882..2.882 rows=1 loops=99)
Index Cond: (c1 = h.c1)
Storage Index Read Requests: 1
Storage Index Execution Time: 2.859 ms
Planning Time: 0.085 ms
Execution Time: 1765.460 ms
Storage Read Requests: 687
Storage Write Requests: 0
Storage Execution Time: 1707.983 ms
Peak Memory Usage: 30 kB
(16 rows)
赤字部分はストレージ(DocDB)での処理時間や回数の情報。
Storage Table~はSeqScan処理でDocDBへ行われたRPCの回数と所要時間。
Storage Index~はIndex Scan処理でDocDBへ行われたRPCの回数と所要時
間。
Storage Read/Write RequestはDocDBへリクエストされたRPCの総回数。
Storage Execution TimeはDocDBでの処理総時間。
なお、loopsが2以上の場合はStorage~Requestsはその回数だけ実施される。
DISTオプションによる実際にクエリを実行した場合のDocDBでの処理時間やリクエスト回数などの情報。
12. © 2023 NTT DATA Corporation 12
YugabyteDBのユニークな処理 – HashとRange -
YugabyteDBではインデックスはデフォルトでハッシュインデックスが利用される。そのため範囲検索を多用する場合はインデックス
定義に注意しておく。
=# CREATE TABLE r_t1 (c1 int, c2 int, c3 int, c4 text, c5 timestamp, primary key (c1 ASC)); -- 主キーはRange
=# CREATE TABLE h_t1 (c1 int, c2 int, c3 int, c4 text, c5 timestamp, primary key (c1)); -- 主キーはHash
(各テーブルに60万件ほど投入)
=# EXPLAIN (ANALYZE on, COSTS off) SELECT * FROM r_t1 WHERE c1 < 100;
QUERY PLAN
-------------------------------------------------------------------------------
Index Scan using r_t1_pkey on r_t1 (actual time=1.099..1.134 rows=99 loops=1)
Index Cond: (c1 < 100)
Planning Time: 0.055 ms
Execution Time: 1.163 ms
Peak Memory Usage: 0 kB
(5 rows)
=# EXPLAIN (ANALYZE on, COSTS off) SELECT * FROM h_t1 WHERE c1 < 100;
QUERY PLAN
-----------------------------------------------------------------
Seq Scan on h_t1 (actual time=19.090..2783.098 rows=99 loops=1)
Filter: (c1 < 100)
Rows Removed by Filter: 599901
Planning Time: 1.557 ms
Execution Time: 2783.488 ms
Peak Memory Usage: 0 kB
(6 rows)
同じInteger型の列に定義した主キーの範囲検索で
あっても、ハッシュインデックスではインデックスが効かない
13. © 2023 NTT DATA Corporation 13
YugabyteDBのユニークな処理 – remote filter -
YugabyteDBではストレージ層のKVS(DocDB)からデータを読み取り、YSQLの層(postgresのバックエンドプロセス)でFilter
や結合を実施する。そのためSeqScanなどは大量のデータをDocDBから読み込むことになる。
=# EXPLAIN (ANALYZE on,DIST on,COSTS off) SELECT * FROM h_t1 WHERE c1 < 100;
QUERY PLAN
-------------------------------------------------------------------------------
Seq Scan on h_t1 (actual time=13.273..3742.157 rows=99 loops=1)
Filter: (c1 < 100)
Rows Removed by Filter: 599901
Storage Table Read Requests: 588
Storage Table Execution Time: 3636.899 ms
Planning Time: 0.058 ms
Execution Time: 3742.478 ms
Storage Read Requests: 588
Storage Write Requests: 0
Storage Execution Time: 3636.899 ms
Peak Memory Usage: 0 kB
(11 rows)
Tserver
YSQL
DocDB
データ
ここでFilterや結合、
集計を実施
Tserver
DocDB
Tserver
DocDB
14. © 2023 NTT DATA Corporation 14
YugabyteDBのユニークな処理 – remote filter -
YugabyteDBではDocDB側へ一部のFilter演算をPushdownし、データのリクエスト量・回数を抑えることが可能。
Pushdownされた処理はRemote Filterとして表示される。
=# SET yb_enable_expression_pushdown TO on;
SET
=# EXPLAIN (ANALYZE on,DIST on,COSTS off) SELECT * FROM h_t1 WHERE c1 < 100;
QUERY PLAN
-------------------------------------------------------------------------------
Seq Scan on h_t1 (actual time=1211.024..2408.519 rows=99 loops=1)
Remote Filter: (c1 < 100)
Storage Table Read Requests: 2
Storage Table Execution Time: 2406.933 ms
Planning Time: 0.061 ms
Execution Time: 2408.693 ms
Storage Read Requests: 2
Storage Write Requests: 0
Storage Execution Time: 2406.933 ms
Peak Memory Usage: 14 kB
(10 rows)
=# EXPLAIN (ANALYZE on,DIST on,COSTS off) SELECT * FROM h_t1 WHERE c1 < 100;
QUERY PLAN
-----------------------------------------------------------------------------
--
Seq Scan on h_t1 (actual time=13.273..3742.157 rows=99 loops=1)
Filter: (c1 < 100)
Rows Removed by Filter: 599901
Storage Table Read Requests: 588
Storage Table Execution Time: 3636.899 ms
Planning Time: 0.058 ms
Execution Time: 3742.478 ms
Storage Read Requests: 588
Storage Write Requests: 0
Storage Execution Time: 3636.899 ms
Peak Memory Usage: 0 kB
(11 rows)
Remote Filterが有効に働くと、Storage~のリクエスト数などが
低減し、性能が向上することがある。
15. © 2023 NTT DATA Corporation 15
YugabyteDBのユニークな処理 – batched nested loop -
YugabyteDBではDocDB側からRPC経由でデータを取得するため、Nested Loopのような処理はNWレイテンシの影響など
を受けやすい。Range分割しているキーで範囲検索をするとある程度まとめてデータを取得できるが、Innerのテーブルへの検索
は多くのLoopとなる。
=# EXPLAIN (ANALYZE on, DIST on, COSTS off, TIMING off)
SELECT * FROM r_t1 r1, r_t2 r2 WHERE r1.c1 = r2.c1 AND r1.c1 < 2000;
QUERY PLAN
------------------------------------------------------------------------
Nested Loop (actual rows=1999 loops=1)
-> Index Scan using r_t1_pkey on r_t1 r1 (actual rows=1999 loops=1)
Index Cond: (c1 < 2000)
Storage Index Read Requests: 2
-> Index Scan using r_t2_pkey on r_t2 r2 (actual rows=1 loops=1999)
Index Cond: (c1 = r1.c1)
Storage Index Read Requests: 1
Planning Time: 0.116 ms
Execution Time: 309.301 ms
Storage Read Requests: 2001
Storage Write Requests: 0
Storage Execution Time: 262.997 ms
Peak Memory Usage: 24 kB
(13 rows)
Innerテーブルとなるr_t2に1999回のアクセス
Tserver
YSQL
DocDB
ここでFilterや結合、
集計を実施
Tserver
DocDB
Tserver
DocDB
16. © 2023 NTT DATA Corporation 16
YugabyteDBのユニークな処理 – batched nested loop -
YugabyteDBではyb_bnl_batch_sizeという動的に変更できるパラメータがあり、
「ANY(ARRAY[指定した数値分のデータ])」を利用してバッチ的にInnerテーブルへ引き当てに行く。
=# SET yb_bnl_batch_size = 5;
=# EXPLAIN (ANALYZE on, DIST on, COSTS off, TIMING off)
SELECT * FROM r_t1 r1, r_t2 r2 WHERE r1.c1 = r2.c1 AND r1.c1 < 2000;
QUERY PLAN
------------------------------------------------------------------------
YB Batched Nested Loop Join (actual rows=1999 loops=1)
Join Filter: (r1.c1 = r2.c1)
-> Index Scan using r_t1_pkey on r_t1 r1 (actual rows=1999 loops=1)
Index Cond: (c1 < 2000)
Storage Index Read Requests: 2
-> Index Scan using r_t2_pkey on r_t2 r2 (actual rows=5 loops=400)
Index Cond: (c1 = ANY (ARRAY[r1.c1, $1, $2, $3, $4]))
Storage Index Read Requests: 3
Planning Time: 0.134 ms
Execution Time: 210.351 ms
Storage Read Requests: 1202
Storage Write Requests: 0
Storage Execution Time: 183.998 ms
Peak Memory Usage: 237 kB
batch_sizeを5にすると、一度のIndex Scanで5件の検索をまとめて行う。
結果的にDocDBへのリクエスト数も減り、性能向上する。
(このケースだとsizeを100に引き上げると40msec程度までレスポンスタイムが改善。)
17. © 2023 NTT DATA Corporation 17
YugabyteDBのユニークなポイント
現時点のYugabyteDBは統計情報を収集しておらず、また活用することもしない。つまりルールベース オプティマイズと同様。
内部では固定値の行見積値を使っているため、想定行数は一定となる。また基本的にインデックスが使える場合はIndex Scan
を使用するようになる。ANALYZEはbeta機能として利用可能。
=# EXPLAIN SELECT * FROM r_t1 WHERE c1 = 1; -- 主キーで1件
QUERY PLAN
-----------------------------------------------------------------------
Index Scan using r_t1_pkey on r_t1 (cost=0.00..4.11 rows=1 width=52)
Index Cond: (c1 = 1)
(2 rows)
=# EXPLAIN SELECT * FROM r_t1 WHERE c1 < 100; -- 主キー範囲で99件
QUERY PLAN
-----------------------------------------------------------------------
Index Scan using r_t1_pkey on r_t1 (cost=0.00..4.11 rows=1 width=52)
Index Cond: (c1 < 100)
(2 rows)
=# EXPLAIN SELECT * FROM r_t1 WHERE c1 > 0; -- 主キー範囲で60万件
QUERY PLAN
-----------------------------------------------------------------------
Index Scan using r_t1_pkey on r_t1 (cost=0.00..4.11 rows=1 width=52)
Index Cond: (c1 > 0)
(2 rows)
18. © 2023 NTT DATA Corporation 18
YugabyteDBのユニークなポイント
前述のとおり統計情報を利用せず、インデックススキャンを積極的に利用する傾向が強いため、必然的にNested Loop結合が
選択されやすい。もともとYugabyteDBでは大量データのスキャンなどは得意としていないので、比較的多くの行を選択したり結
合する場合、HINT句の活用を視野に入れる必要がある。
=# EXPLAIN ANALYZE SELECT * FROM r_t1 r JOIN h_t1 h ON r.c1 = h.c1 WHERE r.c1 < 1000000;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------
Nested Loop (cost=0.00..8.23 rows=1 width=104) (actual time=8.286..244997.931 rows=600000 loops=1)
-> Index Scan using r_t1_pkey on r_t1 r (cost=0.00..4.11 rows=1 width=52) (actual time=7.775..1382.285 rows=600000 loops=1)
Index Cond: (c1 < 1000000)
-> Index Scan using h_t1_pkey on h_t1 h (cost=0.00..4.11 rows=1 width=52) (actual time=0.387..0.387 rows=1 loops=600000)
Index Cond: (c1 = r.c1)
Planning Time: 0.212 ms
Execution Time: 245603.057 ms
Peak Memory Usage: 32 kB
(8 rows)
=# /*+ HashJoin(r h) */ EXPLAIN ANALYZE SELECT * FROM r_t1 r JOIN h_t1 h ON r.c1 = h.c1 WHERE r.c1 < 1000000;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------
Hash Join (cost=4.12..106.76 rows=1 width=104) (actual time=4548.694..9061.421 rows=600000 loops=1)
Hash Cond: (h.c1 = r.c1)
-> Seq Scan on h_t1 h (cost=0.00..100.00 rows=1000 width=52) (actual time=6.727..3051.250 rows=600000 loops=1)
-> Hash (cost=4.11..4.11 rows=1 width=52) (actual time=4541.308..4541.309 rows=600000 loops=1)
Buckets: 65536 (originally 1024) Batches: 16 (originally 1) Memory Usage: 3725kB
-> Index Scan using r_t1_pkey on r_t1 r (cost=0.00..4.11 rows=1 width=52) (actual time=7.352..3880.254 rows=600000 loops=1)
Index Cond: (c1 < 1000000)
Planning Time: 0.294 ms
Execution Time: 9503.739 ms
Peak Memory Usage: 5899 kB
(10 rows)
19. © 2023 NTT DATA Corporation 19
まとめ
YugabyteDBでの実行計画の取得方法と簡単な見方、およびYugabyteDB特有の実行計画に関する機能・仕組みを紹介し
ました。PostgreSQLに慣れた方ならば、それと気づかずにYugabyteDBの実行計画を読めてしまうかもしれません。
どんなDBMSであっても実行計画の読み解きは必要となるスキルなので、ぜひ色々なクエリ、DBMSの実行計画を読んでみましょう。
20. © 2023 NTT DATA Corporation 20
参考
YugabyteDBのEXPLAIN
https://docs.yugabyte.com/preview/api/ysql/the-sql-language/statements/perf_explain/
PostgreSQLのEXPLAIN
https://www.postgresql.org/docs/current/sql-explain.html
YugabyteDBのHINT句利用方法
https://docs.yugabyte.com/preview/explore/query-1-performance/pg-hint-plan/
21. © 2022 NTT DATA Corporation
その他、記載されている会社名、商品名、又はサービス名は、
各社の登録商標又は商標です。