大きなファイル(10 MB)をデータベースに保存するのは悪い習慣ですか?


188

現在、ユーザーが1 MB〜10 MBのサイズのファイルを保存および共有できるWebアプリケーションを作成しています。

データベースにファイルを保存すると、データベースアクセスが大幅に遅くなるように思えます。

これは有効な懸念事項ですか?ファイルシステムにファイルを保存し、データベースにファイル名とパスを保存する方が良いでしょうか?データベースを操作する際のファイルの保存に関連するベストプラクティスはありますか?

私はこのプロジェクトでPHPとMySQLを使用していますが、ほとんどの環境(Ruby on RailsPHP.NET)およびデータベース(MySQL、PostgreSQL)で同じ問題があります。



11
:誰が(SQL Server 2008の)この問題に行わMSの研究掲示しないことに驚いラージオブジェクトストレージデータベースやファイルシステム:BLOB Toまたは未BLOBへ
オデッド

2
largeは相対的な量であり、私(およびおそらく他の多くの人)は10MB現代のシステムではそれほど大きくありません。

27
FAQによると、これはトピックに沿ったものです-「設計パターン」(アンチパターンのスラッシュ)と「ソフトウェアアーキテクチャ」という箇条書きの下に収まります。なぜ閉鎖されたのですか?
イズカタ

21
現在のように、質問にはあいまいさはありません。なぜ閉鎖されたのかわかりません。
reinierpost

回答:


139

データベースにファイルを保存することを支持する理由:

  1. 更新のロールバックを含むACID一貫性。ファイルがデータベースの外部に保存されている場合は複雑です。これは軽度につやつやされるべきではありません。ファイルとデータベースを同期し、トランザクションに参加できるようにすることは非常に便利です。
  2. ファイルはデータベースに付属しており、データベースから孤立させることはできません。
  3. バックアップには、ファイルバイナリが自動的に含まれます。

データベースにファイルを保存する理由:

  1. バイナリファイルのサイズはデータベースによって異なります。たとえば、SQL Serverでは、FILESTREAMオブジェクトを使用しない場合、2 GBです。ユーザーがより大きなファイル(映画など)を保存する必要がある場合は、その魔法を実現するためにフープをジャンプする必要があります。
  2. データベースのサイズを増やします。心に留めておくべき1つの一般的な概念:データベースの保守に必要な知識のレベルは、データベースのサイズに比例して上がります。つまり、大規模なデータベースは、小規模なデータベースよりも保守が複雑です。データベースにファイルを保存すると、データベースがさらに大きくなる可能性があります。データベースのサイズが大きくなると、毎日の完全バックアップで十分であったとしても、それができなくなる可能性があります。ファイルを別のファイルグループに配置することを検討する必要がある場合があります(データベースがサポートしている場合)。メンテナンスが複雑になるため、ビジネスにコストがかかります。また、データベースを大きくすると、できるだけ多くのデータをメモリに詰め込もうとするため、より多くのメモリが消費されます。
  3. SQL ServerのFILESTREAMオブジェクトなどのシステム固有の機能を使用しており、別のデータベースシステムに移行する必要がある場合、移植性が問題になる可能性があります。
  4. ファイルをデータベースに書き込むコードが問題になる場合があります。ある時点で私がコンサルティングを行ったある会社は、Microsoft Accessフロントエンドをデータベースサーバーに接続し、Ole Objectコントロールを使用してAccessの「何でも」をアップロードする機能を使用しました。その後、彼らは、まだオレに依存している別のコントロールを使用するように変更しました。その後、誰かがインターフェースを変更して生のバイナリを保存しました。これらのOleオブジェクトの抽出は、新しいレベルの地獄でした。ファイルシステムにファイルを保存する場合、ソースファイルのラップ/微調整/変更に関連する追加のレイヤーはありません。
  5. Webサイトにファイルを提供するのはより複雑です。バイナリ列でこれを行うには、データベースからファイルバイナリをストリーミングするハンドラを作成する必要があります。ファイルパスを保存している場合でも、これを行うことができますが、これを行う必要はありません。繰り返しますが、ハンドラーを追加することは不可能ではありませんが、複雑さを追加し、別の障害点です。
  6. クラウドストレージを利用することはできません。ある日、ファイルをAmazon S3バケットに保存したいとします。データベースに保存するのがファイルパスの場合、S3でそれらをパスに変更することができます。私の知る限り、どのDBMSを使用するシナリオでもそれは不可能です。

