# 機能設計書 54-Test-DbaDbCompression

## 概要

本ドキュメントは、SQL Serverデータベースのテーブルとインデックスに対する最適な圧縮設定を分析・推奨する機能「Test-DbaDbCompression」の設計仕様を記述する。

### 本機能の処理概要

Test-DbaDbCompressionは、SQL Serverのsp_estimate_data_compression_savings システムプロシージャとワークロードパターン分析を組み合わせて、各テーブル・インデックスに対してROW圧縮、PAGE圧縮、または圧縮なしを推奨する機能である。

**業務上の目的・背景**：データ圧縮は効果的なストレージ最適化手法だが、全オブジェクトに同じ圧縮を適用するのは非効率である。更新頻度が高いテーブルにはROW圧縮が、スキャン主体のテーブルにはPAGE圧縮が適している。本機能は、Microsoftタイガーチームの圧縮分析ロジック（sys.dm_db_index_operational_statsのワークロード統計）に基づき、各オブジェクトに最適な圧縮タイプを自動判定する。

**機能の利用シーン**：
- 圧縮最適化プロジェクトの事前分析
- ストレージ削減効果の見積もり
- Set-DbaDbCompressionへの入力データ生成
- 定期的な圧縮効果レポートの作成

**主要な処理内容**：
1. 対象データベースの未圧縮テーブル・インデックスを列挙
2. sp_estimate_data_compression_savingsでROW/PAGE圧縮の推定サイズを取得
3. sys.dm_db_index_operational_statsから操作統計（スキャン率、更新率）を取得
4. ワークロードパターンに基づき最適な圧縮タイプを判定
5. 圧縮率と推定サイズを計算して出力

**関連システム・外部連携**：
- sp_estimate_data_compression_savings: SQL Server組み込みプロシージャ
- sys.dm_db_index_operational_stats: インデックス操作統計DMV

**権限による制御**：
- 対象データベースへのVIEW DATABASE STATE権限が必要
- sp_estimate_data_compression_savingsの実行権限

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | CLIコマンド | 主画面 | PowerShellコマンドラインからの直接実行 |

## 機能種別

分析 / レポート生成

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| SqlInstance | DbaInstanceParameter[] | Yes | 対象SQL Serverインスタンス | パイプライン入力可能 |
| SqlCredential | PSCredential | No | SQL Server接続用認証情報 | - |
| Database | string[] | No | 対象データベース名 | ワイルドカード対応 |
| ExcludeDatabase | string[] | No | 除外データベース名 | - |
| Schema | string[] | No | 対象スキーマ名 | - |
| Table | string[] | No | 対象テーブル名 | - |
| ResultSize | int | No | 分析対象数の制限 | 1以上の整数 |
| Rank | string | No | ソート基準（デフォルト: TotalPages） | TotalPages/UsedPages/TotalRows |
| FilterBy | string | No | フィルタ粒度（デフォルト: Partition） | Partition/Index/Table |
| EnableException | switch | No | 例外をスローする | - |

### 入力データソース

- sys.tables: テーブル一覧
- sys.indexes: インデックス一覧
- sys.partitions: パーティション情報
- sys.dm_db_index_operational_stats: インデックス操作統計

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ComputerName | string | SQL Serverインスタンスのコンピュータ名 |
| InstanceName | string | SQL Serverインスタンス名 |
| SqlInstance | string | 完全なSQL Serverインスタンス名 |
| Database | string | データベース名 |
| Schema | string | スキーマ名 |
| TableName | string | テーブル名 |
| IndexName | string | インデックス名（ヒープの場合はnull） |
| Partition | int | パーティション番号 |
| IndexID | int | インデックスID |
| IndexType | string | インデックスタイプ |
| PercentScan | smallint | スキャン操作の割合（0-100） |
| PercentUpdate | smallint | 更新操作の割合（0-100） |
| RowEstimatePercentOriginal | bigint | ROW圧縮時の推定サイズ比率 |
| PageEstimatePercentOriginal | bigint | PAGE圧縮時の推定サイズ比率 |
| CompressionTypeRecommendation | string | 推奨圧縮タイプ（ROW/PAGE/NO_GAIN/?） |
| SizeCurrent | dbasize | 現在のサイズ（バイト） |
| SizeRequested | dbasize | 推奨圧縮後の推定サイズ |
| PercentCompression | decimal | 推定圧縮率 |

