SQLチューニング入門：DBMSの内部処理とパフォーマンス最適化

# SQLチューニング入門：DBMSの内部処理とパフォーマンス最適化

SQL文のパフォーマンスを向上させるには、DBMSの内部処理を理解することが不可欠です。  
本記事では、オプティマイザの仕組みや統計情報、実行計画の確認方法などを、アウトプットをかねて実例・コマンド付きでまとめています。


---

## 1. DBMSにおけるSQLクエリ処理の流れ

DBMSはSQL文を以下のステップで処理します：

1. **パーサ（Parser）**  
   SQLの構文解析と正当性チェックを行う。

2. **オプティマイザ（Optimizer）**  
   実行方法の候補を作り、コストを比較して最適な実行計画を選定。

3. **実行計画（プラン）**  
   選ばれた実行方法の詳細なプラン。

4. **実行エンジン（Executor）**  
   実際にプランを元にデータを読み取り、結果を返す。

```text
┌───────┐
│ クエリ │
└──┬────┘
   ↓
┌─────────────┐
│ パーサ      │
└────┬────────┘
     ↓
┌─────────────┐
│ オプティマイザ│
└────┬────────┘
     ↓
┌─────────────┐
│ 実行計画(プラン)│
└────┬────────┘
     ↓
┌─────────────┐
│ 実行エンジン  │
└─────────────┘
```



## 2. オプティマイザと付き合う方法

SQLのパフォーマンスを左右する大きな要因のひとつが、**オプティマイザ（Optimizer）**の働きです。  
オプティマイザは、SQL文の構文を解析したあと、最適な実行方法（実行計画）を決定します。

### オプティマイザの判断基準

オプティマイザは、以下のような情報をもとにコストを計算し、最適なプランを選びます。

- 各テーブルの行数（件数）
- 各列の値のバラつき（カーディナリティ）
- インデックスの有無
- NULLの比率
- 統計情報の更新状況

これらの情報は「**統計情報**」としてDBMS内部に保持されています。

---

## 3. 統計情報を更新するには

統計情報が古くなっていると、オプティマイザは誤った実行計画を選んでしまうことがあります。  
そのため、テーブルのデータ量が大きく変わったタイミングで、**統計情報を更新すること**が重要です。

### 各DBMSの統計情報更新コマンド

| DBMS               | 統計情報更新コマンド                                         |
|--------------------|--------------------------------------------------------------|
| Oracle             | `EXEC DBMS_STATS.GATHER_TABLE_STATS('SCHEMA', 'TABLE');`     |
| Microsoft SQL Server | `UPDATE STATISTICS TableName;`                              |
| DB2                | `RUNSTATS ON TABLE TableName;`                                |
| MySQL              | `ANALYZE TABLE TableName;`                                    |

---

## 4. 実行計画を確認する

SQL文がどのように実行されるかは、**実行計画（Execution Plan）**を確認することでわかります。  
各DBMSで実行計画を表示するためのコマンドは以下のとおりです。

### 各DBMSの実行計画確認コマンド

| DBMS                 | 実行計画コマンド                                          |
|----------------------|-----------------------------------------------------------|
| Oracle               | `EXPLAIN PLAN FOR SELECT * FROM users;`                  |
| Microsoft SQL Server | `SET SHOWPLAN_ALL ON;` → `SELECT * FROM users;`          |
| DB2                  | `EXPLAIN PLAN FOR SELECT * FROM users;`                  |
| PostgreSQL           | `EXPLAIN ANALYZE SELECT * FROM users;`                   |
| MySQL                | `EXPLAIN SELECT * FROM users;`                           |

---

### PostgreSQLの例

```sql
EXPLAIN ANALYZE
SELECT * FROM users WHERE email = 'example@example.com';
```

出力例

```zsh
Index Scan using index_users_on_email on users
  (cost=0.29..8.30 rows=1 width=244)
  (actual time=0.035..0.036 rows=1 loops=1)
```

## 5. チューニング例：インデックスの有無による差

SQLの実行速度は、インデックスの有無によって大きく異なります。ここでは具体例を使って、インデックスの効果を見てみましょう。

### インデックスがない場合のクエリ

以下のように `customer_id` を指定して `orders` テーブルを検索するクエリがあります。

```sql
SELECT * FROM orders WHERE customer_id = 123;
```

```zsh
Seq Scan on orders
```

## インデックスを追加した場合

```sql
CREATE INDEX idx_orders_customer_id ON orders(customer_id);
```

再実行時の実行計画

```zsh
Index Scan using idx_orders_customer_id on orders
```

→ 該当行のみピンポイントでアクセスできるため高速化！



## まとめ

- SQLのパフォーマンスは、オプティマイザが選ぶ実行計画によって大きく左右される。
- 実行計画の中身を読めるようになることで、ボトルネックの特定が可能になる。
- インデックス、統計情報、クエリの書き方を総合的に見直すことが大切。


---

## 参考
[SQL実践入門──高速でわかりやすいクエリの書き方 (WEB+DB PRESS plus)](https://www.amazon.co.jp/SQL%E5%AE%9F%E8%B7%B5%E5%85%A5%E9%96%80%E2%94%80%E2%94%80%E9%AB%98%E9%80%9F%E3%81%A7%E3%82%8F%E3%81%8B%E3%82%8A%E3%82%84%E3%81%99%E3%81%84%E3%82%AF%E3%82%A8%E3%83%AA%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9-WEB-DB-PRESS-plus/dp/4774173010)