これは、Ubuntu Online、Fedora Online、Windows オンライン エミュレーター、MAC OS オンライン エミュレーターなどの複数の無料オンライン ワークステーションの XNUMX つを使用して、OnWorks 無料ホスティング プロバイダーで実行できるコマンド pt-visual-explainp です。
プログラム:
NAME
pt-visual-explain - EXPLAIN 出力をツリーとしてフォーマットします。
SYNOPSIS
使用法: pt-visual-explain [オプション] [ファイル]
pt-visual-explain は、EXPLAIN 出力をクエリ プランのツリー表現に変換します。
FILE が指定された場合、入力はファイルから読み取られます。 FILE がない場合、または FILE が - の場合、読み取ります
標準入力。
例:
pt-visual-explain
pt-visual-explain -c
mysql -e "explain select * from mysql.user" | mysql -e "explain select * from mysql.user" | mysql -e "explain select * from mysql.user" pt-visual-explain
リスク
Percona Toolkit は成熟しており、現実世界で実証されており、十分にテストされていますが、すべてデータベースです
ツールはシステムやデータベース サーバーにリスクをもたらす可能性があります。 このツールを使用する前に、
お願いします:
・ツールのドキュメントを読む
・ツールの既知の「バグ」を確認します
· 非運用サーバーでツールをテストする
· 運用サーバーをバックアップし、バックアップを検証します。
DESCRIPTION
pt-visual-explain は、MySQL の EXPLAIN 出力をクエリ実行プランにリバース エンジニアリングします。
次に、内部で計画が表現されるのと同じ方法で、左の深さのツリーとしてフォーマットされます。
MySQL。 これを手動で行うことも、EXPLAIN の出力を直接読み取ることも可能ですが、
忍耐と専門知識が必要です。 多くの人は木の表現をよりよく見つけます
理解できる。
入力を pt-visual-explain にパイプすることも、コマンド ラインでファイル名を指定することもできます。
これには、標準入力から読み取られる魔法の「-」ファイル名が含まれます。 XNUMXつできる
入力に関するもの: EXPLAIN 出力のようなものを解析するか、接続します。
MySQL インスタンスに接続し、入力に対して EXPLAIN を実行します。
入力を解析するとき、pt-visual-explain は XNUMX つの形式を理解します。
mysql コマンドライン クライアントに表示されます。\G 行を使用して作成されたものと同じように垂直に表示されます。
mysql コマンドライン クライアントのターミネータとタブ区切り。 どの行も無視します
解析方法がわかりません。
入力を実行すると、pt-visual-explain は入力内のすべてを置き換えます。
最初の SELECT キーワードに「EXPLAIN SELECT」を指定し、その結果を実行します。 絶対です
入力をクエリとして実行するには、「--connect」を指定します。
いずれの場合も、結果セットからツリーを構築し、それを標準出力に出力します。 のために
次のクエリ、
select * from sakila.film_actor join sakila.film using(film_id);
pt-visual-explain は次のクエリ プランを生成します。
登録
+- ブックマークの検索
| +- テーブル
| | テーブル映画_俳優
| | | | possible_keys idx_fk_film_id
| +- インデックス検索
| キー film_actor->idx_fk_film_id
| | possible_keys idx_fk_film_id
| | key_len 2
| | ref sakila.film.film_id
| 行2
+- テーブルスキャン
行952
+- テーブル
テーブルフィルム
possible_keys プライマリ
クエリ プランは左の深さ、深さ優先の検索であり、ツリーのルートが出力ノードです。
実行計画の最後のステップ。 つまり、次のように読んでください。
1. 推定 952 行にアクセスする「film」テーブルをテーブル スキャンします。
2. 各行に対して、インデックス検索を実行して、一致する行を見つけます。
film_actor->idx_fk_film_id インデックスと sakila.film.film_id の値、そして
film_actor テーブルへのブックマークのルックアップ。
EXPLAIN 出力の読み方の詳細については、「」を参照してください。
<http://dev.mysql.com/doc/en/explain.html>、そしてこの講演のタイトルは「MySQL クエリ オプティマイザー」
v. 5.2 の内部と今後の機能: MySQL の XNUMX つである Timour Katchaounov より
開発者:http://goo.gl/VIWvo>
モジュール
このプログラムは実際には、単なる通常の Perl スクリプトではなく、実行可能なモジュールです。 実際には、
XNUMX つのモジュールが組み込まれています。 これにより単体テストが簡単になりますが、同時に
必要に応じて、解析およびツリー構築機能を簡単に使用できます。
ExplainParser パッケージは文字列を受け入れ、それがどのように見えるかを解析します。
そこからの出力を説明します。 概要は次のとおりです。
「pt-visual-explain」が必要です。
私の $p = ExplainParser->new();
my $rows = $p->parse("何らかのテキスト");
# $rows は hashref の arrayref です。
ExplainTree パッケージは行のセットを受け取り、それをツリーに変換します。 便宜上、
また、ExplainParser に委任してテキストを解析させることもできます。 こちらが
あらすじ:
「pt-visual-explain」が必要です。
私の $e = ExplainTree->new();
my $tree = $e->parse("テキスト", \%options);
私の $output = $e->pretty_print($tree);
$tree を印刷します。
アルゴリズム
EXPLAINをツリーに変換するアルゴリズムについて説明します。 あなたもそうかもしれません
EXPLAIN をより完全に理解したい場合、またはこれから試してみたい場合は、これを読むことに興味があります。
これがどのように機能するかを理解してください。そうでない場合、このセクションはおそらくあなたの人生を豊かにすることはありません
より豊かに。
ツリーは、各行の id、select_type、および table 列を調べることによって構築できます。
彼らについて私が知っていることは次のとおりです。
id 列は選択の連続番号です。 これはネストを示すものではありません。 それ
SQL ステートメントの左側から SELECT を数えることによって得られます。 まるでキャプチャーしてるような
正規表現の中のかっこ。 UNION RESULT 行には ID がありません。
SELECTではありません。 私の記憶によれば、ソース コードでは実際には UNION を fake_lex として参照しています。
隣接する XNUMX つの行が同じ ID 値を持つ場合、それらは標準の単一行で結合されます。
スイープマルチジョインメソッド。
select_type 列は、a) 新しいサブスコープが開かれたこと、b) サブスコープの種類を示します。
その行が前の行と持つ関係 c) その行が表す操作の種類。
· SIMPLE は、クエリ全体にサブクエリやユニオンがないことを意味します。
· PRIMARY は存在することを意味しますが、これは最も外側の SELECT です。
· [DEPENDENT] UNION は、この結果が前の結果 (行ではなく、
結果には複数の行が含まれる場合があります)。
· UNION RESULT は、UNION 化された結果のセットを終了します。
· [DEPENDENT|UNCACHEABLE] SUBQUERY は、新しいサブスコープが開かれていることを意味します。 これはその種類です
WHERE 句、SELECT リストなどで発生するサブクエリ。 戻らない
いわゆる「派生テーブル」。
· DERIVED は FROM 句のサブクエリです。
JOIN されるテーブルはすべて同じ select_type を持ちます。 たとえば、XNUMX つを結合すると、
依存サブクエリ内のテーブルでは、すべて同じことを言います: DEPENDENT SUBQUERY。
テーブル列は通常、テーブル名または別名を指定しますが、次のように指定することもできます。 または
。 それが言うなら、行は一時的なアクセスを表します。
ID が N のサブクエリの結果を保持するテーブル。 その
同じことですが、UNION した結果を指します。
最後に、順序が重要です。 行のIDがその前のIDより小さい場合、それは意味すると思います
それは、その前のもの以外のものに依存しています。 例えば、
選択を説明する
(sakila.filmから1つ選択)、
(sakila.film_actorから2つ選択)、
(sakila.actorから3つ選択);
| ID | 選択タイプ | テーブル |
+-----+---------------+----------+
| 1 | プライマリ | NULL |
| 4 | サブクエリ | 俳優 |
| 3 | サブクエリ | 映画俳優 |
| 2 | サブクエリ | 映画 |
結果が 2-3-4 の順序であった場合、3 は 2 のサブクエリ、4 は XNUMX のサブクエリであることを意味すると思います。
3 のサブクエリ。そのままでは、4 が最も近い前の最近の行のサブクエリであることを意味します。
ID は 1 と小さくなります。3 と 2 についても同様です。
この構造は、プログラムでツリーに組み込むのが難しいのと同じ理由で困難です。
調べて理解するには、前方参照と後方参照の両方があります。
は selectN への前方参照ですが、 selectM への後方参照であり、
Nを選択します。 そのため、再帰やその他のツリー構築アルゴリズムを正しく理解することが困難になります (注:
実装後、転送と転送の両方にどのように対処できるかがわかりました。
逆方向参照ですが、機能するものを変更する動機はありません)。 考慮する
以下
* から選択 (
sakila.actorからactor_1として1を選択
組合
sakila.actorからactor_1として2を選択
) der_1 として
組合
* から選択 (
sakila.actorからactor_1として3を選択
ユニオンオール
sakila.actorからactor_1として4を選択
) der_2 として;
| ID | 選択タイプ | テーブル |
+------+--------------+-----------+
| 1 | プライマリ | |
| 2 | 派生 | 俳優_1 |
| 3 | ユニオン | 俳優_2 |
| NULL | 組合結果 | |
| 4 | ユニオン | |
| 5 | 派生 | 俳優_3 |
| 6 | ユニオン | 俳優_4 |
| NULL | 組合結果 | |
| NULL | 組合結果 | |
このように見えると、作業がはるかに簡単になります(IDを括弧で囲みました)
移動した行):
| ID | 選択タイプ | テーブル |
+------+--------------+-----------+
| [1] | 組合結果 | |
| 1 | プライマリ | |
| [2] | 組合結果 | |
| 2 | 派生 | 俳優_1 |
| 3 | ユニオン | 俳優_2 |
| 4 | ユニオン | |
| [5] | 組合結果 | |
| 5 | 派生 | 俳優_3 |
| 6 | ユニオン | 俳優_4 |
実際、PRIMARY 行が 2 になるように、すべての ID に番号を付け直してみませんか? それ
さらに読みやすくなります。 残念ながら、それは次のような影響もあります
id 列の意味を破壊します。これは、
最後の木。 また、読みやすくはなりますが、読みやすくはなりません。
プログラムで操作する。 したがって、番号はそのままにしておいても問題ありません。
並べ替えの目的は、どの行がその子であるかを簡単に把握できるようにすることです。
実行計画内のどの行であるか。 並べ替えられたリストとテーブルが次のような行があるとします。
または、必要な行のスライスの先頭を見つけるのは簡単です。
ツリー内の子ノードになります。ID が同じ最初の行を探すだけです。
表の最初の番号。
次の質問は、UNION または UNION の子ノードとなる最後の行を見つける方法です。
派生。 このソリューションにより UNION が簡単になるため、DERIVED から始めます。
MySQL が SELECT の位置に応じて順番に番号を付ける方法を検討してください。
SQL、左から右へ。 DERIVED テーブルはテーブル内のすべてをスコープ内に囲むため、
が一時テーブルになる場合、考慮すべきことは XNUMX つだけです。その子のサブクエリです。
結合体 (存在する場合)、およびそれを囲むスコープ内の次の兄弟。 その子供たち
定義上、すべての ID は実際の ID よりも大きいため、それ以降の行の ID が小さいものになります。
id でスコープを終了します。
ここに例を示します。 ここの中間の派生テーブルには、サブクエリと UNION があり、
例としてはもう少し複雑です。
選択1を説明します
から(
sakila.film から film_id を選択 制限 1
) der_1 として
参加する (
select film_id、actor_id、(sakila.rental から count(*) を選択) as r
sakila.film_actor 制限 1 より
ユニオンオール
sakila.film_actorから1、1、1をダミーとして選択
) (film_id) を使用して der_2 として
参加する (
sakila.actor制限1からactor_idを選択
) (actor_id) を使用して der_3 として。
EXPLAIN の出力は次のとおりです。
| ID | 選択タイプ | テーブル |
| 1 | プライマリ | |
| 1 | プライマリ | |
| 1 | プライマリ | |
| 6 | 派生 | 俳優 |
| 3 | 派生 | 映画俳優 |
| 4 | サブクエリ | レンタル |
| 5 | ユニオン | ダミー |
| NULL | 組合結果 | |
| 2 | 派生 | 映画 |
兄弟はすべて ID 1 を持ち、私が注目している真ん中の ID は派生 3 です。 (MySQL に注意してください
定義した順序で実行されませんが、問題ありません)。 ここで、MySQL に注目してください。
サブクエリを定義したのとは逆の順序で行を出力します: 6、3、2。常に
これを行うようですが、スコープの境界を見つける他の方法があるかもしれません
次に大きい兄弟の下限を探すことも含まれますが、これは良いことです。
十分なヒューリスティックです。 非 DERIVED サブクエリではこれに依存する必要があるため、これに依存します
ここでも。 したがって、3 以上のものはすべて、
派生スコープ。
UNION のルールは単純です。UNION は、囲んでいるスコープ全体を消費し、
それぞれの構成部分を確認すると、「」で参照されている各部分の始まりがわかります。
定義であり、その終わりが次の定義の直前か、
最後の部分、end はスコープの終わりです。
UNION はスコープ全体を消費するため、これは単純です。
ステートメント、または DERIVED テーブルのスコープ。 これは、UNION を兄弟にすることができないためです。
別の UNION またはテーブルの、派生かどうかに関係なく。 (そうでない場合は、そのようなステートメントを書いてみてください
直感的にわかります)。 したがって、外側のスコープの境界を見つけるだけで済みます。
残りは簡単です。 上の例では、UNION が終了していることに注意してください。 、 どれの
ID 4 の行が含まれます。これには、3 から 5 までのすべての行が含まれます。
最後に、非派生サブクエリも処理する必要があります。 この場合は見れません
DERIVED の場合と同様に、兄弟でスコープの終わりを見つけます。 MySQL を信頼する必要があります
深さ優先で実行します。 以下に例を示します。
説明します
Actor_id を選択し、
(
選択数(フィルムID)
+ (sakila.filmからcount(*)を選択)
sakila.film から (film_id) を使用して sakila.film_actor に参加します
存在する場所(
select * from sakila.actor
ここで、sakila.actor.actor_id = sakila.film_actor.actor_id
)
)
sakila.actorより;
| ID | 選択タイプ | テーブル |
| 1 | プライマリ | 俳優 |
| 2 | サブクエリ | 映画 |
| 2 | サブクエリ | 映画俳優 |
| 4 | 依存サブクエリ | 俳優 |
| 3 | サブクエリ | 映画 |
順番に、ツリーは次のように構築する必要があります。
· 行 1 を参照してください。
· 行 2 を参照してください。これは 1 よりも高い ID であるため、他の行と同様にサブクエリになります。
ID が 2 より大きい。
· このスコープ内では、2 と 2 を参照して JOIN します。 4 を参照してください。これは 2 よりも高い ID であるため、
これもサブクエリです。 再帰する。 その後、これも高い 3 を参照してください。 再帰する。
しかし、ネストされたサブクエリに選択 3 が含まれていない唯一の理由は、選択 4 が含まれているためです。
初め。 つまり、EXPLAIN が次のようになった場合、
| ID | 選択タイプ | テーブル |
| 1 | プライマリ | 俳優 |
| 2 | サブクエリ | 映画 |
| 2 | サブクエリ | 映画俳優 |
| 3 | サブクエリ | 映画 |
| 4 | 依存サブクエリ | 俳優 |
select 3 を見ると、select 4 はそのサブクエリであると推測せざるを得ません。
単に囲んでいるスコープ内の次の兄弟になるだけではありません。 これが間違っている場合は、
アルゴリズムが間違っているので、それに対して何ができるのかわかりません。
UNION は、単に「スコープ全体が UNION である」ということよりも少し複雑です。
UNION 自体は、最初の項目によってのみ示される囲みスコープ内にある可能性があります。
ユニオン内で。 囲むスコープは UNION、DERIVED、および の XNUMX 種類のみです。
サブクエスト。 UNION は UNION を囲むことができず、DERIVED には独自の「スコープ マーカー」がありますが、
SUBQUERY は、空のテーブル t1 のこの奇妙な例のように、UNION を完全に囲むことができます。
Explain select * from t1 where not存在(
(t11 t1 から t11.i を選択) 結合 (t12 t1 から t12.i を選択));
| ID | 選択タイプ | テーブル | 番外編 |
+------+--------------+-----------+-------------- ------------------+
| 1 | プライマリ | t1 | const 行が見つかりません |
| 2 | サブクエリ | NULL | テーブルは使用されていません |
| 3 | サブクエリ | NULL | const テーブルに一致する行がありません |
| 4 | ユニオン | t12 | const 行が見つかりません |
| NULL | 組合結果 | | |
UNION の後方参照により、UNION がサブクエリを囲んでいるように見える場合があります。
しかし、クエリを研究すると、そうではないことが明らかになります。 したがって、UNION の最初の行が
SUBQUERY は、これは特殊なケースだと言います。
ところで、私はこのクエリ プランを完全には理解していません。 には番号付きの SELECT が 4 つあります。
計画していますが、クエリには 3 つしかありません。 UNION を囲む括弧は意味を持ちます。 削除中
それらはEXPLAINを異なるものにします。 ご存知の場合、これがどのように機能するのか、なぜ機能するのか教えてください。
この知識があれば、再帰を使用して親子関係を切り替えることができます。
すべての行間の関係を実行計画を表すツリーにまとめます。
MySQL は、前方参照と後方参照も含めて、実行順に行を出力します。 で
どのスコープでも、行は左の深さのツリーとして処理されます。 MySQL は「ふさふさ」をしません
実行計画。 テーブルから始まり、次のテーブルで一致する行を見つけます。
行を出力する最後のテーブルまで継続します。 それがなくなると、それまでバックトラックします
次の行を見つけて繰り返します。 もちろん細かい点はありますが、これは
基本プラン。 これが、MySQL がすべての RIGHT OUTER JOIN を LEFT OUTER JOIN に変換する理由です。
FULL OUTER JOIN は実行できません。
これは、特定のスコープ内で、たとえば、
| ID | 選択タイプ | テーブル |
| 1 | シンプル | tbl1 |
| 1 | シンプル | tbl2 |
| 1 | シンプル | tbl3 |
実行計画は、このツリーを深さ優先で走査するように見えます。
登録
/\
テーブル3に参加する
/\
tbl1 tbl2
JOIN は JOIN ではない可能性があります。 たとえば、サブクエリである可能性があります。 これは、
EXPLAIN の type 列。 ドキュメントには、これは「結合タイプ」であると記載されていますが、私は「アクセス」だと思います。
type」は「MySQL が行にアクセスする方法」であるため、より正確です。
pt-visual-explain は、行をノードに変換するだけでなく、ツリーを大幅に装飾します。
各ノードは、ノードを複数のサブツリーに変える一連の変換を受ける場合があります。
ノード。 たとえば、「インデックスを使用」とマークされていないインデックス スキャンでは、ブックマーク ルックアップを実行する必要があります。
テーブルの行に。 それは XNUMX ノードのサブツリーです。 ただし、上記のノード順序付けの後、
スコープ設定を行うだけで、残りのプロセスは非常に簡単です。
OPTIONS
このツールは追加のコマンドライン引数を受け入れます。 「概要」と使用方法を参照してください。
詳細については情報。
--ask-pass
MySQL に接続するときにパスワードの入力を求められます。
- 文字コード
短縮形: -A; タイプ: 文字列
デフォルトの文字セット。 値が utf8 の場合、STDOUT の Perl の binmode を utf8 に設定します。
mysql_enable_utf8 オプションを DBD::mysql に渡し、その後 SET NAMES UTF8 を実行します。
MySQL に接続します。 他の値は、utf8 レイヤーを使用せずに STDOUT で binmode を設定します。
MySQL に接続した後、SET NAMES を実行します。
--clustered-pk
PRIMARY KEY インデックスへのアクセスでは、ブックマークを検索して取得する必要がないと仮定します。
行。 これは InnoDB の場合に当てはまります。
--config
タイプ:配列
このコンマ区切りの構成ファイルのリストを読んでください。 指定する場合、これが最初である必要があります
コマンドラインのオプション。
- 接続
入力をクエリとして扱い、MySQL インスタンスに接続して EXPLAIN 出力を取得します
そしてクエリに対して EXPLAIN を実行します。 このオプションが指定された場合、pt-visual-explain は
MySQL に接続するための「--user」などの他の接続固有のオプション
実例。 .my.cnf ファイルがある場合はそれを読み取るため、指定する必要がない場合があります。
接続固有のオプション。
-データベース
短縮形:-D; タイプ:文字列
このデータベースに接続します。
--デフォルトファイル
短縮形: -F; タイプ: 文字列
指定されたファイルから mysql オプションのみを読み取ります。 絶対パス名を指定する必要があります。
- フォーマット
タイプ: 文字列; デフォルト: ツリー
出力フォーマットを設定します。
デフォルトは、簡潔できれいに印刷されたツリーです。 有効な値は次のとおりです。
値の意味
===== ============================================ ===
ツリー かわいらしくプリントされた簡潔なツリー。
dump Data::Dumper の出力 (詳細については、Data::Dumper を参照)。
- 助けて
ヘルプを表示して終了します。
- ホスト
短い形式: -h; タイプ: 文字列
ホストに接続します。
- パスワード
短い形式: -p; タイプ: 文字列
接続時に使用するパスワード。 パスワードにカンマが含まれている場合はエスケープする必要があります
バックスラッシュ付き: "exam\,ple"
--pid
タイプ:文字列
指定された PID ファイルを作成します。 PID ファイルがすでに存在する場合、ツールは起動しません。
含まれているPIDは、現在のPIDとは異なります。 ただし、PIDファイルの場合
存在し、それに含まれる PID が実行されなくなった場合、ツールは PID を上書きします
現在の PID を持つファイル。 PID ファイルは、ツールが終了すると自動的に削除されます。
- 港
短縮形: -P; 型: int
接続に使用するポート番号。
--set-vars
タイプ:配列
この「変数=値」ペアのカンマ区切りリストに MySQL 変数を設定します。
デフォルトでは、ツールは以下を設定します。
wait_timeout=10000
コマンドラインで指定された変数は、これらのデフォルトをオーバーライドします。 例えば、
「--set-vars wait_timeout=500」を指定すると、デフォルト値の 10000 がオーバーライドされます。
変数を設定できない場合、ツールは警告を出力し、続行します。
- ソケット
短縮形: -S; タイプ: 文字列
接続に使用するソケットファイル。
- ユーザー
短い形式: -u; タイプ: 文字列
現在のユーザーでない場合は、ログインするユーザー。
- バージョン
バージョンを表示して終了します。
DSN OPTIONS
これらの DSN オプションは、DSN を作成するために使用されます。 各オプションは「option=value」のように与えられます。
オプションでは大文字と小文字が区別されるため、P と p は同じオプションではありません。 そんなことはありえない
「=」の前後には空白があり、値に空白が含まれる場合は引用符で囲む必要があります。
DSN オプションはカンマで区切られます。 詳細については、percona-toolkit マンページを参照してください。
・A
DSN: 文字セット; コピー: はい
デフォルトの文字セット。
・ NS
DSN: データベース; コピー: はい
デフォルトのデータベース。
・ NS
DSN: mysql_read_default_file; コピー: はい
指定されたファイルからデフォルトのオプションのみを読み取ります
・h
DSN: ホスト; コピー: はい
ホストに接続します。
・ NS
DSN: パスワード; コピー: はい
接続時に使用するパスワード。 パスワードにカンマが含まれている場合はエスケープする必要があります
バックスラッシュ付き: "exam\,ple"
・p
DSN: ポート; コピー: はい
接続に使用するポート番号。
・ NS
DSN: mysql_socket; コピー: はい
接続に使用するソケットファイル。
・あなた
DSN: ユーザー; コピー: はい
現在のユーザーでない場合は、ログインするユーザー。
ENVIRONMENT
環境変数「PTDEBUG」を使用すると、STDERR への詳細なデバッグ出力が有効になります。 有効にする
デバッグしてすべての出力をファイルにキャプチャするには、次のようにツールを実行します。
PTDEBUG=1 pt-visual-explain ... > ファイル 2>&1
注意: デバッグ出力は大量であり、数メガバイトの出力が生成される可能性があります。
SYSTEM 募集要項
Perl、DBI、DBD::mysql、およびいくつかのコア パッケージが必要です。
Perlのかなり新しいバージョン。
onworks.net サービスを使用して pt-visual-explainp をオンラインで使用する