Db2のコマンド逆引き（環境の確認）

既に構築されたDBがどのような環境になっているか実機で確認したいようなときに使えるコマンドの覚書。
＝＝＝随時更新予定＝＝＝
// 2018-11-29
* 表やインデックスの配置先表スペースおよびコンテナ確認手順追記
* `db2pd`による環境確認追記

# 前提環境
+ Db2 V11.1

# 環境確認コマンド逆引きリファレンス
詳細は公式マニュアルにリンクを貼ることにして、ここでは典型的な使い方のコマンド実行例を記載する（オプション不要なものはコマンド名のみ）。また、文末に用語集としてDb2の構成概要を載せておく。
あえてカテゴライズはせずに、大きな単位（Db2のインストールレベル）から小さな単位（コンテナやページ）に向かって確認していく。
なお、製品製造元の意図かどうかはともかく["There's more than one way to do it"](https://en.wikipedia.org/wiki/There%27s_more_than_one_way_to_do_it)なので、適当な範囲で複数の手段を記載しておく。

## インストールの確認

### Db2のバージョン情報
[db2level](https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.1.0/com.ibm.db2.luw.admin.cmd.doc/doc/r0009195.html)

### ライセンスの確認（フィーチャーなどのライセンス準拠確認）
[db2licm](https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.1.0/com.ibm.db2.luw.admin.cmd.doc/doc/r0002451.html)

```bash
db2licm -l # リスト表示
db2licm -g /tmp/db2_compliant.txt # コンプライアンスチェック結果をファイル出力
cat /tmp/db2_compliant.txt
```

### インストール済みDb2製品・フィーチャーの確認
[db2ls](https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.1.0/com.ibm.db2.luw.admin.cmd.doc/doc/r0023668.html)
[ENV_FEATURE_INFO管理ビュー](https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.1.0/com.ibm.db2.luw.sql.rtn.doc/doc/r0052409.html)からも確認が可能。

```bash
db2ls

db2 "SELECT * FROM SYSIBMADM.ENV_FEATURE_INFO"
```

## インスタンスの確認
### インスタンスのリスト
[db2ilist](https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.1.0/com.ibm.db2.luw.admin.cmd.doc/doc/r0002059.html)
その他では、"/etc/services"にもサービスポート番号が記載されるので、何らかの手がかりにはなるかもしれない。

### インスタンスポートの確認
[db2 "GET DBM CFG"](https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.1.0/com.ibm.db2.luw.admin.cmd.doc/doc/r0001955.html)

```bash
# 純粋にポート番号だけ確認したいとき
db2 "GET DBM CFG" | grep SVCENAME
```

```bash:db2pd
db2pd -dbm  # これだとメモリ上の値とディスク上の値（次回起動時反映）を確認可能
```

## データベースの確認
### データベースの一覧
[db2 "LIST DB DIRECTORY"](https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.1.0/com.ibm.db2.luw.admin.cmd.doc/doc/r0001961.html)

```bash
db2 "LIST DB DIRECTORY"                          # 全データベースのリスト
db2 "LIST DB DIRECTORY ON /path/to/database"     # 特定のローカルデータベースの情報（Local database directory指定）
```

これでどのようなデータベースがシステム上に存在するかわかったので、以降は以下のように当該データベースに接続しての確認とする。

```bash
db2 "CONNECT TO ${DBNAME}"   # ${DBNAME}は上で確認したDB名または別名
```

### 自動ストレージ構成の確認
[ADMIN_GET_STORAGE_PATHS()](https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.1.0/com.ibm.db2.luw.sql.rtn.doc/doc/r0055331.html)

```bash
# 手っ取り早くストレージグループ名とストレージパスのみ取得
db2 "SELECT VARCHAR(storage_group_name,15) AS NAME, VARCHAR(db_storage_path, 20) AS STORAGE_PATH FROM TABLE(ADMIN_GET_STORAGE_PATHS('', -1)) AS T"
# 全情報をファイルにエクスポート（使用状況等もわかる）
db2 "EXPORT TO storagepaths.csv OF DEL SELECT * FROM TABLE(ADMIN_GET_STORAGE_PATHS('',-1)) AS T"
```
出力は、
ストレージグループ名,ストレージグループID,パーティション番号,ストレージパス,DPE（Database Partition Expression）ストレージパス,ストレージパスの状態,ストレージパスID,ファイルシステムID,容量,使用済み容量,自動ストレージパス空き容量
となる。

```bash:db2pd
db2pd -db ${DBNAME} -storage
db2pd -alldbs -storage        # 全アクティブDB確認
```

### 表スペースの確認
[db2 "LIST TABLESPACES"](https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.1.0/com.ibm.db2.luw.admin.cmd.doc/doc/r0002004.html)
なぜかVer9.7から非推奨になってしまった（LISTのが圧倒的につかいやすいんですけど、、、IBMさんいったいどうして？？？）。
[MON_GET_TABLESPACE()](https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.1.0/com.ibm.db2.luw.sql.rtn.doc/doc/r0053943.html)

```bash
db2 "LIST TABLESPACES"

# これと同等の内容を得るには以下のようにする
db2 "SELECT TBSP_ID,VARCHAR(TBSP_NAME,20) AS TBSP_NAME,TBSP_TYPE,TBSP_CONTENT_TYPE,TBSP_STATE FROM TABLE(MON_GET_TABLESPACE(NULL,NULL)) AS T"
```

```bash:db2pd
db2pd -db ${DBNAME} -tablespaces
db2pd -alldbs -tablespaces         # 全アクティブDB確認
```

### コンテナの確認
表スペース情報（表スペースID）がわかったので、その表スペースを構成するコンテナの物理パスを特定できるようになる。
[db2 "LIST TABLESPACE CONTAINERS FOR N](https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.1.0/com.ibm.db2.luw.admin.cmd.doc/doc/r0002002.html)
こちらも"LIST TABLESPACES"同様非推奨になってしまった。
[MON_GET_TABLESPACE()](https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.1.0/com.ibm.db2.luw.sql.rtn.doc/doc/r0053944.html)

```bash
db2 "LIST TABLESPACE CONTAINERS FOR 0"   # 0のところには表スペースIDを指定する（LIST TABLESPACESで確認した値）

# これと同等の内容を得るには以下のようにする
db2 "SELECT TBSP_ID,CONTAINER_ID,CONTAINER_NAME,CONTAINER_TYPE FROM TABLE(MON_GET_CONTAINER(NULL,NULL)) AS T"
```

### 表スペースの使用状況の確認
[SYSIBMADM.TBSP_UTILIZATIONビュー](https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.1.0/com.ibm.db2.luw.sql.rtn.doc/doc/r0022022.html)
[SYSCAT.TABLESPACESビュー](https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.1.0/com.ibm.db2.luw.sql.ref.doc/doc/r0001064.html)

```bash
db2 "SELECT * FROM SYSIBMADM.TBSP_UTILIZATION"

# 画面上見やすい範囲で有益な情報を出力
db2 "SELECT TBSP_ID, VARCHAR(TBSP_NAME,16) AS TBSP_NAME, TBSP_TYPE, TBSP_CONTENT_TYPE, TBSP_TOTAL_SIZE_KB, TBSP_USED_SIZE_KB, TBSP_UTILIZATION_PERCENT, TBSP_PAGE_SIZE, TBSP_EXTENT_SIZE, TBSP_USING_AUTO_STORAGE, TBSP_NUM_CONTAINERS FROM SYSIBMADM.TBSP_UTILIZATION"

# 使用しているバッファープールは出力されないので、別途以下のようにして確認
db2 "SELECT VARCHAR(TBSPACE,16) AS TBSP_NAME,TBSPACEID,BUFFERPOOLID FROM SYSCAT.TABLESPACES"
```

なお、TBSP_USING_AUTO_STORAGEが"1"なら自動ストレージということ。また、ページサイズ（TBSP_PAGE_SIZE）やエクステントサイズ（TBSP_EXTENT_SIZE）もここで確認できる。

### バッファープールの確認
表スペースごとに使用しているバッファープールがわかったので、そいつが使っているバッファープールを確認する。
[SYSCAT.BUFFERPOOLSビュー](https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.1.0/com.ibm.db2.luw.sql.ref.doc/doc/r0001032.html)

```bash
db2 "SELECT VARCHAR(BPNAME,20) AS BP_NAME,BUFFERPOOLID,PAGESIZE FROM SYSCAT.BUFFERPOOLS"

# 表スペースとバッファプール一気に確認するなら以下のようにすればよい
db2 "SELECT a.TBSPACEID,a.TBSPACETYPE,a.PAGESIZE,a.EXTENTSIZE,a.DATATYPE,a.BUFFERPOOLID,VARCHAR(b.BPNAME,16) AS BUFFERPOOL_NAME
FROM SYSCAT.TABLESPACES AS a
LEFT OUTER JOIN SYSCAT.BUFFERPOOLS AS b
ON a.BUFFERPOOLID = b.BUFFERPOOLID"
```

### ログ周りの設定確認
[db2 "GET DB CFG [FOR ${DBNAME}]"](https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.1.0/com.ibm.db2.luw.admin.cmd.doc/doc/r0001954.html)
出力情報を絞るオプションがないので、単にログの設定だけ見たければ"grep log"するとよい。

```bash
db2 "GET DB CFG FOR ${DBNAME}"
db2 "GET DB CFG" | grep -i log
```

```bash:db2pd
db2pd -db ${DBNAME} -dbcfg   # -dbm同様メモリ上の値とディスク上の値を確認可能

db2pd -db ${DBNAME} -logs    # ログの使用状況確認
```

## データベースの中身の確認
ここまでで基盤的な内容は確認できたので、ここからDBの中身を見ていく。

### 表の一覧
[db2 "LIST TABLES"](https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.1.0/com.ibm.db2.luw.admin.cmd.doc/doc/r0001967.html)

```bash
db2 "LIST TABLES"                     # FOR USERが省略時のデフォルトで接続ユーザIDと一致するスキーマのテーブル等
db2 "LIST TABLES FOR SYSTEM"          # カタログ表
db2 "LIST TABLES FOR ALL"             # そのまんまで、すべての表、ビュー、別名
db2 "LIST TABLES FOR SCHEMA db2inst1" # スキーマ指定
```

### 表の内容（列情報など）を取得
[db2 "DESCRIBE TABLE schema.tableName"](https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.1.0/com.ibm.db2.luw.admin.cmd.doc/doc/r0002019.html)

```bash
db2 "DESCRIBE TABLE Hogetbl"
db2 "DESCRIBE TABLE Hogetbl SHOW DETAIL"
```

### リバース・エンジニアリング
[db2look](https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.1.0/com.ibm.db2.luw.admin.cmd.doc/doc/r0002051.html)

```bash
dblook -d ${DBNAME} -createdb   # CREATE DATABASEステートメント
db2look -d ${DBNAME} -e         # DBを複製するのに必要なDDLを生成
```

### 表やインデックスの格納先表スペースおよびコンテナの確認
```sql:全テーブル・インデックスの物理位置とバッファープール情報
--- テーブルの物理位置とバッファープール
--- カレントスキーマのみならWHERE a.tabschema = CURRENT_SCHEMA
SELECT
	VARCHAR(a.tabschema,10) AS schema,
	VARCHAR(a.tabname,50) AS name,
        b.sgid AS stoid,
	VARCHAR(b.sgname,15) AS stogroup,
	VARCHAR(b.tbspace,15) AS tbspname,
	b.bufferpoolid AS bpid,
	VARCHAR(c.bpname,15) AS bpname,
	VARCHAR(d.container_name,100) AS container
FROM SYSCAT.Tables AS a
LEFT OUTER JOIN SYSCAT.Tablespaces AS b ON a.tbspaceid = b.tbspaceid
LEFT OUTER JOIN SYSCAT.Bufferpools AS c ON b.bufferpoolid = c.bufferpoolid
LEFT OUTER JOIN TABLE(MON_GET_CONTAINER(NULL,NULL)) AS d ON a.tbspaceid = d.tbsp_id
ORDER BY schema, name, container
;

--- インデックスの物理位置とバッファープール
--- カレントスキーマのみならWHERE a.indschema = CURRENT_SCHEMA
SELECT
	VARCHAR(a.indschema,10) AS schema,
	VARCHAR(a.indname,50) AS name,
        b.sgid AS stoid,
	VARCHAR(b.sgname,15) AS stogroup,
	VARCHAR(b.tbspace,15) AS tbspname,
	b.bufferpoolid AS bpid,
	VARCHAR(c.bpname,15) AS bpname,
	VARCHAR(d.container_name,100) AS container
FROM SYSCAT.Indexes AS a
LEFT OUTER JOIN SYSCAT.Tablespaces AS b ON a.tbspaceid = b.tbspaceid
LEFT OUTER JOIN SYSCAT.Bufferpools AS c ON b.bufferpoolid = c.bufferpoolid
LEFT OUTER JOIN TABLE(MON_GET_CONTAINER(NULL,NULL)) AS d ON a.tbspaceid = d.tbsp_id
ORDER BY schema, name, container
;
```
## その他便利コマンド
### 接続しているユーザ確認
[db2 "LIST APPLICATIONS"](https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.1.0/com.ibm.db2.luw.admin.cmd.doc/doc/r0001958.html)

### Db2関連のプロセス一覧（Db2専用psコマンド）
[db2_local_ps](https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_11.1.0/com.ibm.db2.luw.admin.cmd.doc/doc/r0051955.html)
※中身はksh

### その他
db2pdコマンドでもいろいろな情報が得られるが、なにせ多機能のため、別の機会にまとめたい。

# 概要（用語集）
Db2の主要なコンポーネントを簡単に記載しておく（~~お絵かきに疲れてしまったので~~環境確認にかかわらないログバッファやI/Oクリーナーといったコンポーネントは省略）。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/232587/20bd7709-a512-68b4-912f-8af1e943c9b7.png)

## インスタンス
最も大きな単位がこれ。OSのユーザプロセスといえばわかりやすいだろうか（実際には複数のサービスやスレッドからなる）。
固有のポートを持つので、ここでは一つのDBサービスとでもいっておく。一つのOS上に複数のインスタンスを作成できる。

## データベース
トランザクションの境界となる単位。一つのインスタンス内に複数のデータベースを作成できる。

## ストレージグループ
後述する表スペースを作成するディスク（ファイルシステム上のディレクトリ）の集合。自動ストレージ機能を使用している場合には、ストレージグループという単位でDb2がデータの配置を適切に管理してくれる。

## 表スペース
表やインデックス、一時表といったデータベースオブジェクトが格納される論理的な領域。

## コンテナ
表スペースのデータが実際に置かれる物理的なファイル。複数のコンテナから表スペースを構成できる（IOを分散できる）。

## バッファープール（BP）
メモリ上の領域。その名の通りバッファであり、適切にウォームアップができていればSELECT照会の結果はディスクIOをすることなく、バッファープールの内容が返される。
更新についても同様で、BPの内容とディスクの内容が異なる（ダーティになる）と、IOクリーナーというバックグラウンドプロセスがディスクへのフラッシュを行う。
一つの表スペースは、必ず一つのBPと紐付けられる。逆に一つのBPは複数の表スペースと関連付けることができる。

## ページ
表スペース（コンテナ）を拡大してみてみると、中身はページという単位で区切られており、そこにレコードが格納される。
ページはDb2がデータを格納するときの最小単位となる（実際にディスクに書き出したりするときはエクステント単位で複数ページをフラッシュする）。

以下の点に注意が必要。

+ デフォルトのページサイズはデータベース作成時に指定し、あとから変更できない
+ バッファープールもページで管理している（なので表スペースとバッファープールのページサイズは一致している必要あり）
+ 一つのレコード（テーブルの行）は、ページをまたいで格納されない（LOBやVARCHARなどを除く）

図で青いバーで示したのが実際の１レコードであり、２番目のページに収まりそうなデータは、連続した空き領域がないので３番目のページに格納されている。
１番目のページには空きがあるものの、ここにデータが格納されることはおそらくない。
ページはフルに使わないようになっている（PCTFREEでページの空きを確保する割合を指定できる）。

## トランザクションログ
RDBMSによって呼び方も様々（OracleではUNDO/REDO、HiRDBではシステムログなど）だが、データの更新要求はトランザクションログに書き込んだ時点でリターンする。
トランザクションログは複数面を持ち、１ファイルあたりの上限サイズとファイル数を定められる（つまりトータルのトランザクションログ容量を固定できる）。
最低でも１トランザクションをまかなえるだけの容量がないといけない（極端な話1 GBのデータを一気に消すような処理をすると1 GB程度の容量が必要）。

# 参考資料
[コマンドチートシート](http://portablecode.info/wp-content/uploads/db2_cheat_sheet.pdf)：対象バージョンは若干古いが、コマンドの関連（ここで確認した値をどこで使うなど）や概要も記載されていて、とてもわかりやすい