# 機能設計書 170-Invoke-DbaDbShrink

## 概要

本ドキュメントは、dbatools PowerShellモジュールの`Invoke-DbaDbShrink`コマンドレットに関する機能設計書である。このコマンドは、データベースファイル（データファイルおよびログファイル）から未使用領域を削除してファイルサイズを縮小する機能を提供する。

### 本機能の処理概要

Invoke-DbaDbShrinkは、データベースファイルのサイズを縮小し、未使用領域をディスクに解放する。データファイル、ログファイル、または両方を対象とし、段階的な縮小（StepSize）やフラグメンテーション統計の取得をサポートする。

**業務上の目的・背景**：
データベースは時間とともに成長し、大量のデータ削除やインデックス再構築後に未使用領域が残ることがある。ディスク容量が逼迫した緊急時や、データベース移行の準備として、この未使用領域を回収する必要がある。ただし、縮小操作はインデックスフラグメンテーションを引き起こすため、慎重に使用すべきである。

**機能の利用シーン**：
- 緊急のディスク容量回復
- 大量データ削除後の領域回収
- データベース移行前のサイズ最適化
- テスト環境のクリーンアップ

**主要な処理内容**：
1. 対象データベース/ファイルの特定
2. DBCC UPDATEUSAGE実行（オプション）
3. 縮小前のフラグメンテーション統計取得（オプション）
4. SMO Shrinkメソッドによるファイル縮小
5. StepSize指定時は段階的縮小
6. 縮小後のフラグメンテーション統計取得（オプション）
7. 結果の出力（サイズ変更、フラグメンテーション統計）

**関連システム・外部連携**：
- SQL Server Database Engine
- SMO（Server Management Objects）
- sys.dm_db_index_physical_stats（フラグメンテーション統計）

**権限による制御**：
- sysadminまたはdb_owner権限が必要
- スナップショットデータベースは縮小不可

## 関連画面

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

## 機能種別

ユーティリティ / メンテナンス / ストレージ管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| SqlInstance | DbaInstanceParameter[] | No | ターゲットSQL Serverインスタンス | パイプライン入力対応 |
| SqlCredential | PSCredential | No | 代替資格情報 | - |
| Database | object[] | No | 縮小対象データベース | - |
| ExcludeDatabase | object[] | No | 除外データベース | - |
| AllUserDatabases | switch | No | 全ユーザーデータベースを対象 | - |
| PercentFreeSpace | int | No | 縮小後の空き領域割合（デフォルト: 0） | ValidateRange 0-99 |
| ShrinkMethod | string | No | 縮小方法（デフォルト: Default） | ValidateSet: 'Default', 'EmptyFile', 'NoTruncate', 'TruncateOnly' |
| FileType | string | No | 対象ファイル種別（デフォルト: All） | ValidateSet: 'All', 'Data', 'Log' |
| StepSize | int64 | No | 段階的縮小のステップサイズ | 1024以上（バイト単位） |
| StatementTimeout | int | No | コマンドタイムアウト（分）（デフォルト: 0） | - |
| ExcludeIndexStats | switch | No | インデックス統計を除外 | - |
| ExcludeUpdateUsage | switch | No | UPDATEUSAGE実行を除外 | - |
| EnableException | switch | No | 例外を有効化 | - |
| InputObject | Database[] | No | パイプラインからのデータベースオブジェクト | - |

### 入力データソース

- コマンドライン引数
- パイプライン入力（SqlInstance, InputObject）
- Get-DbaDatabase出力

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ComputerName | string | SQL Serverインスタンスのコンピュータ名 |
| InstanceName | string | SQL Serverインスタンス名 |
| SqlInstance | string | 完全なSQL Serverインスタンス名（computer\instance） |
| Database | string | データベース名 |
| File | string | 縮小対象ファイルの論理名 |
| Start | datetime | 縮小開始日時 |
| End | datetime | 縮小終了日時 |
| Elapsed | string | 経過時間（HH:mm:ss形式） |
| Success | bool | 縮小成功フラグ |
| InitialSize | dbasize | 縮小前のファイルサイズ |
| InitialUsed | dbasize | 縮小前の使用領域 |
| InitialAvailable | dbasize | 縮小前の空き領域 |
| TargetAvailable | dbasize | 目標空き領域（PercentFreeSpaceから算出） |
| FinalAvailable | dbasize | 縮小後の空き領域 |
| FinalSize | dbasize | 縮小後のファイルサイズ |
| InitialAverageFragmentation | decimal | 縮小前の平均フラグメンテーション（%） |
| FinalAverageFragmentation | decimal | 縮小後の平均フラグメンテーション（%） |
| InitialTopFragmentation | decimal | 縮小前の最大フラグメンテーション（%） |
| FinalTopFragmentation | decimal | 縮小後の最大フラグメンテーション（%） |
| Notes | string | 警告メッセージ（インデックス再構築推奨） |

