#背景
長年プロダクション環境で稼働しているシステムでは、現在では(機能廃止等に伴い)使われなくなったテーブルが存在することがよくあると思います。
アプリ観点でアクセスログ等から調査する方法もあるかと思いますが、DB観点でも割とシンプルに未使用テーブルを探すことが可能なため、方法についてまとめてみました。
#SQL Serverのテーブルの概念
方法について説明する前に、SQL Serverのテーブルについても簡単にまとめておきます。
SQL Serverの実データは「クラスタ化インデックス」または「ヒープ」というデータ構造で格納されます。1テーブルごとに必ずどちらか一つだけで、クラスタ化インデックスもヒープも存在するテーブルというのは存在しません。
また、SQL Serverではヒープも「インデックスの一種」と捉えられます。(この方が説明がいろいろしやすいです)
実データ以外にも、特定のカラムだけから成るインデックスを任意で複数作成することも可能です。こちらは「非クラスタ化インデックス」と呼ばれています。
以上をまとめると、SQL Serverにおいて、各テーブルは必ず以下の4パターンのいずれかに該当します。
1.クラスタ化インデックスのみ
2.クラスタ化インデックス+1つ以上の非クラスタ化インデックス
3.ヒープのみ
4.ヒープ+1つ以上の非クラスタ化インデックス
###留意事項
正確には、XMLインデックス、空間インデックス、カラムストアインデックス、メモリ最適化テーブルにおける非クラスター化ハッシュインデックス等、別のインデックスも存在しますが、大多数のテーブルは上記4パターンのいずれかに当てはまると思います。
###テーブルの概念についてのまとめ
SQL Serverでは、各テーブルは1つ以上のインデックスの集合として定義されると捉えることができます。
#アイデア
次に、使っていないテーブルをどうやって探していくかについて説明します。
SQL Serverでは、DMV(Dynamic Management View / 動的管理ビュー)を使って各インデックスの最終アクセス時間を確認できます。
SQL Serverにおいて、テーブルはインデックスの集合である、ということを踏まえると、「1つのテーブルの全インデックスの最終アクセス日時が古ければ、現在使われていない」と判断することができます。
どのくらい古ければいいか、という判断は難しいところではありますが、例えば最終アクセス日時が3か月以上前であれば、かなり高い確率で未使用といえると思います。
インデックスへの最終アクセス時刻は、以下の4種類に分類されるため、4種類すべてを考慮するようにクエリを組めばOKです。
出典
#方法
こちらで検出用のクエリを公開しました。
※実行にはVIEW_SERVER_STATE権限が必要です。
使い方について説明します。
####1. @threasholdDateの値を設定
デフォルトでは3か月前の日付となるように作っています。
直接 '2020/01/28'など設定していただいてOKです。
各テーブルごとに、全インデックスへの最終アクセス日時が@threasholdDateを上回らないようなテーブルを検出します。
####2. クエリを実行
取得できたテーブルたちが、未使用と判断できるテーブルです。
TableName:未使用と判断したテーブル名
latest_last_user_seek:そのテーブルの全インデックスにおける最新のuser_seek日時
latest_last_user_scan:そのテーブルの全インデックスにおける最新のuser_scan日時
latest_last_user_lookup:そのテーブルの全インデックスにおける最新のuser_lookup日時
latest_last_user_update:そのテーブルの全インデックスにおける最新のuser_update日時
※NULLの場合は全インデックスで一切アクセスが無かったとの解釈でOKです。
#注意事項
テーブルがレプリケーションされている場合、サブスクライバ側(スレーブ側)では、レプリの配布コマンドによってもuser_seeksカラムがカウントアップされることがあります。
SQL Server2017で検証したところ、クラスタ化インデックスと非クラスタ化インデックスでそれぞれ以下の挙動となりました。
※ヒープはレプリできないため検証対象外です。
■ 非クラスタ化インデックス
insert/update/deleteしたとき:user_updatesが1カウントアップ
■ クラスタ化インデックス
insertしたとき:user_updatesが1カウントアップ
update/deleteしたとき:userseeks/user_updatesが1カウントアップ
そのため、アプリケーションから一切アクセスが無い状態でも、もしパブリッシャ側(マスタ側)でデータ更新が日次バッチ等で行われている場合は、「本当は使われていないけどuser_seeksがカウントアップされ続けているため、使われているテーブルのようにみえる」といった状態になってしまう可能性があります。
基本的には、未使用のテーブルであればマスタ側のデータ更新も停止しているはずなので問題ないかと思いますが、「使われていないけどデータ更新だけはバッチ等で定期的に実行されている場合」は今回紹介した方法では未使用と判断ができないため、別途調査の必要がありそうです。