SQLアンチパターン：DB論理設計のアンチパターン

# はじめに
有名なあの本を読んだ備忘録です。
ありふれた内容ですが、こんな記事いくらあってもいいですからね！

https://www.oreilly.co.jp/books/9784873115894/

# 1章　ジェイウォーク（信号無視）
## 概要
一つの列に複数の値をもたせるのはやめましょう。
| product_id       |       product_name|    account_id      |
|:----------------:|:-----------------:|:------------------:|
| 1                |             table |    123, 456        |
| 2                |           chair   |     456, 789       |

## 対策
交差テーブルを作りましょう。
![スクリーンショット 2022-05-12 16.00.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572098/47af45cf-66cc-e702-cef2-fc316487062b.png)


# 2章　ナイーブツリ－（素朴な木）
別途

# 3章　IDリクアイアド（とりあえずID）
## 概要
主キー名はわかりやすく命名しましょう。
また、必ずしもid列は必要ありません。

## 対策
例えば、交差テーブルの主キーは複合キーをつかう。

```sql
create table Contacts (
  product_id bigint unsigned not null,
  account_id bigint unsigned not null,
  foreign key (product_id) references Products(product_id),
  foreign key (account_id) references Accounts(account_id),
  primary key (product_id, account_id)
);
```

# 4章 キーレスエントリ（外部キー嫌い）
## 概要
外部キー制約を使って参照整合性を担保しましょう。
キーレスエントリでは柔軟性が高まりますが、さまざまな代償が伴います。

# 5章　EAV (Entity Attribute Value)
## 概要
汎用的な属性テーブルを使用するのはやめましょう。
| issue_id         |       attr_name   |    attr_value      |
|:----------------:|:-----------------:|:------------------:|
| 1                |           severity|    5               |
| 2                |      sponsor      |    example_inc     |
| 3                | status            | NEW                |
## 対策
- 半構造化データに対してはNoSQLを使いましょう
- 例えば下記のようなサブタイプのモデリングを行いましょう

### 「クラステーブル継承」の例
`Bugs`と`FeatureRequest`は`Issues`を継承しています。
![スクリーンショット 2022-05-12 16.00.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572098/216615f5-5fb6-166b-75e3-38fb0a31ccdc.png)


## メモ
blob, clob, text型などをLOB（Large Object）という。
処理が重くなりがちなので基本避ける。
Jsonなどの半構造化データはこの型をつかう。

# 6章　ポリモーフィック関連
# 概要
一つのエンティティに対して、複数の親を設定するのはやめましょう。
2つ以上の親に対して外部キーを設定できないからです。
![スクリーンショット 2022-05-12 19.50.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572098/4f16c734-a853-c5d1-808d-5167e82e8ac9.png)
## 対策
- 交差テーブルの作成
![スクリーンショット 2022-05-12 19.59.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572098/9f4b0bad-7624-be22-b709-c577108a1e4e.png)

- 共通の親テーブルの作成
![スクリーンショット 2022-05-12 20.07.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572098/9f8ac1ea-dc23-6cf5-6a87-931c04d9cfa4.png)

# 7章　マルチカラムアトリビュート (複数列属性)
## 概要
複数の列を定義するのはやめましょう。
| product_id       |       product_name| 　tag1  | tag2 | tag3 |
|:----------------:|:-----------------:|:-----:|:----:|:----:|
| 1                |             table | white | NULL | NULL |  
| 2                |           chair   | NULL  | long | NULL |
| 3                |          paper    |  NULL | NULL | 100  |

## 対策
従属テーブルを作成する。
上の例で言うと、tagを新たなテーブルとして作成し、productテーブルから参照させます。

# 8章 メタデータドリブル(メタデータ大増殖)
## 概要
スケーラビリティを求めて、内容の同じテーブルや列をコピーするのはやめましょう。

```sql
create table Bugs_2008 (...);
create table Bugs_2009 (...);
create table Bugs_2010 (...);
```

## 対策
- 水平パーティショニング
DBエンジンのパーティション機能を使う。
テーブルは物理的に分割されているが、あたかも1つのテーブルかのようにSQLステートメントを実行できる。

```sql
create table Bugs (
  bug_id serial primary key,
  ...,
  date_reported DATE
) partition by hash (year (date_reported))
  partitions 4;
```

- 垂直パーティショニング
列でテーブルを分割できる。１部の列がサイズが大きい場合や、滅多に使用されない場合に活用できる。
例えば、BLOB列とTEXT列はサイズ可変で、通常は非常に大きいサイズであることが考えられる。
これらの列を分割して保存することで、他の列に効率的にアクセスできる。
クエリの際の列名に`*`を使わないように注意。

- 従属テーブルの導入
概要の例でいうと、プロジェクトごとに年別の列を持たせる代わりに、プロジェクトと年の組み合わせが1行となる従属テーブルを新たに定義しましょう。

```sql
create table ProjectHistory (
  project_id bigint,
  year smallint,
  primary key (project_id, year)
  foreign key (project_id) references Projects(project_id)
);
```

# おわりに
まだまだ続きます。