IMOは、データベース内のファイルの保存を「不良」とみなすか、状況と要件に関する詳細情報を必要とします。ファイルのサイズや数は常に小さくなりますか?クラウドストレージを使用する予定はありませんか?ファイルはWebサイトまたはWindowsアプリケーションのようなバイナリ実行可能ファイルで提供されますか?

一般に、私の経験では、ACIDの欠如と孤児の可能性を考慮しても、ビジネスにとってパスの保存は安価であることがわかりました。ただし、これは、インターネットがACID制御の欠如がファイルストレージの問題を抱えているというわけではないという意味ではありませんが、一般的にそのソリューションの構築、理解、および保守が容易であることを意味します。


CDNを使用できないのはなぜですか?これは、私が聞いたことがあるほぼすべてのCDNでサポートされているシナリオです。
ビリーONeal

@BillyONeal-CDN 使用してデータベースにファイル保存することはできません。複製に問題がない限り、両方を使用することはできません。
トーマス

3
うーん、CDNの重要なポイントは複製です。CDNは、単にWebアドレスのターゲットをキャッシュするだけです。唯一の要件は、コンテンツを提供するHTTPホストがあり、コンテンツがめったに変更されないことです。(とにかく画像をどこから
取得

3
@BillyONeal-しかし、これは私の側の言葉の悪い選択だと思い、答えを調整しました。具体的には、クラウドストレージを使用する場合(そして、おそらくクラウドストレージでCDNを使用する場合)、データベースストレージソリューションでネイティブに実行することはできません。データベースからファイルを取得してクラウドストレージプロバイダーに送信するには、同期ルーチンを作成する必要があります。
トーマス

@BillyONeal-ある意味では、あなたのコメントが最良の答えでした。DBストレージのすべての利点を享受できますが、問題はありません。
B七つの

89

多くの場合、これは悪い考えです。データベースファイルが膨張し、いくつかのパフォーマンスの問題が発生します。多数の列があるテーブルにblobを貼り付けると、さらにひどくなります。

しかしながら!SQL Serverなどの一部のデータベースには、FILESTREAM列タイプがあります。この場合、データは実際にはデータベースサーバー上の別のファイルに保存され、ファイルのIDのみがテーブルに保存されます。この場合、SQLサーバーにデータを保持しない理由はあまりありません。ファイルはサーバーバックアップの一部として自動的に含まれ、データベースとファイルは同期しなくなります。ファイル名を保存するというトニーの提案の問題は、データベースとファイルシステムが同期しなくなる可能性があることです。データベースは、ディスク上で削除されたファイルが存在すると主張します。プロセスがデータベースを変更してからクラッシュした場合、ファイルとデータベースは一致しません(つまり、データベース外のファイルにACIDがありません)。


21
「プロセスがDBを変更してからクラッシュした場合、ファイルとDBは一致しません。」プロセス全体をトランザクションでラップ(ファイルの作成、ファイルの検証、dbの更新)してエラーメッセージをスローすると何かがうまくいかない場合、それらを同期させるのは非常に簡単です。
-Briddums

3
私はそれについての不満を持っています:シナリオを考えてください:ファイルシステムにファイルを保存する(古いものを削除せずに)、DBを更新する、成功時に古いファイルを削除する、ロールバック時に新しいファイルを削除する。最悪のシナリオ-プロセスが中断された場合、孤立ファイルがあります。ただし、正しいバージョンのDBによって常に参照されるファイルがあります。
バルテック

2
ファイル/ DBメソッドに関するその他の潜在的な問題:1)コピーオンライトとして更新を行う必要があります。更新中にプロセスがクラッシュした場合、DBステータスはロールバックされますが、ファイルはロールバックされません。2)これを行うには、古いファイルの何らかのガベージコレクションが必要です。3)DBにすべてを保存するということは、バックアップ後にDBとファイルのバージョンが同期していることを意味します。DBを2週間前の状態に復元します...では、その時点でファイルの内容はどこにありますか?
ティモシーボールドリッジ

3
@briddums-いいえ。SQLServerはファイルシステムに直接統合され、OSに代わってそれらのファイルを管理します。私はそれらを自分で使用したことはありませんが、ドキュメントはFILESTREAMとその子孫FileTablesのように見えるので、両方の長所が得られます。データベース。
ニックチャマス

1
ニックに同意します。Disk + DBシステムをFILESTREAM列に置き換えましたが、振り返ることはありませんでした。FKを介して他のテーブルにファイルを関連付けることができるのは本当に素晴らしいことです。したがって、実際には「各人には1つ以上のHRドキュメントが関連付けられている必要があります」などと言うことができます。
ティモシーボールドリッジ

35

はい、それは悪い習慣です。