### 出力先

- コンソール（PSCustomObject）

## 処理フロー

### 処理シーケンス

```
1. beginブロック
   ├─ StepSizeバリデーション（1024以上）
   ├─ stepSizeKBの計算
   ├─ StatementTimeoutSecondsの計算
   └─ フラグメンテーションクエリ定義
2. processブロック
   ├─ パラメータ検証（Database/ExcludeDatabase/AllUserDatabases/InputObject）
   ├─ SqlInstanceループ
   │   ├─ Connect-DbaInstance
   │   └─ データベースフィルタリング
   │       ├─ IsAccessible
   │       ├─ AllUserDatabases → IsSystemObject=false
   │       ├─ Database指定
   │       └─ ExcludeDatabase適用
   └─ InputObjectループ
       ├─ スナップショットチェック（スキップ）
       ├─ ファイル取得（FileType: All/Data/Log）
       └─ ファイルループ
           ├─ サイズ計算（Initial, Target）
           ├─ サイズ検証（縮小可能か）
           ├─ 縮小前フラグメンテーション取得（ExcludeIndexStats=false時）
           ├─ タイムアウト設定
           ├─ 縮小実行
           │   ├─ StepSize指定時: 段階的縮小
           │   └─ StepSize未指定時: 一括縮小
           ├─ 縮小後フラグメンテーション取得（ExcludeIndexStats=false時）
           └─ 結果オブジェクト生成
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{StepSize >= 1024?}
    B -->|No| C[Stop-Function]
    B -->|Yes| D[stepSizeKB計算]
    C --> Z[終了]
    D --> E[StatementTimeoutSeconds計算]
    E --> F{Database/AllUserDatabases/InputObject指定?}
    F -->|No| G[Stop-Function]
    F -->|Yes| H[SqlInstanceループ]

    H --> I[Connect-DbaInstance]
    I --> J[データベースフィルタリング]
    J --> K[InputObject追加]
    K --> L[InputObjectループ]

    L --> M{IsDatabaseSnapshot?}
    M -->|Yes| L
    M -->|No| N[ファイル取得]

    N --> O[ファイルループ]
    O --> P[サイズ計算]
    P --> Q{空き領域 > 目標?}
    Q -->|No| R[Warning出力]
    Q -->|Yes| S[ShouldProcess確認]
    R --> O

    S --> T{ExcludeIndexStats?}
    T -->|No| U[縮小前フラグメンテーション取得]
    T -->|Yes| V[タイムアウト設定]
    U --> V

    V --> W{StepSize指定?}
    W -->|Yes| X[段階的縮小ループ]
    W -->|No| Y[一括縮小]

    X --> AA[ステップ計算]
    AA --> AB[Shrink実行]
    AB --> AC[Refresh]
    AC --> AD{サイズ変化?}
    AD -->|No| AE[break]
    AD -->|Yes| AF{次のステップ?}
    AF -->|Yes| AA
    AF -->|No| AG[タイムアウト復元]
    AE --> AG

    Y --> AG

    AG --> AH{ExcludeIndexStats?}
    AH -->|No| AI[縮小後フラグメンテーション取得]
    AH -->|Yes| AJ[結果オブジェクト生成]
    AI --> AJ

    AJ --> AK{次のファイル?}
    AK -->|Yes| O
    AK -->|No| AL{次のDB?}
    AL -->|Yes| L
    AL -->|No| AM{次のインスタンス?}
    AM -->|Yes| H
    AM -->|No| Z
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | PercentFreeSpaceデフォルト | デフォルト0%（最大縮小） | 常時 |
| BR-002 | スナップショット除外 | スナップショットDBは縮小不可 | 常時 |
| BR-003 | アクセス可能DB | IsAccessible=trueのみ対象 | 常時 |
| BR-004 | StepSize最小値 | 1024バイト以上 | StepSize指定時 |
| BR-005 | StatementTimeout | デフォルト0（無限） | 常時 |
| BR-006 | ShrinkMethodデフォルト | Default（データ移動＋ファイル切り詰め） | 常時 |
| BR-007 | FileTypeデフォルト | All（データ＋ログ） | 常時 |
| BR-008 | フラグメンテーション警告 | 縮小後はインデックス再構築推奨 | 常時 |

### 計算ロジック

**目標空き領域の計算**:
```
TargetAvailable = (PercentFreeSpace / 100) * UsedSpace
TargetFileSize = UsedSpace + TargetAvailable
```

**段階的縮小の計算**:
```
ShrinkGap = InitialSize - TargetSize
NumberIterations = Ceiling(ShrinkGap / StepSize)
ShrinkSizePerStep = InitialSize - (StepSize * iteration)
```

**フラグメンテーション統計クエリ**:
```sql
SELECT
  AVG(avg_fragmentation_in_percent) AS avg_fragmentation_in_percent,
  MAX(avg_fragmentation_in_percent) AS max_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS indexstats
