拡張イベントを使ってスロークエリを探す で出力されたファイルをkibanaに取り込んでスロークエリの確認をします。
kibanaのインストールはSQLServer+probespawner+Elasticsearch+kibanaの手順で行いました。
probespawner のjsonは添付のように設定しました。
{ "input": ["DatabaseInput"], "DatabaseInput": { "probemodule": { "module": "cooldbprobe", "name" : "DatabaseProbe" }, "output": ["ElasticsearchOutput"], "interval": 60, "url": "jdbc:sqlserver://[対象のDBサーバ]:1433;integratedSecurity=true;databaseName=Master", "driverClassName": "com.microsoft.sqlserver.jdbc.SQLServerDriver", "username": "", "password": "", "minIdle": "2", "maxIdle": "2", "maxAge": "86400", "maxCycles": 1, "sql": [ { "statement": "select CONVERT(varchar(30), xml_data.value('(/event/@timestamp)[1]','datetime') , 127) as '@timestamp' , @@SERVERNAME as servername , @@SERVICENAME as servicename , xml_data.value('(event/@name)[1]', 'varchar(50)') AS class , case when CHARINDEX('Server 2012',@@VERSION,1) > 1 OR xml_data.value('(event/@name)[1]', 'varchar(50)') <>'rpc_completed' then xml_data.value('(/event/data[@name=''duration'']/value)[1]','bigint')/1000000.0 else xml_data.value('(/event/data[@name=''duration'']/value)[1]','bigint')/1000.0 end duration_sec , xml_data.value('(/event/action[@name=''sql_text'']/value)[1]','varchar(max)') sql_text , xml_data.value('(/event/data[@name=''statement'']/value)[1]','varchar(max)') statement , xml_data.value('(/event/action[@name=''client_hostname'']/value)[1]','varchar(max)') hostname , xml_data.value('(/event/action[@name=''username'']/value)[1]','varchar(max)') loginname from (select object_name as event, CONVERT(xml, event_data) as xml_data from sys.fn_xe_file_target_read_file ('G:\\work\\ExtendedEvents_log\\slowquery*.xel', 'G:\\work\\ExtendedEvents_log\\slowquery*.xem', null, null) ) v where DATEADD(hh, 9, xml_data.value('(/event/@timestamp)[1]','datetime')) >= convert(varchar(15),dateadd(MI,-20,getdate()),120)+'0:00' and DATEADD(hh, 9, xml_data.value('(/event/@timestamp)[1]','datetime')) < convert(varchar(15),dateadd(MI,-10,getdate()),120)+'0:00' order by '@timestamp' desc" } ] }, "ElasticsearchOutput": { "class": "elasticsearch", "outputmodule": { "module": "jelh2", "name" : "Elasticsearch" }, "cluster" : "[設定したクラスタ名]", "host" : "[ElasticsearchのIPアドレス]", "port" : 9300, "bulkActions": 1000, "bulkSize": 107374182400, "indexPrefix": "sqlserver", "indexSuffix": "@timestamp", "type": "jdbc", "index_settings": { "index" : { "analysis" : { "analyzer" : { "ana_analyzer" : { "type" : "standard", "tokenizer": "standard", "filter": ["standard", "asciifolding", "lowercase"] }, "sortable": { "tokenizer": "standard", "filter": ["standard", "asciifolding", "lowercase"] } } } } }, "type_mapping": { "jdbc": { "properties" : { "@timestamp" : { "type" : "date" }, "servername" : { "type" : "string", "index" : "not_analyzed", "omit_norms": "true" }, "servicename" : { "type" : "string", "index" : "not_analyzed", "omit_norms": "true" }, "class" : { "type" : "string", "index" : "not_analyzed", "omit_norms": "true" }, "sql_text" : { "type" : "multi_field", "fields" : { "sql_text" : {"type" : "string", "index" : "analyzed", "analyzer": "ana_analyzer"}, "disp" : {"type" : "string", "index" : "not_analyzed"} } }, "statement" : { "type" : "string", "index" : "not_analyzed", "omit_norms": "true" }, "hostname" : { "type" : "string", "index" : "not_analyzed", "omit_norms": "true" }, "loginname" : { "type" : "string", "index" : "not_analyzed", "omit_norms": "true" }, "value" : {"type" : "double" } } } } } }
下記の場所を環境に合わせて修正してください。
8行目
“url”: “jdbc:sqlserver://[対象のDBサーバ]:1433;integratedSecurity=true;databaseName=Master”,
※Windows認証にしましたので、バッチはDBに接続できるユーザで実行します。
25,26行目
“cluster” : “[設定したクラスタ名]”,
“host” : “[ElasticsearchのIPアドレス]”,
その他
18行目のstatement句のSQL文内にスロークエリを取得する時間を指定してあります。
where句で抽出対象時間を20分前から10分前までにしています。
あまり直近時間にすると、拡張イベントのファイル出力が非同期のため、データが落ちてない場合があります。
取得バッチをOSのタスクに登録して、有効/無効化を切り替えたかったので
15行目の maxCyclesを1として、処理を1回で終了するようにしています。
取得バッチ
G:\App\probespawner-master\test.bat
cd /d "%~dp0" probespawner.bat probespawner_sql_sample.json
バッチをタスクに登録して、定期的に実行するとよいと思います。
取得することができました。
sql_text をanalyzedに設定したので、ある程度の文字列検索もできるようです。
表示に利用する時は、sql_text.dispを使います。
まだまだ勉強中なので間違っていたり、無駄な部分があるかもしれません。。。