DBのパフォーマンスへの影響:

  • SELECTBLOBカラムでa を実行すると、常にディスクアクセスが実行されますが、BLOBがないと、RAMから直接データを取得する機会があります(高スループットDBはRAMにテーブルに適合するように最適化されます)。
  • BLOBをスレーブにプッシュする必要があるため、レプリケーションは遅く、レプリケーションの遅延は大きくなります。レプリケーション遅延が大きいと、明示的に考慮しない限り、あらゆる種類の競合状態やその他の同期の問題が発生します。
  • DBのバックアップ/復元にはかなり時間がかかります。

速度の利点— なし!一部の古いファイルシステムは数百万のファイルがあるディレクトリをうまく処理できませんが、最新のもののほとんどはまったく問題なく、実際にはBD(通常Bツリー)と同じ種類のデータ構造を使用します。たとえば、ext4(デフォルトのLinuxファイルシステム)はHtreeを使用します。

結論:DBのパフォーマンスが低下し、ファイル取得のパフォーマンスは向上しません。

あなたは、Webアプリケーションの話をしているので、また、 -現代のウェブサーバを使用して、ファイルシステムから直接静的ファイルを提供し、行うことができますsendfile()システムコールをある驚異的なパフォーマンスの向上。DBからファイルを取得している場合、これはもちろん不可能です。例えば考えてみましょう。このベンチマークを示し、1000の同時で25K REQ /秒をやっNgnixをローエンドのノートPCに接続。この種の負荷は、あらゆる種類のDBをフライします。


6
+1。Webサーバーに、ディスクからファイルを提供して、ベストを尽くします。PHPにMySQLなどを要求する必要があるため、PHPに要求しないでください。
deizel

3
プログラマーは、パフォーマンスだけが重要ではないことをいつ知りますか?
reinierpost

2
@reinierpost:笑 おそらくリベラルアーツ専攻を取得したとき;-)
バルテック

1
@BillyONeal:静的コンテンツと動的コンテンツに同じサーバーが必要だと思うのはなぜですか?サーバー間でファイルを同期するには、そのために特別に設計されたツールがあり、データベースよりもはるかに効率的です。データベースをファイルサーバーとして使用することは、ドライバーで釘を打つようなものです。
バルテック

1
@BillyONeal:それが機能する「ソリューション」があることに同意します。MySQLで画像を使用したアマチュアPHPセットアップが非常に多く見られます。ただし、このようなセットアップでは、DBはBLOBを提供する高トラフィックをサポートしません。
バルテック

18

私はそれについて実用的であり、「まだ最適化しない」という原則に従います。現時点で意味のあるソリューションを作成し、適切に実装するための開発リソースがあることを確認します。多くの潜在的な問題があります。しかし、それらは必ずしも本当の問題になるわけではありません。たとえば、100人のユーザーがいる場合、おそらく問題にはなりません。それはかもしれないあなたが100,000 10,000,000のユーザーを持っている場合は問題になります。しかし、後者の場合、すべての問題に対処するためのより多くの開発リソースの基盤が必要です。

ただし、データベースにデータを保存すると、ファイルの保存場所、バックアップ方法など、他の問題に対処できなくなります。Webアプリケーションを作成しているので、セキュリティ上の理由から非常に良い考えです。アプリケーションをホストするプロセスにファイルシステムへの書き込みアクセス権がないことを確認するには、データが保存されているフォルダーへの読み取り/書き込みアクセス権を持つようにサーバーを構成する必要があります。

個人的にデータベースにデータを保存することを選択しますが、BLOBが本当に必要になるまで読み込まれないようにします。つまり、ブログを含むテーブルで「SELECT * FROM ...」が実行されないようにします。また、パフォーマンスの問題が発生した場合、データベースのデータをファイルシステムに簡単に移動できるように設計します。たとえば、ファイル情報を別のFileテーブルに保存して、ファイル情報を他のビジネスエンティティから遠ざけるようにします。

データベースで読み込まれたファイルを表すためのFileクラスがあると仮定すると、後でそれを移動することによるコーディングへの影響は最小限になります。


これは素晴らしい提案です。持っていない問題の解決を始めないでください。
ヘビーE

16

マイクロソフトは、これについて数年前にホワイトペーパーをリリースしました。SqlServerに重点を置いていますが、そこには興味深い情報がいくつかあります。

BLOBにするかしないか データベースまたはファイルシステムのラージオブジェクトストレージ?

彼らの結論の非常に簡潔なバージョンは次のとおりです。

NTFSファイルシステムとSQL Server 2005を比較すると、256KB未満のBLOBはSQL Serverでより効率的に処理され、NTFSは1MBを超えるBLOBでより効率的に処理されます。