WHERE indexstats.avg_fragmentation_in_percent > 0 AND indexstats.page_count > 100
GROUP BY indexstats.database_id
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| フラグメンテーション取得 | sys.dm_db_index_physical_stats | SELECT | インデックスフラグメンテーション統計 |
| ファイル縮小 | データベースファイル | DBCC SHRINKFILE | ファイルサイズの縮小 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ValidationError | StepSize < 1024 | Stop-Function -Return |
| - | ValidationError | Database/AllUserDatabases/InputObject未指定 | Stop-Function |
| - | ConnectionError | SQL Server接続失敗 | Stop-Function -Continue |
| - | ShrinkError | 縮小操作失敗 | Stop-Function -Continue |
| - | SkipWarning | スナップショットDB | Warning出力、スキップ |
| - | SkipWarning | 空き領域 <= 目標 | Warning出力、スキップ |

### リトライ仕様

リトライ機能なし（エラー発生時は次のファイル/データベースに継続）

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

- トランザクション管理なし
- SMO Shrinkメソッドは内部でDBCC SHRINKFILEを実行

## パフォーマンス要件

- 大規模データベースの縮小は時間がかかる
- StepSizeで段階的縮小を推奨
- StatementTimeout=0（無限）がデフォルト
- 縮小中はI/O負荷が高い
- インデックスフラグメンテーションが発生

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

- sysadminまたはdb_owner権限が必要
- ConfirmImpact='Low'（確認プロンプトなし）
- WhatIfサポート

## 備考

- 縮小はインデックスフラグメンテーションを引き起こすため、縮小後はDBCC INDEXDEFRAGまたはALTER INDEX REORGANIZEの実行を推奨
- 本番環境での使用は慎重に
- ShrinkMethod:
  - Default: データ移動＋ファイル切り詰め
  - EmptyFile: 全データを他ファイルに移動
  - NoTruncate: データ移動のみ
  - TruncateOnly: 切り詰めのみ（データ移動なし、最もリソース軽量）

---

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

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

### 推奨読解順序

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

縮小処理のサイズ計算とdbasize型を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | dbasize型 | 269-273行目 | KB→バイト変換、dbasize型使用 |
| 1-2 | フラグメンテーションクエリ | 205-210行目 | sys.dm_db_index_physical_stats |

**読解のコツ**: file.SizeとUsedSpaceはKB単位、dbasize型はバイト単位で処理される。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Invoke-DbaDbShrink.ps1 | `public/Invoke-DbaDbShrink.ps1` | 関数全体の構造とパラメータ定義 |

**主要処理フロー**:
1. **169-191行目**: パラメータ定義
2. **193-211行目**: beginブロック（バリデーション、クエリ定義）
3. **213-385行目**: processブロック（メイン処理）

#### Step 3: パラメータ検証と初期化

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | StepSizeバリデーション | 195-198行目 | 1024以上チェック |
| 3-2 | stepSizeKB計算 | 200-202行目 | dbasize型でKB変換 |
| 3-3 | StatementTimeout計算 | 203行目 | 分→秒変換 |

