【SQLServer2016新機能】クエリストアで実行プランの変化を監視する

2016年6月1日にリリースされたSQLServer2016ですが、
まだまだ実運用されてる方は少ないかと思います。

SQLServer2016の新機能には、クエリの高速化、セキュリティの強化、BIツール郡の強化
など様々なトピックがありますが、この記事では
**「クエリストア」**という<font color="Red">**クエリの実行履歴を保存する機能**</font>を使って、
実行プランの変更履歴を確認してみようと思います。



#<i class="fa fa-list"></i> 目次

- クエリストアがあると何が嬉しいの？
- クエリストアを使ってみる
- クエリストアを使ってみた感想
- 参考URL

#<i class="fa fa-question"></i> クエリストアがあると何が嬉しいの？

**チューニングや、性能低下時の調査に大活躍します！**
良くあるシチュエーションとしては、
毎日実行している処理が、ある日突然遅くなった場合です。

「データも増えてないのに、クエリが遅くなった！」
「再起動してからある処理だけDBのレスポンスが悪くなった！」
そんなとき、実行プランの変更が原因かもしれません。

実行プランは、SQLが実行されたときに、どのようにデータを走査して探していくかの手順のことですが、
クエリストアがあれば過去にどのような実行プランが使われたかもGUIで確認することができます。




# <i class="fa fa-caret-square-o-right"></i> クエリストアを使ってみる

クエリストアはDB毎に有効にすることで利用できます。
DBを右クリック⇒プロパティ⇒クエリストア
![2.PNG](https://qiita-image-store.s3.amazonaws.com/0/153290/9ed3224b-3995-ddd8-2242-5865f7b1ab8a.png)

最初は操作モードが[オフ]になっているので、[読み取り、書き込み]に変更して[OK]
これだけでクエリストアが使えるようになります。

クエリストアはこんな画面です。
![概要図.PNG](https://qiita-image-store.s3.amazonaws.com/0/153290/18d44b20-a13e-9dd8-322c-91ae2b791a3c.png)



確認できる情報は以下の通りです。

- CPU時間
- 実行時間
- クエリ毎の実行回数
- 論理読み取り
- 論理書き込み
- メモリ使用量
- 物理読み取り
- クエリ実行毎の実行プラン

この記事では、
**同じクエリが複数回実行される中で、実行プランが変わる事象を再現して、
クエリストア上で確認**してみます。


## 　準備
まず、下記のようなテーブルを作成します。
カラム[ColA]が主キーですが、[ColC]の値に**極端な偏り**をつけます。
[ColC]には、ほとんど1が入っています。2行だけ2,3が入っています。
![17.PNG](https://qiita-image-store.s3.amazonaws.com/0/153290/de432e0e-9979-82ce-8890-3689f506737f.png)

また、カラム[ColC]にインデックスを張っておきます。
![F.PNG](https://qiita-image-store.s3.amazonaws.com/0/153290/cda258d5-4003-4e8a-9cca-81f332972849.png)



**このテーブルに対してColCの値を指定してデータを取得するとき、
取得する値のレコード量によって、以下のように実行プランが変わります。**

■ColC=1を取る場合
ほぼ全件取得なのでインデックスを使ってると余計に時間がかかる⇒<font color="Red">**ColCのインデックスは使わない**</font>

■ColC=2を取る場合
1件のみなのでインデックスが良く効く⇒<font color="Red">**ColCのインデックスを使う**</font>


## 　クエリを実行してみる
今回はパラメータクエリを使います。

まずはCol=2を取得するクエリを3回ほど実行します。

```sql:test.sql
EXEC sp_executesql N'SELECT TOP 10000 * FROM TestTable WHERE ColC = @p1',N'@p1 int', @p1 = 2
```

ColCのインデックスが使われてることも確認できます。
![A.PNG](https://qiita-image-store.s3.amazonaws.com/0/153290/b2278526-b9b9-8ae2-48f9-59d8082a5abf.png)



次にCol=1を指定して実行したいのですが、
実行プランのキャッシュが残っているので、一度クリアします。
キャッシュが残っていると、ずっと同じ実行プランを使い続けます。
このキャッシュはサーバの再起動などでも消えてしまうので、これが実行プランが変わる原因になります。

![11.PNG](https://qiita-image-store.s3.amazonaws.com/0/153290/45deb94a-2858-387c-ea00-97313820670d.png)

それではCol=1で実行してみます。

```sql:test.sql
EXEC sp_executesql N'SELECT TOP 10000 * FROM TestTable WHERE ColC = @p1', N'@p1 int', @p1 = 1
```

ほぼ全件取得になるので、[ColC]のインデックスを使わない実行プランが選ばれるはずです。
![B.PNG](https://qiita-image-store.s3.amazonaws.com/0/153290/0fa688ed-9fb5-9825-3aba-fc60a290f41f.png)

予想通りですね。

問題は次です。
ここでまたCol=2を取得するクエリを実行してみましょう。

```sql:test.sql
EXEC sp_executesql N'SELECT TOP 10000 * FROM TestTable WHERE ColC = @p1',N'@p1 int', @p1 = 2
```

1~3回目ではインデックスを使う実行プランが選ばれましたが、
今はCol=1で実行した時のキャッシュが効いているので、
インデックスを使わない実行プランが選ばれてしまいます！


こういった事象は後から気付きにくいですが、クエリストアがあれば一目瞭然です。

実行速度も大幅に遅くなっているのが分かると思います。
![C.PNG](https://qiita-image-store.s3.amazonaws.com/0/153290/47b8b1f6-307d-4825-b955-a90b2aad7aba.png)


# <i class="fa fa-smile-o"></i> クエリストアを使ってみた感想

・いままで確認が難しかった実行プランの履歴を
　こうして簡単に確認できるだけでも価値があるように思います。
　運用シーンでも活用できる場面は多いのではないでしょうか。

・ただ、クエリプランに保存される情報の中には、
　システム内部で自動的に実行されるクエリも含まれるようで、若干見づらいです。

・また、クエリストアでは実行プランの固定が可能です。
　実行プランの固定はヒント句でも可能ですが、
　クエリの修正をせずにGUIからのみで設定できるのは嬉しいですね。

・個人的に期待していた実行プラン変更などの自動検知は難しそうです。
　ただし、クエリストアの情報は全て、DB内部のシステムビューに格納されているので、
　そのビューを直接参照することで、好きなようにデータを取得することができます。




# <i class="fa fa-file-text-o"></i> 参考URL

クエリのストアを使用した、パフォーマンスの監視
https://msdn.microsoft.com/ja-jp/library/dn817826.aspx

SQLServer自習書
https://www.microsoft.com/ja-jp/cloud-platform/products-SQL-Server-2016-Evaluate.aspx