# 機能設計書 313-Find-DbaDbDuplicateIndex

## 概要

本ドキュメントは、SQL Serverデータベース内の重複または重複するインデックスを検出するFind-DbaDbDuplicateIndex機能の設計仕様を記載する。

### 本機能の処理概要

Find-DbaDbDuplicateIndexは、データベーステーブルをスキャンして、同一または重複するカラム構造を持つインデックスを特定する機能である。重複インデックスは不要なストレージスペースを消費し、INSERT/UPDATE/DELETE操作のパフォーマンスを低下させる。

**業務上の目的・背景**：データベースの長期運用において、開発者やDBAが意図せず重複したインデックスを作成してしまうケースは少なくない。また、アプリケーションの進化に伴い、以前は有効だったインデックスが他のインデックスと重複するようになることもある。重複インデックスはストレージコストの増大、データ変更操作の遅延、メンテナンス時間の増加を招く。本機能は、これらの問題を事前に発見し、インデックス最適化の判断材料を提供することで、データベースパフォーマンスの維持・向上に貢献する。

**機能の利用シーン**：本機能は以下のような場面で利用される。
- インデックスメンテナンス時の最適化候補特定
- パフォーマンスチューニング作業の一環
- データベース移行前のインデックス整理
- ストレージコスト削減のための不要インデックス検出
- 定期的なデータベースヘルスチェック

**主要な処理内容**：
1. 指定されたSQL Serverインスタンスへの接続確立
2. 対象データベースの特定
3. バージョン別のT-SQLクエリを使用した重複/重複インデックス検索
4. カラム順序、ソート方向、包含カラム、フィルター条件を考慮した比較
5. インデックスサイズ、行数、圧縮状態を含む詳細情報の取得

**関連システム・外部連携**：SQL Server Management Objects (SMO)を使用してSQL Serverに接続し、DMVとシステムカタログビューを参照するT-SQLクエリを実行する。

**権限による制御**：対象データベースへのVIEW DATABASE STATE権限が必要。SQL Server 2005（バージョン9）以降で動作する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | インデックス管理 | 主機能 | 重複インデックスの検出と一覧表示 |

## 機能種別

データ検索 / インデックス分析

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| SqlInstance | DbaInstanceParameter[] | Yes | 検索対象のSQL Serverインスタンス（複数可） | SQL Server 2005以降 |
| SqlCredential | PSCredential | No | 代替認証資格情報 | Windows/SQL/AD認証サポート |
| Database | object[] | No | 検索対象データベース名（複数可、ワイルドカード対応） | - |
| IncludeOverlapping | switch | No | 完全一致だけでなく重複するインデックスも検出 | - |
| EnableException | switch | No | 例外処理の有効化 | - |

### 入力データソース

- SQL Serverインスタンスへの直接接続
- パイプラインからのSqlInstance入力

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| DatabaseName | string | インデックスを含むデータベース名 |
| TableName | string | スキーマ.テーブル形式のテーブル名 |
| IndexName | string | インデックス名 |
| KeyColumns | string | キーカラム（ASC/DESC付き、カンマ区切り） |
| IncludedColumns | string | 包含カラム（カンマ区切り、なければ空） |
| IndexType | string | CLUSTERED または NONCLUSTERED |
| IndexSizeMB | decimal | インデックスサイズ（MB） |
| RowCount | int | テーブルの行数 |
| IsDisabled | bool | インデックスが無効化されているか |
| IsUnique | bool | 一意インデックスか |
| IsFiltered | bool | フィルター付きインデックスか（SQL 2008+） |
| CompressionDescription | string | 圧縮タイプ（NONE/ROW/PAGE）（SQL 2008+） |

### 出力先

- PowerShellパイプライン（PSCustomObject形式）

## 処理フロー

### 処理シーケンス

```
1. SQLクエリ定義（beginブロック）
   └─ SQL 2005用とSQL 2008+用の2種類のクエリを定義
   └─ 完全重複用と重複用の計4種類のクエリ
2. インスタンスループ開始
   └─ 各SqlInstanceに対して処理を実行
3. 接続確立
   └─ Connect-DbaInstanceでSQL Server 2005以降に接続
4. データベース取得
   └─ Database指定時は指定DB、未指定時はアクセス可能な全DB
5. データベースループ
   └─ 各DBに対してバージョン適切なクエリを実行
6. 結果出力
   └─ 結果をパイプラインに出力
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[4種類のSQLクエリ定義]
    B --> C[foreach SqlInstance]
    C --> D[Connect-DbaInstance]
    D --> E{接続成功?}
    E -->|No| F[エラー出力, Continue]
    E -->|Yes| G{Database指定?}
    G -->|Yes| H[指定DBをフィルタ]
    G -->|No| I[アクセス可能な全DB取得]
    H --> J[foreach database]
    I --> J
    J --> K{SQL Server バージョン判定}
    K -->|Version 9| L{IncludeOverlapping?}
    K -->|Version 10+| M{IncludeOverlapping?}
    L -->|Yes| N[overlappingQuery2005]
    L -->|No| O[exactDuplicateQuery2005]
    M -->|Yes| P[overlappingQuery]
    M -->|No| Q[exactDuplicateQuery]
    N --> R[db.Query実行]
    O --> R
    P --> R
    Q --> R
    R --> S[結果出力]
    S --> J
    F --> C
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 最小バージョン要件 | SQL Server 2005（バージョン9）以降が必要 | 接続時 |
| BR-002 | バージョン別クエリ選択 | SQL 2005はhas_filter非対応のためクエリを分ける | クエリ実行時 |
| BR-003 | 完全重複判定 | KeyColumns + IncludedColumns + IsFiltered が一致 | IncludeOverlapping未指定時 |
| BR-004 | 重複判定 | KeyColumnsの一部が一致（前方一致） | IncludeOverlapping指定時 |
| BR-005 | HEAPとsysスキーマ除外 | index_id > 0 かつ スキーマ名 != 'sys' | 常時 |

### 計算ロジック

```sql
-- インデックスサイズの計算
IndexSizeMB = SUM(used_page_count) * 8 / 1024.0
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 重複インデックス検索 | sys.indexes, sys.index_columns, sys.columns, sys.dm_db_partition_stats, sys.partitions | SELECT | カタログビューとDMVから重複インデックス情報を取得 |

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

