web-dev-qa-db-ja.com

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

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

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

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

私はPHPおよびこのプロジェクトのMySQLで作業していますが、ほとんどの環境で同じ問題です( Ruby on Rails[〜#〜] php [〜#〜]。NET )およびデータベース(MySQL、 PostgreSQL )。

202
B Seven

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

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

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

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

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

一般に、私の経験では、パスの保存は、ACIDの欠如と孤立の可能性を考慮に入れても、ビジネスにとって費用がかからないことがわかっています。ただし、これは、ACID制御の欠如がファイルストレージでうまくいかないという話がインターネットに影響を与えるわけではないことを意味しますが、一般に、ソリューションの構築、理解、維持がより簡単になることを意味します。

145
Thomas

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

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

93

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

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

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

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

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

また、ウェブアプリケーションについて話しているため、最新のウェブサーバーを使用してファイルシステムから静的ファイルを直接提供します sendfile() syscall is tremendousパフォーマンスの向上。もちろん、DBからファイルをフェッチしている場合、これは不可能です。たとえば、 このベンチマーク を考えてみます。Ngnixはローエンドのラップトップで25Kリクエスト/秒で1000同時実行接続を示しています。この種の負荷は、あらゆる種類のDBを処理します。

36
vartec

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

ただし、データベースにデータを保存することで、他の問題(たとえば、ファイルを保存する場所、ファイルをバックアップする方法などシステムなので、プロセスがデータが格納されているフォルダへの読み取り/書き込みアクセス権を持つようにサーバーを構成する必要があります。

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

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

21
Pete

Microsoftは数年前にこれに関するホワイトペーパーをリリースしました。それはSqlServerに集中していますが、そこにいくつかの興味深い情報を見つけるかもしれません:

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

彼らの結論の非常に簡潔なバージョンは:

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

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

16
Benjol

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

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

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

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

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

バックアップした

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

確保された

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

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

ロックがあります

読みの一貫性があります...

11

はい。

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

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

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

8
Evan P.

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

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

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

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

ファイルが追加および削除されるだけで、ファイルへのトランザクションアクセスが問題にならないシステムでは、ファイルシステムストレージが最良の選択です。

5
Danubian Sailor

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

5
TMN

この問題のいくつかに遭遇するかもしれません:

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

もちろん、いくつかのメリットもあります。

  • 同期しているデータとファイルをバックアップする
  • データベースが知らないうちにファイルを削除することは不可能です
  • ディスクからファイルを読み取る必要はありませんが、1つのSQLステートメントで読み取ることができます。
  • データベースをダウンロードし、ダンプを開発環境に含め、すべての依存関係をすぐに持つことができます

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

4
Sgoettschkes

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

1
šljaker

実用的な実装のために、ここにあなたが心配するかもしれないものがあります:

メリット:

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

欠点:

  1. セマンティック上は同じであるがファイルのコンテンツを格納しないデータベースと比較すると、データベースはクエリを実行する際にメモリを大幅に消費する傾向があります。
  2. 自動バックアップはパフォーマンスの問題を引き起こす可能性がありますが、それほどではありません。データベースサーバーが6時間ごとにバックアップを行っていて、それらのデータベースがレコードごとに10 MBのファイルを保存しているとしましょう。そのシナリオはあなたが望むものではありません。
1

これは、「かみそりの刃を使ってリンゴを切り開くことはできますか」の1つです。はい、できます。

しますか? 誰に伝えるか ...

私は、ツールがそれを許可するか、または利用可能な唯一のツールである(少なくともその期限を達成するための)状況にいると思います。たとえば、マイナスドライバーを使用してフィリップスボルトタイプを取り外しました...それでよろしいですか?それは正しいツールでしたか?それは悪い選択でしたか?

この場合の答えは次のとおりです。DBはファイルを保存することを想定していません...間違っている場合はいつでも、理論的にはマイナスドライバを使用してフィリップスボルトを外すべきではありませんでした。フィリップススクリュードライバーの位置がずれず、私が作業しているものに損傷を与えないという利点(DBをファイルストレージソリューションとして使用すると、利点が失われるため)...でも、リスクを適切に計算したところ、すべてがうまくいきました。

正しいことをしたい場合は、おそらくgitを使用してファイルを格納し、必要なgitハッシュをDBに保持して、必要な正しいファイルバージョンを参照する必要があります...私のツールにアクセスするのと同じ方法でボックスとくそフィリップスドライバーを取得...

0
Ordiel