この記事は Percona Live 2019 in Texas Austin 現地レポ(Session Day 1) – Side.Aの2つ目です。
弊社のロゴを発見
目次
Deep Dive into TiDB SQL Layer
元Alibaba社のMaxConmputeチームにいたZhang Jianさんのセッションです。
個人的に非常に気になっていたTiDBのセッションを聞きました。
TiDBはマルチノード、マルチプロセスのソフトウェアですが、中でもSQLの実行、解析にフォーカスしたセッションでした。
以下内容を箇条書きで記載します。
- TiDBはフロントエンドのMySQLClientとTiDBノードとTiKVノード(+PDB)から構成される
- SQLレイヤはParserから渡されたパースツリーをLogical optimizer、Physical Optimizerが解析し、Root Executer(Main worker)がDistSQLへ実行計画を渡し、各TiKVのCopExecuter(coworker)が実際に処理を実行して、結果がクライアントへ戻される
- Execution Planはexplainコマンドで表示でき、ツリービューはIndex scanなどの情報に加え、各フェーズをCopExecuterが実行したのか、RootExecuterが実行したのかという情報が表示される
- CopExecuterはプッシュダウンされたクエリを並列で実行する
- Logical optimizer
- いくつかのルールに従ってクエリを最適化する
- 不必要なカラム、パーティション、Group by、Max/Min、Outer Joinの削除
- Where、集約関数、Top/LimitのTiKVへのプッシュダウン
- JOINの順序の入れ替え
- Examples
select s.* from s left join t on s.a = t.unique_key
このクエリはselect * from sと等価なのでleft joinは削除される
select sum(distinct s.a) from s left join t on s.b = t.b
このクエリはselect sum(distinct s.a) from sと等価なので書き換えられる
- Physical Optimizer
- データの順序、タスクのタイプを判断する
- select * from s join t on s.a = t.b order by s.aのようなソートがある時に
ソート結果を元にLogilcal optimizerの実行計画と突き合わせて最適化をする
- 統計情報
- カーディナリティの算出は、以下の述語の実行時に行われる
- WHERE
- ON
- GROUP BY
- 統計情報としては以下
- ヒストグラム
- CM-Sketch(https://en.wikipedia.org/wiki/Count%E2%80%93min_sketch)
- TiDBはMySQLのフォークではない(フロントエンドがMySQLプロトコルであるだけ)
- JOINに関してはMySQLよりも戦略は多い
- hash join
- merge join
- hash aggregation
- etc..
- 最もコストを重視するべきはネットワーク
- ほとんどのMySQLのクエリ最適化を実装していますが、以下は未実装
- index merge, loose index scan
- index diveは行わない
- TiDBの各レイヤごとに最適化は行われる
- クエリの実行計画(パラレル実行されるプラン)
- Hash Join
- Index Join
- Hash Aggregate
- https://github.com/pingcap/tidb/projects/11で絶賛開発中
- Index Join
- Step 1
- 外部表からのフェッチ
- Step 2
- main thread/inner thread(TiKV)へのタスクの割当
- Step 3
- 各スレッドによるフェッチ
- Step 4
- 内部表のフェッチ
- Step 5
外部表、内部表、ハッシュ表からのフェッチが完了したらmain threadに通知
- DistSQLの役割
- Cop(coworker)へリクエストを送る
- Copからのレスポンスを受け取る
- TiKVでエラーが発生したときのハンドリング
- 将来的な機能
- Query Plannerの多重化
- マルチカラム統計
- SQL Tuning Adviser
- SQL Plan の展開(Cop単位の実行計画?)
- マルチインデックススキャン
- Queryのパラレル制御&スケジューリング
- クエリ単位でのメモリ制御
とても可能性を感じさせるプロダクトで、すでにCloud Native Computing FoundationのIncubating Projectにリストされていたりと、今後要チェックです!
MariaDB and MySQL – What Statistics Optimizer Needs Or When and How Not to Use Indexes
Vicentju Ciorbaru氏(MariaDBのRoleやWindow関数を実装している方)
MariaDB及びMySQL(どちらかといえば主にMariaDB観点)でオプティマイザに関する内容のセッションが行われました。
以下箇条書きとなります。
- Optimizerはストレージエンジンに以下のような統計情報を確認して実行計画を組み立てる
- テーブルには何行格納されている?
- 全体をスキャンしたときのコストは?
- このインデックスを使ってたくさんの行をスキャンした時のコストは?
- このインデックスにはユニークな値はどのくらいある(カーディナリティ)?
- インデックスの値の範囲内に幾つの値がある?
- また、ストレージエンジンが返す統計情報はそれぞれの実装により様々
- 例として以下を実行
1 2 3 4 |
CREATE TABLE t1 (a INT, B INT, c INT, KEY(a,b)) ENGINE=MyISAM; INSERT t1 VALUES(RAND()*100000,RAND()*100000,RAND()*100000); ... 400,000行 ... SELECT COUNT(DISTINCT a) AS cardinality FROM t1; |
I_S.statisticsでは以下の結果
1 2 3 4 5 6 7 |
SELECT cardinality FROM information_schema.statistics WHERE table_name = "t1" and column_name = "a"; 98304 rows ALTER TABLE t1 ENGINE = InnoDB; SELECT cardinality FROM information_schema.statistics WHERE table_name = "t1" and column_name = "a"; 196914 rows |
- また、統計情報はインデックスに対して収集され、インデックスは以下を必要とする
- 容量
- DMLのパフォーマンスダウン
- それらの解決策としてストレージエンジンから独立した統計情報を必要としていた
- 安定している
- 正確である
- 詳細である
- すべてのストレージエンジンで同じ
- 互換性がある
- そしてヒストグラム統計と、統計の永続化を実装した
- ヒストグラムを実装し、インデックスの有無に関わらず統計情報を収集可能とした
- mysqlスキーマに統計用テーブルを追加した
@@use_stat_tables = [never | complementary | preferably]
@@optimizer_use_condition_selectivity = 1..5
ANALYZE TABLE .. [PERSISTENT FOR ...]
※ 詳しくは以下を参照
https://mariadb.com/kb/en/library/engine-independent-table-statistics/
https://mariadb.com/kb/en/library/histogram-based-statistics/
- MariaDB 10.0では以下の統計を実装
- テーブル統計: 行数
- Index統計: カーディナリティ
- カラム統計 : カーディナリティ/ min:max / 等高ヒストグラム / サンプリング
- MySQL 8.0では以下の統計を実装
- Optimizer統計
- カラム統計
- nullの数
- 等高ヒストグラム・シングルトンヒストグラム
- 不要な値のskipを行いデータセットを小さく保てるために、大きなテーブルではMariaDB 10.0よりも早い
- MariaDB 10.4ではヒストグラム統計がデフォルトで有効化された
- MariaDB 10.4ではヒストグラムがデフォルトで有効化され、従来のフルスキャンではなくサンプリングベースの収集方法となった
今後はMariaDBでもヒストグラム統計のために夜な夜なANALYZE TABLE .. PERSISTENT
を実行するという運用が行われるのかもしれません。