### 出力先

PowerShellパイプライン（即座に出力）

## 処理フロー

### 処理シーケンス

```
1. SQL Serverインスタンスに接続
   └─ Connect-DbaInstance -MinimumVersion 10

2. SQLバージョンに応じた除外条件構築
   └─ SQL 2012+: メモリ最適化、FileTable除外
   └─ SQL 2014+: 暗号化列除外
   └─ SQL 2017+: グラフテーブル除外

3. 一時テーブル作成と対象オブジェクト列挙
   └─ ##TestDbaCompression に未圧縮オブジェクトを登録

4. ResultSizeによるフィルタリング
   └─ Top N件に絞り込み（Rank基準でソート）

5. 除外対象の削除
   └─ スパースカラム、FileStreamカラム、バージョン固有除外

6. sp_estimate_data_compression_savings実行
   └─ 各オブジェクトに対してROW/PAGEの推定サイズ取得

7. 操作統計更新
   └─ sys.dm_db_index_operational_statsからPercentScan/PercentUpdate計算

8. 圧縮推奨判定
   └─ ワークロードパターンに基づきROW/PAGE/NO_GAIN/?を判定

9. 結果取得と出力
   └─ ##TestDbaCompressionから結果を取得しPSCustomObject出力
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[Connect-DbaInstance]
    B --> C{接続成功?}
    C -->|No| D[Stop-Function]
    D --> A
    C -->|Yes| E[バージョン別除外条件構築]
    E --> F[データベースフィルタ]
    F --> G[データベースループ]
    G --> H{Status = Normal?}
    H -->|No| I[スキップ]
    I --> G
    H -->|Yes| J{CompatLevel >= 100?}
    J -->|No| I
    J -->|Yes| K[SQL実行: 一時テーブル作成]
    K --> L[SQL実行: オブジェクト列挙]
    L --> M[SQL実行: ResultSizeフィルタ]
    M --> N[SQL実行: 除外対象削除]
    N --> O[SQL実行: sp_estimate呼び出し]
    O --> P[SQL実行: 操作統計更新]
    P --> Q[SQL実行: 圧縮推奨判定]
    Q --> R[結果取得]
    R --> S[PSCustomObject出力]
    S --> T{次のDB?}
    T -->|Yes| G
    T -->|No| U[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 未圧縮のみ対象 | data_compression_desc = 'NONE'のみ分析 | 常時 |
| BR-02 | メモリ最適化除外 | is_memory_optimized = 1は除外 | SQL 2012+ |
| BR-03 | FileTable除外 | is_filetable = 1は除外 | SQL 2012+ |
| BR-04 | 暗号化列除外 | encryption_type IS NOT NULLは除外 | SQL 2014+ |
| BR-05 | グラフテーブル除外 | is_node = 1 OR is_edge = 1は除外 | SQL 2017+ |
| BR-06 | スパースカラム除外 | is_sparse = 1を含むテーブルは除外 | 常時 |
| BR-07 | FileStreamカラム除外 | is_filestream = 1を含むテーブルは除外 | 常時 |

### 計算ロジック

**PercentScan計算**:
```sql
range_scan_count * 100.0 /
(range_scan_count + leaf_insert_count + leaf_delete_count +
 leaf_update_count + leaf_page_merge_count + singleton_lookup_count)
```

**PercentUpdate計算**:
```sql
leaf_update_count * 100.0 /
(range_scan_count + leaf_insert_count + leaf_delete_count +
 leaf_update_count + leaf_page_merge_count + singleton_lookup_count)
