狠狠撸

狠狠撸Share a Scribd company logo
自己結合SQLクエリ検出ツール
によるチューニングの提案
岸本拓也 株式会社インサイトテクノロジー
Agenda
? 研究テーマとした業務上の課題
? 自己結合SQL例
? 研究課題
? 作成したツールの紹介
? 実証実験結果
? 関連研究
? まとめ
研究テーマとした業務上の課題
? 現在SIおよびユーザ企業向けにRDBMSパフォーマンス監視、
チューニングサービスを提供
? 仕事は主に本番稼働前後が多い
? パフォーマンス問題をもっと開発早期に解決したい
? SQLクエリべからず集を作成し、開発ベンダに参照してもらっている
が、ほとんど遵守されていない
? べからず集に抵触するクエリは開発早期に発見し、パフォーマンス
問題になる前に改修したい
3
V字モデルにおけるパフォーマンス要件の
確認段階
4
パフォーマンス要件 負荷テスト
コーディング規定
べからず集 コードレビュー
この段階でパフォーマンス問題を解決したい
HWスペック
パラメータ
正規化
べからず集抜粋
? 重複が許可されているか一意性が保証されている場合は、"UNION"
ではなく"UNION ALL"の使用を検討してください
? 列名に対して関数を利用しない。(索引が利用されなくなる)
? 列名に対して型変換をしない。(索引が利用されなくなる)
? 列名に対して計算をしない。(索引が利用されなくなる)
? 後方一致、または中間一致のLIKE述語を用いてはいけない。∵前方
一致検索のみ索引が使用される
? 自己結合の排除
自己結合SQL例
? Window関数を用いて書換可能なSQL
※左記抽出対象行
6
id val1 val2
1 50a
1 123b
1 132c
2 44d
2 111e
3 32f
3 13g
3 89h
select id,val1,val2 from tab1 as a, (select
id,max(val1) as val1 from tab1 group by id)
as b where a.id=b.id and a.val1=b.val2;
select id,val1,val2 from (select id,val1,val2,
row_number() over(partition by id order by
val1 desc) row_number from tab1) where
row_number=1;
Tuning前 (3.94秒)
Tuning後 (2.66秒)
自己結合SQLクエリを構造化し解釈する
? 構文解析
? ANTLR4により、SQLクエリの構文解析器を生成
? 構文解析器によりSQLクエリ構文をXML変換出力
? XMLファイルを検証すれば、パフォーマンス向上が可能なSQLクエリを検出で
きるのでは?
研究課題
1. 複雑なSQLクエリのパターンマッチ方法の検討
? 具体的には自己結合SQLクエリ
? Data Base Administrator(DBA)がモデルパターンを増やせるようにする
(プログラムが書けなくてもSQLクエリが書ければO.K.)
2. 開発早期に自己結合SQLクエリを抽出するツール機能の実装
? 単体?結合テスト段階ではデータ量が少ないため、
SQLクエリの書き方が悪くてもパフォーマンス問題は発見できない
? 書き方が悪いSQLクエリを開発早期に洗い出して、 手戻りコストを低減
8
作成したツール
作成したツールアーキテクチャ
9
Parser
Generator
(ANTLR4)
XML
ファイル
Parser
検査対象
SQLクエリ
ファイル
SQLクエ
リ比較
自己結合
SQLモデル
XML
ファイル
ユーザ
自己結合
SQLパターン
自己結合
SQLパターン
自己結合
SQLパターン
XML→リ
スト変換
列,表,関
数名など
の定値
化,削除
サブクエ
リのネス
トタグを
削除
<Step1> <Step2> <Step3> <Step4>
Step1: XML構造→リスト構造に変換
['', 'parse', 'sql_stmt_list', 'sql_stmt', 'factored_select_stmt', 'select_core', 'K_SELECT', 'TOKEN', 'SELECT']
['', 'parse', 'sql_stmt_list', 'sql_stmt', 'factored_select_stmt', 'select_core', 'result_column', 'expr', 'column_name',
'any_name', 'IDENTIFIER', 'TOKEN', 'id']
['', 'parse', 'sql_stmt_list', 'sql_stmt', 'factored_select_stmt', 'select_core', 'K_FROM', 'TOKEN', 'from']
['', 'parse', 'sql_stmt_list', 'sql_stmt', 'factored_select_stmt', 'select_core', 'table_or_subquery', 'table_name',
'any_name', 'IDENTIFIER', 'TOKEN', 'tab1']
<parse id=“-1”>
<sql_stmt_list id=“164”>
<sql_stmt id=“182”>
<factored_select_stmt id=“225”>
<select_core id=“641”>
<K_SELECT id=“128”>
<TOKEN id="128" startline="1" startpos="0" endline="1"
endpos="6">SELECT</TOKEN>
</K_SELECT>
…
select
fromvalue
‘id’ ‘tab1’
構
文
解
析
器
SQLクエリ XML構造
リスト構造
Step2: 列名,表名,関数名などの定値化,削除
? 列名 → 削除
[..'result_column', 'column_name', 'any_name', 'IDENTIFIER', 'TOKEN', 'id']
? エイリアス名 → 削除
[..’table_alias’, ‘any_name', 'IDENTIFIER', 'TOKEN‘,’alias1’]
? リテラル値 → 削除
[.. ‘literal_value’, ‘TOKEN‘,’削除’]
? 表名 → 2回以上出現 → ‘TABS’に変換
→ 1回のみ出現 → ‘TAB’に変換
[.. ‘table_name’, ‘any_name’, ‘IDENTIFIER’, ‘TOKEN’, ‘TAB']
? 関数名 → ‘MIN’は’MAX’に変換
[..'function_name', 'any_name', 'IDENTIFIER', 'TOKEN', ‘MAX']
×
Step3: サブクエリのネストタグを削除(続く)
検査対象SQLクエリ例
SELECT * from tab1 where id =
(SELECT max(id) from tab1)
SQLクエリパターン例
SELECT max(id) from tab1
['', 'parse', 'sql_stmt_list', 'sql_stmt', 'factored_select_stmt',
'select_core', 'K_SELECT', 'TOKEN', 'SELECT']
['', 'parse', 'sql_stmt_list', 'sql_stmt', 'factored_select_stmt',
'select_core', 'result_column', 'expr', 'function_name',
'any_name', 'IDENTIFIER', 'TOKEN', 'max']
['', 'parse', 'sql_stmt_list', 'sql_stmt', 'factored_select_stmt',
'select_core', 'result_column', 'expr', 'TOKENS', 'TOKEN', '(']
…
['', 'parse', 'sql_stmt_list', 'sql_stmt', 'factored_select_stmt',
'select_core', 'expr', 'expr', 'select_stmt', 'select_or_values',
'K_SELECT', 'TOKEN', 'SELECT']
['', 'parse', 'sql_stmt_list', 'sql_stmt', 'factored_select_stmt',
'select_core', 'expr', 'expr', 'select_stmt', 'select_or_values',
'result_column', 'expr', 'function_name', 'any_name',
'IDENTIFIER', 'TOKEN', 'max']
['', 'parse', 'sql_stmt_list', 'sql_stmt', 'factored_select_stmt',
'select_core', 'expr', 'expr', 'select_stmt', 'select_or_values',
'result_column', 'expr', 'TOKENS', 'TOKEN', '(']
…
サブクエリの中をパターンと比較するために、ネスト情
報のタグを削除する必要がある
Step3: サブクエリのネストタグを削除
検査対象SQLクエリリスト例
['', 'parse', 'sql_stmt_list', 'sql_stmt',
'factored_select_stmt', 'select_core', 'expr', 'expr',
'select_stmt', 'select_or_values', 'K_SELECT', 'TOKEN',
'SELECT']
['', 'parse', 'sql_stmt_list', 'sql_stmt',
'factored_select_stmt', 'select_core', 'expr', 'expr',
'select_stmt', 'select_or_values', 'result_column', 'expr',
'function_name', 'any_name', 'IDENTIFIER', 'TOKEN',
'max']
['', 'parse', 'sql_stmt_list', 'sql_stmt',
'factored_select_stmt', 'select_core', 'expr', 'expr',
'select_stmt', 'select_or_values', 'result_column', 'expr',
'TOKENS', 'TOKEN', '(']
…
SQLクエリパターンリスト例
['', 'parse', 'sql_stmt_list', 'sql_stmt', 'factored_select_stmt',
'select_core', 'K_SELECT', 'TOKEN', 'SELECT']
['', 'parse', 'sql_stmt_list', 'sql_stmt', 'factored_select_stmt',
'select_core', 'result_column', 'expr', 'function_name',
'any_name', 'IDENTIFIER', 'TOKEN', 'max']
['', 'parse', 'sql_stmt_list', 'sql_stmt', 'factored_select_stmt',
'select_core', 'result_column', 'expr', 'TOKENS', 'TOKEN', '(']
…
‘expr’, ‘select_stmt’, ‘select_or_values’, ‘table_or_subquery’, ‘join_clause’, ‘common_table_expression’,
‘select_core’, ‘join_constraint’, ‘factored_select_stmt’, ‘insert_stmt’はトルツメ
○
Step4: 比較機能
['', 'parse', 'sql_stmt_list', 'sql_stmt',
'factored_select_stmt', 'select_core', 'K_SELECT',
'TOKEN', 'SELECT']
['', 'parse', 'sql_stmt_list', 'sql_stmt',
'factored_select_stmt', 'select_core',
'result_column', 'expr', 'column_name',
'any_name', 'IDENTIFIER', 'TOKEN']
['', 'parse', 'sql_stmt_list', 'sql_stmt',
'factored_select_stmt', 'select_core',
'result_column', 'expr', 'column_name',
'any_name', 'IDENTIFIER', 'TOKEN']
['', 'parse', 'sql_stmt_list', 'sql_stmt',
'factored_select_stmt', 'select_core', 'K_FROM',
'TOKEN', 'from']
['', 'parse', 'sql_stmt_list', 'sql_stmt',
'factored_select_stmt', 'select_core',
'table_or_subquery', 'table_name', 'any_name',
'IDENTIFIER', 'TOKEN', 'tab1']
['', 'parse', 'sql_stmt_list', 'sql_stmt',
'factored_select_stmt', 'select_core', 'K_SELECT',
'TOKEN', 'SELECT']
['', 'parse', 'sql_stmt_list', 'sql_stmt',
'factored_select_stmt', 'select_core', 'result_column',
'expr', 'column_name', 'any_name', 'IDENTIFIER',
'TOKEN']
['', 'parse', 'sql_stmt_list', 'sql_stmt',
'factored_select_stmt', 'select_core', 'K_FROM',
'TOKEN', 'from']
['', 'parse', 'sql_stmt_list', 'sql_stmt',
'factored_select_stmt', 'select_core',
'table_or_subquery', 'table_name', 'any_name',
'IDENTIFIER', 'TOKEN', 'tab1']
T
r
u
e
T
r
u
e
T
r
u
e
T
r
u
e
検査対象SQLクエリリスト
Select id,name from tab1
自己結合SQLクエリパターンリスト
Select col1 from tab1
全ての自己結合SQLクエリパターンリストがマッチした
場合、書換可能な自己結合SQLクエリとして判定
作成した自己結合SQLクエリパターン1
特定列の最大?最小値をキーとした自己結合
1. SELECT COL1,COL2 FROM TAB1 A,(SELECT COL1,MAX(COL2) FROM TAB1 GROUP
BY COL1) B WHERE A.COL1=B.COL1 AND A.COL2=B.COL2
2. SELECT COL1 FROM TAB1 WHERE COL2 = (SELECT MAX(COL2) FROM TAB1)
3. SELECT COL1,COL2,COL3 FROM TAB1 A INNER JOIN (SELECT
COL1,COL2,MAX(COL3) COL3 FROM TAB1 GROUP BY COL1,COL2) B
ON A.COL1=B.COL1 WHERE A.COL2=B.COL2 AND A.COL3=B.COL3
4. SELECT * FROM TAB1 JOIN TAB2 ON TAB1.COL2=TAB2.COL2
INNER JOIN TAB3 ON
TAB3.COL3 = (SELECT MAX(COL3) FROM TAB3)
作成した自己結合SQLクエリパターン2
特定列をキーとした自己結合
1. SELECT COL1 FROM TAB1 WHERE COL2 IN (SELECT COL2 FROM TAB1)
2. SELECT COL2 FROM TAB1 A,TAB1 B WHERE A.COL1=B.COL1
3. SELECT COL1,COL2 FROM TAB1 A JOIN TAB1 B ON A.COL1=B.COL1
Union句による自己結合
1. SELECT COL1 FROM TAB1 UNION SELECT COL1 FROM TAB1
ツールDEMO
17
実証実験結果
? 顧客の1データベース(Oracle11.2)商用環境
? 実行計画を確認して、自己結合SQLか否かを確認
? 自己結合SQLクエリ132件と非自己結合SQLクエリ261件(計393件)を実験対象
として抽出
18
自己結合
SQLクエリ
非自己結合
SQLクエリ
検査対象件数 132 261
検出できた件数 127 -
誤検出件数 5 12
再現率 精度
96% 95%
誤検出の原因
? 自己結合SQL
パターンファイルの追加はした
実行計画は自己結合をしているが、SQLクエリは結合処理をしていない(OR検索、VIEWの利用)
? 非自己結合SQL:
ツールロジックに不具合があるようだが、未改修
SQLクエリ構文解析によるパフォーマンス
改善関連研究
以下論文およびツールは特定ロジックに基づき、問題のあるクエリを検出
? Belknap(2009): Self-Tuning for SQL Performance in Oracle Database 11g
? Quest(2010): Quest SQL Optimizer for Oracle
? Embarcadero(2010): DB Optimizer XE
? Herodotou (2009): Automated SQL Tuning through Trial and (Sometimes) Error
? Araújo(2014): ARE-SQL: AN ONLINE, AUTOMATIC AND NON-INTRUSIVE APPROACH FOR
REWRITING SQL QUERIES
19
本研究の優位点
? SQLクエリパターンをDBAが増やせるようにした
-SQLクエリパターンファイルを増やせば、検出対象を拡張可能
? 自己結合SQLクエリの検出
まとめ
? パフォーマンスを改善可能な自己結合SQLクエリを検出するツールを開発
? パターンはSQLクエリファイルで作成し、ツールがパターンファイルを取り込む
? Pythonコードが書けないDBAでもモデルを追加できる
? SQLクエリの書き方が改善可能なSQLクエリかどうかを判定
? テストデータが少ない環境でもテスト時に実行されたSQLを取込み、改善可能なSQLを検出
? 負荷テストによるパフォーマンス測定を経ないでパフォーマンス改善が可能
? Oracle商用環境で実証実験を行った
? 再現率96%、精度95%
? 今後
? 自己結合SQLクエリ以外のパターン追加
? 他商用環境でのテスト
? 他ベンダDBMS環境でのテスト
20

More Related Content

自己结合厂辩濒クエリ検出ツールによるチューニングの提案