特定のユースケース用の小さなテストを作成することをお勧めします。キャッシュ効果に注意する必要があることに注意してください。(物理的に可能なスループットよりも高いスループットを持っていると思われるディスクへの保存速度を初めて取得したときは驚きました!)


4
1つのディレクトリに100K個を超えるファイルを配置すると、NTFSの動作が非常に不安定になります。ファイルアクセスはかなり遅くなり(少なくとも1桁)、ファイルを開く操作は(見かけ上)ランダムに失敗し始めます。Windows 2008およびWindows 7システムでこの影響を経験しました。複数のディレクトリ間でファイルを再配布すると、すべてが正常に戻りました。それ以降状況が改善されたかどうかはわかりません。
フェルッチョ

11

データベースの外部にファイルを保存するという従来の常識はもはや成り立たないかもしれません。原則として、速度よりも整合性を優先し、最新のDBMSでは両方を使用できます。

トム・カイトは同意するようです:

データベース外に長期間保存したいデータを保存する利点がないことを知っています。

データベースにある場合、私はできる

専門的に管理されていることを確認してください

バックアップされた

回復可能(残りのデータとともに)

安全な

スケーラブル(100,000個のドキュメントを1つのディレクトリに配置してみてください。今度は、それらをテーブルに配置します。これはディレクトリではありません)

簡単に削除の取り消し(フラッシュバック)ができます

ロックがあります

私は一貫性を読みました...


8

はい。

ファイルシステムからファイルを提供する場合、Webサーバーは、BSDまたはLinux上のsendfile()などのカーネルコードを使用して、ファイルをソケットに直接コピーできます。非常に高速で非常に効率的です。

データベースからファイルを提供するということは、データベースサーバーのディスクからデータベースサーバーのメモリにデータをコピーし、次にデータベースサーバーのメモリからデータベースサーバーのネットワークポートにデータをコピーし、次にネットワークからWebサーバープロセスにコピーしてから、発信ネットワーク接続。

本当に正当な理由がない限り、ファイルシステムから静的ファイルを提供する方が常に良いです。


これは本当ですが、ユーザーがデータベースから静的ファイルを提供するという質問でユーザーがどこに述べているかわかりません。これは、動的ファイルまたはユーザーがアップロードしたファイルである可能性があります。これらのファイルは、データベースとは別のファイルシステムに保存されている場合、同期し、個別のバックアップ/復元プロセスが必要です。
maple_shaft

1
私の理解では、質問はユーザーがアップロードしたファイルの提供に関するものです。「現在、ユーザーがファイルを保存および共有できるWebアプリケーションを作成しています[...]データベースにファイルを保存するようです[...]」データベースに多数のマルチメガバイトのblobがあるDBダンプを実行するのはそれほど便利ではないと思います。また、はい、ファイルを扱うのは難しいです。同期、アーカイブはすべて困難です。ただし、それほど難しくはなく、夜間のバックアップスクリプトで数行を保存するためにオンラインパフォーマンスを犠牲にすることは大きな間違いです。
エヴァンP.

5

有名なTom Kyteは、彼ら(Oracle)がOracleデータベースをファイルサーバーとして使用しており、完全に正常に動作し、通常のファイルシステムよりも高速で、完全なトランザクション性、パフォーマンスの損失なし、単一バックアップで動作していると書いています。

はい。ただし、Oracle DBのプロデューサーであり、他のユーザーにはコストの問題があることに注意してください。ファイルの保存にOracleなどの商用DBを使用することは、単にコスト効率が悪いです。

ただし、たとえばPostgreSQLを使用すると、blobストレージに対してのみ別のDBインスタンスを実行できます。その後、完全なトランザクションサポートを利用できます。ただし、トランザクション性にはDBスペースがかかります。複数の同時トランザクションの複数のblobインスタンスをデータベースに保存する必要があります。PostgreSQLでは、このデータベースはトランザクション用に作成されたBLOBの複製を保存するため、VACUUMプロセスが完了するまで、不要になったとしても保存されるため、最も苦痛です。

一方、ファイルシステムストレージでは、誰かがファイルを変更する場合、トランザクションをロールバックでき、古いバージョンが表示されなくなるまでファイルのコピーを保持する必要があるため、非常に注意する必要があります。

ファイルの追加と削除のみが行われ、ファイルへのトランザクションアクセスが問題にならないシステムでは、ファイルシステムストレージが最適な選択肢となります。