```

**CompressionTypeRecommendation判定**:
| 条件 | 推奨 |
|------|------|
| RowCounts = 0 | ? |
| RowEstimate >= 100 AND PageEstimate >= 100 | NO_GAIN |
| PercentUpdate >= 10 | ROW |
| PercentScan <= 1 AND PercentUpdate <= 1 AND RowEstimate < PageEstimate | ROW |
| PercentScan <= 1 AND PercentUpdate <= 1 AND RowEstimate > PageEstimate | PAGE |
| PercentScan >= 60 AND PercentUpdate <= 5 | PAGE |
| PercentScan <= 35 AND PercentUpdate <= 5 | ? |
| その他 | ROW |

**PercentCompression計算**:
```sql
100 - (SizeRequested * 100 / SizeCurrent)
```

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 一時テーブル作成 | ##TestDbaCompression等 | CREATE TABLE | tempdbに一時テーブル作成 |
| オブジェクト列挙 | sys.tables, sys.indexes等 | SELECT | システムビュー参照 |
| 圧縮推定 | sp_estimate_data_compression_savings | EXEC | 共有ロック取得あり |
| 操作統計取得 | sys.dm_db_index_operational_stats | SELECT | DMV参照 |

### テーブル別操作詳細

#### ##TestDbaCompression（一時テーブル）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | Schema, TableName, IndexName等 | sys.tablesから取得 | 初期登録 |
| UPDATE | PercentScan, PercentUpdate | DMVから計算 | 操作統計 |
| UPDATE | RowEstimate, PageEstimate | sp_estimateから取得 | 圧縮推定 |
| UPDATE | CompressionTypeRecommendation | 判定ロジックで決定 | 最終推奨 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ConnectionError | 接続エラー | SQL Serverに接続できない | Stop-Functionで処理継続 |
| DatabaseAccessError | データベースアクセスエラー | データベースが非アクセス可能 | Warning出力で継続 |
| VersionError | バージョンエラー | SQL 2016 SP1未満 + 非Enterprise | Stop-Functionでスキップ |
| QueryError | クエリエラー | SQL実行失敗 | Stop-Functionで処理継続 |

### リトライ仕様

特になし。各データベースは独立して処理され、失敗時は次へ継続する。

## トランザクション仕様

読み取り専用分析のためトランザクション制御なし。ただし、sp_estimate_data_compression_savingsは対象テーブルに共有ロックを取得するため、同時実行アクティビティに影響を与える可能性がある。

## パフォーマンス要件

- 大規模データベースでは多数のsp_estimate呼び出しにより長時間かかる場合がある
- ResultSizeパラメータで分析対象を制限することで高速化可能
- サーバー稼働時間が長いほど操作統計の精度が向上

## セキュリティ考慮事項

- SqlCredentialによる認証情報の安全な受け渡し
- 読み取り専用分析（書き込みなし）

## 備考

- GitHub Microsoft/tigertoolboxのEvaluate-Compression-Gainsスクリプトがベース
- ROW/PAGE圧縮のみ分析、Columnstore圧縮は対象外
- サーバー再起動後はDMVの操作統計がリセットされるため、Get-DbaUptimeで稼働時間確認推奨

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

出力されるPSCustomObjectとSQL一時テーブル構造を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Test-DbaDbCompression.ps1 | `public/Test-DbaDbCompression.ps1` | 339-356行目（##TestDbaCompressionテーブル定義） |
| 1-2 | Test-DbaDbCompression.ps1 | `public/Test-DbaDbCompression.ps1` | 687-706行目（PSCustomObject出力） |

**読解のコツ**: SQL一時テーブルの構造が出力オブジェクトのプロパティに対応している。

#### Step 2: エントリーポイントを理解する

パラメータ定義とbegin blockのSQL構築を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Test-DbaDbCompression.ps1 | `public/Test-DbaDbCompression.ps1` | 175-190行目（パラメータ定義） |
| 2-2 | Test-DbaDbCompression.ps1 | `public/Test-DbaDbCompression.ps1` | 192-264行目（begin block: ResultSizeフィルタSQL構築） |

**主要処理フロー**:
1. **192-264行目**: Schema/Table/ResultSizeに応じたSQL動的構築
2. **204-225行目**: FilterByパラメータでグルーピング粒度を決定

#### Step 3: バージョン別除外条件を理解する

SQL Serverバージョンに応じた除外条件構築を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Test-DbaDbCompression.ps1 | `public/Test-DbaDbCompression.ps1` | 278-327行目 |

**主要処理フロー**:
- **280-301行目**: SQL 2012+ (Version 12) でメモリ最適化、FileTable除外
- **302-315行目**: SQL 2014+ (Version 13) で暗号化列除外
- **316-327行目**: SQL 2017+ (Version 14) でグラフテーブル除外

#### Step 4: メインSQLロジックを理解する

一時テーブル操作と圧縮推定のSQLを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Test-DbaDbCompression.ps1 | `public/Test-DbaDbCompression.ps1` | 328-643行目 |

**主要処理フロー**:
- **339-378行目**: 一時テーブル作成
- **380-411行目**: 未圧縮オブジェクト列挙INSERT
- **443-503行目**: sp_estimate_data_compression_savingsカーソル実行
- **506-519行目**: PercentScan/PercentUpdate計算UPDATE
- **568-613行目**: CompressionTypeRecommendation判定UPDATE

#### Step 5: 圧縮推奨判定ロジックを理解する

CASE文による推奨判定を詳細確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | Test-DbaDbCompression.ps1 | `public/Test-DbaDbCompression.ps1` | 575-606行目 |

**主要処理フロー**:
- **579-580行目**: RowCounts = 0なら'?'
- **583-585行目**: 両Estimate >= 100ならNO_GAIN
- **586-587行目**: PercentUpdate >= 10ならROW
- **588-595行目**: 低活動時はEstimate比較でROW/PAGE
- **596-598行目**: 高スキャン・低更新ならPAGE

### プログラム呼び出し階層図

```
Test-DbaDbCompression
    │
    ├─ Connect-DbaInstance (SQL Server接続)
    │
    └─ [foreach: Database]
           │
           ├─ Server.Query($sql) (大規模SQL実行)
           │      │
           │      ├─ CREATE TABLE ##TestDbaCompression
           │      │
           │      ├─ INSERT: 未圧縮オブジェクト列挙
           │      │      └─ sys.tables JOIN sys.indexes JOIN sys.partitions
           │      │
           │      ├─ DELETE: 除外対象削除
           │      │      └─ スパース、FileStream、バージョン固有除外
           │      │
           │      ├─ CURSOR: sp_estimate_data_compression_savings
           │      │      └─ ROW/PAGE推定サイズ取得
           │      │
           │      ├─ UPDATE: 操作統計
           │      │      └─ sys.dm_db_index_operational_stats
           │      │
           │      ├─ UPDATE: 圧縮推奨判定
           │      │      └─ CASE文による分類
           │      │
           │      └─ SELECT: 結果取得
           │
           └─ PSCustomObject出力
