【データベース】ハッシュインデックスとビットマップインデックスを理解する

# はじめに
今回は「達人に学ぶDB設計徹底指南書 第2版」の6章の演習問題でビットマップインデックス、ハッシュインデックス」について調べたことをまとめていきます！

B-treeインデックスについてはこちら

https://qiita.com/rgj0830/items/2addcde92f051089ade5

## ビットマップインデックス
### 概要
ビットマップインデックスは、検索対象のカラムに対して、その値に対応するビットマップを使用してレコードを特定するインデックス。
主に**データウェアハウス環境**で使用される

https://www.dal.co.jp/column/b-dwh/

## ビットマップインデックスの例
**製品の在庫状態と配送地域**
オンラインショップのデータベースで、製品の「在庫状態」と「配送地域」に対してビットマップインデックスを使用して、レコードを特定する場合。
カラムには「在庫状態」（在庫あり／在庫なし）と「配送地域」（国内／海外）が含まれる。

#### 1. データ構造
以下のような製品データがあるとする(あんまり在庫ありとか、国内とかベタ書きで入れないと思いますが、わかりやすくするためそうしてます笑)

| 製品ID | 製品名       | 在庫状態  | 配送地域 |
|--------|--------------|-----------|----------|
| 1      | スマートフォン | 在庫あり  | 国内     |
| 2      | ノートPC     | 在庫なし  | 海外     |
| 3      | タブレット   | 在庫あり  | 国内     |
| 4      | カメラ       | 在庫なし  | 国内     |
| 5      | ヘッドフォン | 在庫あり  | 海外     |

#### 2. ビットマップインデックス
このデータに対して、「在庫状態」と「配送地域」に基づくビットマップインデックスを作成する

##### ビットマップインデックスの構築
- **在庫状態：在庫あり**
  - `1 0 1 0 1` （1, 3, 5番目の製品が在庫あり）

- **在庫状態：在庫なし**
  - `0 1 0 1 0` （2, 4番目の製品が在庫なし）

- **配送地域：国内**
  - `1 0 1 1 0` （1, 3, 4番目の製品が国内配送）

- **配送地域：海外**
  - `0 1 0 0 1` （2, 5番目の製品が海外配送）

#### 3. クエリ例
##### OR演算の場合

**例1: 国内配送または在庫ありの製品を検索**
- 「在庫あり」と「国内配送」のビットマップをOR演算
  - **在庫あり** = `1 0 1 0 1`
  - **国内配送** = `1 0 1 1 0`
  - OR演算結果 = `1 0 1 1 1`
  - → **結果**: 製品ID 1、3、4、5 が該当

### 長所
- **カーディナリティの低いカラムに対して有効**
取りうる値の種類が少ないカラム（今回の在庫状態や性別、血液型など）に対して高速に機能する。
カーディナリティの低い　= 取りうる値の種類が少ない
- **OR演算子や否定系の検索にも対応**
`OR` 演算子や `NOT` 演算子を使ったクエリでも、インデックスが適用され、効率的な検索が可能。(B-treeではインデックスが効かない)

- **IS NULLにも対応**
B-treeインデックスと異なり、ビットマップインデックスは `IS NULL` に対してもインデックスを利用できる。(インデックス内にNULLも保持するため)

- ビットデータはサイズが小さいため、インデックスのサイズが小さくなる

### 短所
- **データの更新、削除、追加に時間がかかる**
更新頻度の高いシステムでは、ビットマップインデックスのパフォーマンスが低下する。
テーブルのデータが更新されるたびに、インデックスのビット値も更新する処理を行わなければならないため、更新時の性能が悪い。
そのため、頻繁にデータ更新が行われるタイプのシステム(OLTP)で利用するには性能的なリスクが大きい

https://www.ibm.com/jp-ja/topics/oltp

---

## ハッシュインデックス

### 概要
**ハッシュインデックス**は、ハッシュ関数を使用して検索対象のキーと、レコードが格納されているページを直接結びつけるインデックス。
たとえば、従業員番号などをハッシュ関数に入力し、ハッシュ値によって該当するページにアクセスしてレコードを取得する。

#### 例
従業員番号をハッシュ関数にかけたとき、その戻り値がページの参照先となり、データがそのページ(ページについては下記に記載)に格納される。検索する際には、キーを使って同じハッシュ関数で戻り値を計算し、その戻り値が示すページにアクセスして、該当するレコードを探す。

### 長所
- **特定のキーによる検索(等値検索)が非常に高速**
大量のデータから特定のキーを使ってデータを検索する場合、ディスクアクセスを最小限にすることで非常に高速にデータを取得できる。

### 短所
- **オーバーフローページの発生**
ハッシュインデックスでページがいっぱいになった場合、新しいページ（オーバーフローページ）が作成され、チェーン状にリンクされる。これにより、ディスクアクセスが増え、パフォーマンスが低下する。
**例**
ページAがいっぱいの場合、ページBを作成してデータを格納し、ページAにはページBへの参照を保持する。
結果として、複数のページを辿る必要があり、ディスクI/Oが増加する。
- **ハッシュ関数の選択が重要**
均一にページを割り振るためには、適切なハッシュ関数を選ぶ必要がある。データの量や構造に合わないハッシュ関数を選ぶと、パフォーマンスが低下する。(選び方までは、調べられてないので不明)
- **データ量の予測が難しい環境には不向き**
ハッシュ関数を選択するにはデータ量を予測する必要がある。そのため予測が難しい場合は向いていない。

- **等値検索以外ではインデックスが利用できない**
ハッシュ関数で変換されたハッシュ値は、元の値の順序関係を維持していないため。

---
## ページとは？

**ページ**は、データベースがディスク上でデータを格納・管理するための基本的な単位。データベースではデータをページ単位で管理し、効率的にデータの保存やアクセスを行う。

- **固定サイズ**: 通常、InnoDBでは1ページのサイズは16KBですが、他のデータベースエンジンでは異なる場合もある。
- **最小の管理単位**: データはレコード単位で管理されるわけではなく、ページ単位で読み書きされる。これにより、データの管理やアクセスが効率的になる。

### ページのデータ管理
データベースは、ディスク上のデータを**ページ単位**で保存・管理する。特定のページに空きがない場合は、他のページにデータを格納し、そのページに参照情報を保持する。これにより、データが分散され、複数ページにわたって格納されることになる。

---

## まとめ

### ビットマップインデックス
- **データウェアハウス環境**で使用されることが多く、カーディナリティの低いカラムに適している
- OR演算子やNOT演算子、NULLの検索にも適用される
- 更新が少ない環境に適しており、OLTPシステムには不向き

### ハッシュインデックス
- **特定のキーに対する検索**が非常に高速で、ディスクアクセスを最小化にできる
- データの量が決まっているシステムに向いているが、ページのオーバーフロー対策、ハッシュ関数の選択が重要になる
- データ量の急激な変化があったり、予測さが難しい環境には不向き
---

### 参考書籍・サイト・資料

https://www.shoeisha.co.jp/book/detail/9784798186627

https://www.dal.co.jp/column/b-dwh/

https://xtech.nikkei.com/it/article/COLUMN/20060113/227241/

https://qiita.com/gohandesuyo/items/b3a684157b2eefc69a79＃