こんにちは、「ファイルのストレージにOracleを使用するだけで費用対効果が低い」と言ったとき、他の非ファイルデータのストレージにOracleをすでに使用している場合はどうでしょうか。それでも費用対効果は低いですか?
シャオペン-ZenUML.com

RE:「誰かがファイルを変更するときは十分に注意する必要があります」...以前のOracle DBAとして、大きなファイルはデータベースから除外し、ファイルの変更を許可しないことを提案する必要があります。人々は間違いを犯します。これらのファイルのロールバック(取り消し)を管理する唯一の実用的な方法は、それらのファイルにコピーオンライトシステムを実装することです。したがって、すべてのバージョンが維持され、アーカイブされます。最古のは、リモート・ストレージなどの1つのアーカイブの中に小さな変更を統合するために処理ポストにオフに移動することができます
DocSalvager

5

通常、大きなBLOBを別のテーブルに格納し、メインテーブルのBLOBへの外部キー参照を保持するのが最善です。そうすれば、データベースからファイルを取得することができ(特別なコードは必要ありません)、外部のDB依存関係に関連する問題(DBとファイルシステムの同期など)を回避できますが、そのオーバーヘッドが発生するだけです。そのテーブルに明示的に参加する(または別の呼び出しを行う)場合。10MBはそれほど大きくなく、ほとんどの最新の商用データベースには問題はありません。ファイルシステムにファイルを保存する唯一の理由は、データベースの帯域幅を削減することです。データベースでこれらのファイルの多くをシャッフルする場合、ワークロードを分割し、ある種のファイル記述子のみを保存する必要があります。その後、別のサーバーからファイルをロードするために別の呼び出しを行うことができます。


4

この問題のいくつかに出くわすかもしれません:

  • SELECT *大きなblobを持つ行を含むa を実行すると、blobが不要な場合でも非常に時間がかかります(もちろん、特定のselectを実行する必要がありますが、アプリケーションはこのように記述される場合があります)
  • バックアップを実行すると、さらに時間がかかる場合があります。必要に応じて、バックアップ時にテーブルをロックする必要がある場合があります。そのため、バックアップ時間を短く保つことができます。
  • 復元にも時間がかかります。
  • スペースが足りなくなった場合、この問題を解決するために何らかの方法(データベース全体を新しいサーバーに移動する可能性があります)を考える必要があります。ファイルシステムにファイルを保存すると、いつでも別のハードドライブをマウントして、ソフトリンクを設定できます。
  • デバッグやその他の情報のためにファイルを調べるだけでは簡単ではありません。これには、データベースにはアクセスできないが、さまざまなファイルからの情報が必要なスクリプトも含まれます。

もちろん、いくつかの利点もあります。

  • 同期しているデータとファイルのメナのバックアップ
  • データベースを認識せずにファイルを削除することはできません
  • ディスクからファイルを読み取る必要はありませんが、1つのSQLステートメントで実行できます
  • データベースをダウンロードし、開発環境にダンプを含めて、すべての依存関係をそこに置くことができます

個人的に私は短所がプロよりも重いと思うのでそれをしません。ただし、上記のように、ユースケースなどに完全に依存します。


1

SiteCoreなどの一部のEnterpirseコンテンツ管理システムは、1つのデータベースを使用してページデータを保存し、別のデータベースを使用してファイルを保存しています。彼らはMS SQL Serverを使用しています。


これは質問にどう答えますか?
gnat

少し調べてみると、SiteCoreは最も人気のあるエンタープライズコンテンツ管理システムの1つであることがわかります。SiteCoreは多数の同時ユーザーをサポートし、拡張性が非常に高いため、ファイルを別のデータベースに保存することは、適切に行うのであれば悪い習慣ではありません。
šljaker

1

実際に実装するために、次の点に注意してください。

メリット:

  1. すべてのファイルの内容は間違いなくテーブルと同期されます。上記のコメントで述べたように、データをファイルシステムと同期させる必要がないため、データのバックアップは非常に便利です。
  2. コーディングから、SQL selectから直接ファイルコンテンツを取得できます。
  3. クエリから、SQL文からファイルの内容またはサイズを明示的にフィルタリングすることもできます。

欠点:

  1. 構造的に意味が同じでファイルコンテンツを保存しないデータベースと比較すると、データベースはクエリを実行する際に大幅に多くのメモリを消費する傾向があります。
  2. 自動バックアップはパフォーマンスの問題を引き起こす可能性がありますが、それほど問題にはなりません。データベースサーバーが6時間ごとにバックアップを行っており、所有するデータベースがレコードごとに10 MBのファイルを保存しているとします。そのシナリオはあなたが望むものではありません。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.