**主要処理フロー**:
- **195行目**: `Test-Bound -ParameterName StepSize`
- **201行目**: `([dbasize]($StepSize)).Kilobyte`

#### Step 4: データベース・ファイル取得

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | パラメータ検証 | 216-219行目 | Database/AllUserDatabases/InputObject必須 |
| 4-2 | データベースフィルタ | 228-244行目 | IsAccessible, IsSystemObject, Database, ExcludeDatabase |
| 4-3 | ファイル取得 | 258-264行目 | FileType: Log/Data/All |

**主要処理フロー**:
- **253-256行目**: スナップショットチェック
- **259-264行目**: LogFiles, FileGroups.Filesの取得

#### Step 5: 縮小処理

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | サイズ計算 | 268-273行目 | Initial, Used, Available, Target計算 |
| 5-2 | 縮小前フラグメンテーション | 286-293行目 | sys.dm_db_index_physical_stats |
| 5-3 | 段階的縮小 | 306-322行目 | StepSize指定時のループ処理 |
| 5-4 | 一括縮小 | 323-326行目 | StepSize未指定時 |
| 5-5 | 縮小後フラグメンテーション | 341-348行目 | FileType != Log時のみ |

**主要処理フロー**:
- **315行目**: `$file.Shrink($shrinkSizeKB.Megabyte, $ShrinkMethod)`
- **316行目**: `$file.Refresh()`
- **318-321行目**: サイズ変化なし時のbreak

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

```
Invoke-DbaDbShrink
    │
    ├─ Test-Bound
    │      └─ パラメータバインドチェック
    │
    ├─ Connect-DbaInstance
    │      └─ SQL Server接続
    │
    ├─ $server.Databases
    │      └─ データベース取得
    │
    ├─ $db.LogFiles
    │  $db.FileGroups.Files
    │      └─ ファイル取得
    │
    ├─ $server.Query()
    │      └─ sys.dm_db_index_physical_stats
    │
    ├─ $file.Shrink()
    │      └─ SMO Shrinkメソッド
    │
    ├─ $file.Refresh()
    │      └─ ファイル情報再取得
    │
    └─ Select-DefaultView
           └─ ExcludeIndexStats時のプロパティ除外
```

### データフロー図

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

SqlInstance ──────────────────▶ Connect-DbaInstance
SqlCredential ────────────────▶
                                        │
Database ─────────────────────▶ データベースフィルタリング
ExcludeDatabase ──────────────▶ (IsAccessible, IsSystemObject)
AllUserDatabases ─────────────▶
                                        │
InputObject ──────────────────▶ InputObject追加
                                        │
                                        ▼
                               ┌────────────────────┐
                               │ スナップショット   │
                               │ チェック           │
                               └────────────────────┘
                                        │
FileType ─────────────────────▶ ファイル取得
                               (LogFiles/FileGroups.Files)
                                        │
                                        ▼
                               ┌────────────────────┐
PercentFreeSpace ─────────────▶│ サイズ計算        │
                               │ Initial/Target    │
                               └────────────────────┘
                                        │
ExcludeIndexStats ────────────▶ フラグメンテーション取得
                               (縮小前)
                                        │
                                        ▼
ShrinkMethod ─────────────────▶┌────────────────────┐
StepSize ─────────────────────▶│ 縮小実行          │
StatementTimeout ─────────────▶│ Shrink(MB, Method)│
                               └────────────────────┘
                                        │
                                        ▼
ExcludeIndexStats ────────────▶ フラグメンテーション取得
                               (縮小後)
                                        │
                                        ▼
                               ┌────────────────────┐
                               │ PSCustomObject生成  │──────▶ コンソール出力
                               │ - Database         │
                               │ - File             │
                               │ - InitialSize      │
                               │ - FinalSize        │
                               │ - Fragmentation    │
                               │ - Notes            │
                               └────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Invoke-DbaDbShrink.ps1 | `public/Invoke-DbaDbShrink.ps1` | ソース | メイン関数定義 |
| Get-DbaDatabase.ps1 | `public/Get-DbaDatabase.ps1` | ソース | パイプライン入力元 |
| dbasize型 | 内部型定義 | 型 | サイズ変換・表示 |