#### sys.indexes

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | name, object_id, index_id, type_desc, is_disabled, is_unique, has_filter | index_id > 0, type_desc IN ('CLUSTERED', 'NONCLUSTERED') | SQL 2008+はhas_filter使用 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ConnectionError | SQL Serverへの接続失敗 | 接続情報と権限を確認 |
| - | QueryFailure | クエリ実行エラー | データベースアクセス権限を確認 |
| - | MinimumVersion | SQL Server 2005未満 | SQL Server 2005以降にアップグレード |

### リトライ仕様

リトライ機能は実装されていない。

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

本機能は読み取り専用であり、トランザクション管理は不要。

## パフォーマンス要件

- CTE（共通テーブル式）を使用した効率的なクエリ構造
- sys.dm_db_partition_statsを使用したサイズ計算

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

- SqlCredentialによる認証情報の安全な受け渡し
- VIEW DATABASE STATE権限が必要

## 備考

- SQL Server 2005ではIsFiltered, CompressionDescriptionプロパティは出力されない
- FOR XML PATH構文でカラムリストを連結

---

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

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

### 推奨読解順序

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

クエリの出力カラム構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Find-DbaDbDuplicateIndex.ps1 | `public/Find-DbaDbDuplicateIndex.ps1` | .OUTPUTSコメントで出力プロパティを確認 |

**読解のコツ**: SQL 2005用とSQL 2008+用でプロパティセットが異なることに注意。

#### Step 2: SQLクエリを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Find-DbaDbDuplicateIndex.ps1 | `public/Find-DbaDbDuplicateIndex.ps1` | 106-191行目（SQL 2005用完全重複クエリ） |
| 2-2 | Find-DbaDbDuplicateIndex.ps1 | `public/Find-DbaDbDuplicateIndex.ps1` | 193-286行目（SQL 2005用重複クエリ） |
| 2-3 | Find-DbaDbDuplicateIndex.ps1 | `public/Find-DbaDbDuplicateIndex.ps1` | 289-380行目（SQL 2008+用完全重複クエリ） |
| 2-4 | Find-DbaDbDuplicateIndex.ps1 | `public/Find-DbaDbDuplicateIndex.ps1` | 382-470行目（SQL 2008+用重複クエリ） |

**主要処理フロー**:
- **CTE_IndexCols**: インデックスとカラム情報を集約
- **CTE_IndexSpace**: サイズと行数を計算
- **WHERE EXISTS**: 重複条件を判定

#### Step 3: バージョン判定とクエリ選択を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Find-DbaDbDuplicateIndex.ps1 | `public/Find-DbaDbDuplicateIndex.ps1` | 492-498行目のバージョン判定 |

**主要処理フロー**:
- **492行目**: versionMajor -eq 9 でSQL 2005判定
- **493-494行目**: IncludeOverlappingによるクエリ選択
- **495-498行目**: SQL 2008+用のクエリ選択

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

```
Find-DbaDbDuplicateIndex
    │
    ├─ Connect-DbaInstance
    │      └─ MinimumVersion: 9 (SQL Server 2005)
    │
    └─ Database.Query($query)
           └─ T-SQL クエリ実行（バージョン別）
```

### データフロー図

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

SqlInstance ───────────▶ Connect-DbaInstance ───▶ Server オブジェクト
        │                                              │
        ▼                                              ▼
Database パラメータ ───▶ データベースフィルタリング ───▶ 対象DB一覧
        │                                              │
        ▼                                              ▼
IncludeOverlapping ───▶ クエリ選択 ─────────────▶ 適切なSQLクエリ
        │                                              │
        ▼                                              ▼
                                              Database.Query()
                                                       │
                                                       ▼
                                              PSCustomObject ───▶ パイプライン出力
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Find-DbaDbDuplicateIndex.ps1 | `public/Find-DbaDbDuplicateIndex.ps1` | ソース | メイン機能実装 |
| Find-DbaDbDisabledIndex.ps1 | `public/Find-DbaDbDisabledIndex.ps1` | ソース | 関連機能（無効化インデックス検出） |
| Find-DbaDbUnusedIndex.ps1 | `public/Find-DbaDbUnusedIndex.ps1` | ソース | 関連機能（未使用インデックス検出） |