```

### データフロー図

```
[入力]                         [処理]                              [出力]

SqlInstance ─────────────▶ Connect-DbaInstance
                                   │
                                   ▼
Database/Schema/Table ────▶ フィルタSQL構築
                                   │
                                   ▼
                          ##TestDbaCompression作成
                                   │
                                   ▼
sys.tables/indexes/       未圧縮オブジェクト
partitions ───────────────▶ INSERT
                                   │
                                   ▼
                          除外対象DELETE
                                   │
                                   ▼
sp_estimate_data_         ROW/PAGE推定
compression_savings ──────▶ 取得
                                   │
                                   ▼
sys.dm_db_index_          PercentScan/
operational_stats ────────▶ PercentUpdate計算
                                   │
                                   ▼
                          CompressionType判定
                                   │
                                   ▼
                          PSCustomObject ────────────────▶ パイプライン
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Test-DbaDbCompression.ps1 | `public/Test-DbaDbCompression.ps1` | ソース | メイン機能実装 |
| Set-DbaDbCompression.ps1 | `public/Set-DbaDbCompression.ps1` | ソース | 関連機能（推奨適用） |
| Get-DbaDbCompression.ps1 | `public/Get-DbaDbCompression.ps1` | ソース | 関連機能（現状取得） |
| Get-DbaBuild.ps1 | `public/Get-DbaBuild.ps1` | ソース | SQLバージョン取得 |
| Connect-DbaInstance.ps1 | `public/Connect-DbaInstance.ps1` | ソース | SQL Server接続 |
