SQLアンチパターン　ファントムファイル

# ファントムファイル

目的：画像をはじめとする大容量のメディアファイルを格納することを目的とする

アンチパターン：物理ファイルの使用を必須と思い込む

画像データを保存する際にみなさんどのように保存しているだろうか。

* DBにBLOB型として保存？
* 外部のファイルシステムに保存し、DBにはファイルパスを保存？

筆者は後者の外部にファイルを保存し、DBにはファイルパスを格納していた。
おそらく多くの方が後者を採用しているのではないか。

どちらもメリット、デメリットがある。

## ファイル削除時の問題

* 画像をDBの外に保存している場合、DBで画像のファイルパスを削除したとしても実際の画像までは削除されない。
* ファイルパスの削除に応じて参照先のファイルも削除する必要がある。
* ファイルパスを削除して画像を削除しないと「孤児」となった画像が蓄積されていく。

逆に何かしらの理由で画像が削除されてしまった場合、DBに格納されているファイルパスの参照先が存在しないためアプリケーション内で画像が表示されない等の問題が発生する。

## トランザクション分離の問題

* 通常、データベースのデータ更新や削除はトランザクションをコミットするまで変更は他のクライアントには見えない。
* ファイルがデータベースの外にある場合はファイルを物理的に削除した場合にクライアントは即時にアクセスできなくなる。
* ファイルがデータベースの外にある場合はファイルに変更を加えた場合にクライアントは即時に変更を目にすることになる。

この項目は正直そこまで重要ではない.....

## ロールバック時における問題


上記の[トランザクション分離の問題](#トランザクション分離の問題)に関連して。

* 通常のデータベースでは何かしらのエラーが発生した場合はロールバックをする。
* ロールバックにより画像の参照先のファイルパスは復元できる。
* 外部に画像を保存している場合は物理的にファイルを破棄するがDBのロールバックをしてもファイルまではロールバックできない。

データベースは元に戻せるがファイルの実態が存在しない状態となる。


## データベースのバックアップツール使用時における問題

* ほとんどのデータベース製品はバックアップを支援するクライアントツールを提供している。
* バックアップツールには文字列で格納されたファイルパスの参照先のファイルをバックアップの対象にできない。
* DBのバックアップをする際、外部画像ファイル向けにファイルシステム用のバックアップツールを実行する必要がある。
* データベースのバックアップ開始直後にファイルの変更、追加、削除が行われる可能性もある。

DBのバックアップによって参照先ファイルのバックアップを行えないためそれぞれバックアップを行う必要がある。
またバックアップ時にファイルに対してトランザクションを宣言できないためファイルに変更が加わる可能性がある。

## SQLアクセス権限使用時における問題

外部ファイルにはSQLステートメントで割り当てるアクセス権限が適用されない。
データベース内で文字列で指定された外部ファイルを対象にできない。

## ファイルはSQLデータ型ではない

* ファイルの参照先を格納したパスはただの文字列である。
* ファイルパスが正しいものであるかはデータベースでは検証しない。
* ファイル名の変更やファイルの移動、削除等してもデータベース内のファイルパスは変更されない。

データベースの長所はデータの整合性を維持してくれること。
データを外部ファイルで管理することでそのメリットは失われる。

失われた利点をカバーするためにアプリケーション側で整合性を担保する必要がある。

## アンチパターンの見つけ方

設計者や開発者が以下の項目に対して適切な答えを持っていない場合、アンチパターンに陥っている可能性がある。

### バックアップとリストア
* データバックアップとリストアの手順が確立されているか
* バックアップの検証方法が確立されているか
* バックアップ等を実施したサーバーとは別のサーバーでデータのリストアをテストしたか

### ファイルの削除方法
* 画像が増える一方になるのではなく、不要になった際に削除される仕組みになっているか
* 不要なファイルを削除する手順はあるか
* その手順は自動化されているか、それとも手動か

### ファイルのアクセス権
* ファイルへのアクセス権を持っているアプリケーションユーザーは誰か
* アクセス権はどのように適用されているか
* 権限を持たない画像を参照するリクエストをした場合、何が表示されるのか

### ファイルのロールバック
* 画像に対する変更（リネーム、削除、移動など）をキャンセルできるか
* キャンセルできる場合、前の状態に復旧できるか

上記の項目で曖昧な内容や答えられない内容がある場合、ファントムファイルアンチパターンに陥っている可能性がある。

## アンチパターンを用いても良い場合

* データベースの容量を減らせる
* データベースのバックアップが短時間で終了し、バックアップファイルの容量も抑えられる
* ファイルがデータベース外にあることでプレビューの編集が容易

データベース外でファイルを管理することで上記のようなメリットがある。
この項目以前に記載したデメリット、懸念点が問題ないと判断できる場合採用しても良い。

## 解決策

この項目以前に記載したデメリット、懸念点が解決できない場合は***BLOB型***の採用を検討。
このBLOBデータ型は画像をデータベース内部に格納でき、以下のようなメリットがある。

* 画像はデータベースに格納されるため読み込みのための追加ステップが不要
* 誤ったファイルパスを格納するリスクがない
* 行を削除することで画像も自動的に削除される
* 画像の変更はコミットするまで他のクライアントから参照できない
* トランザクションをロールバックすると画像を以前の状態に復元できる
* 行の更新時にロックが行われ、他のクライアントは同時に同じ画像を更新できない
* データベースのバックアップに全ての画像が含まれる
* SQLの権限管理で行と画像へのアクセス権を管理できる

# まとめ

データベース外部のリソースは、データベースで管理できないことに注意しましょう。

# 参考文献

[SQLアンチパターン](
https://www.amazon.co.jp/SQL%E3%82%A2%E3%83%B3%E3%83%81%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3-Bill-Karwin/dp/4873115892/ref=sr_1_1?adgrpid=104444684056&dchild=1&gclid=CjwKCAjw4_H6BRALEiwAvgfzqy-f83NTsyQkauo7gn6ysgAPmJvKyvuI5FaXFnxFmhVfCzCRRACsaBoCY-oQAvD_BwE&hvadid=447984765572&hvdev=c&hvlocphy=1009332&hvnetw=g&hvqmt=e&hvrand=13417269104929133208&hvtargid=kwd-335484809678&hydadcr=27264_11561110&jp-ad-ap=0&keywords=sql%E3%82%A2%E3%83%B3%E3%83%81%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3&qid=1599934568&sr=8-1&tag=googhydr-22)

![参考文献.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257405/b46d45ab-75ec-a620-eeb2-a422f6b1e659.jpeg)