web-dev-qa-db-ja.com

コンテナー間でFILESTREAMファイルを移動または再配布するにはどうすればよいですか?

数百万のファイルを含むFILESTREAMコンテナがあり、それが現在発生しているパフォーマンスの問題(大量のタイムアウト)の原因であると考えています。

このブログFILESTREAMのベストプラクティスによると、各コンテナは300,000を超えるファイルに到達しないようにする必要があります。

ここで受け入れられた回答 によると、テーブルを新しいFILESTREAMの場所に再作成することを除いて、これを達成する方法はありません。

  1. これは私の状況に当てはまりますか?
  2. もしそうなら、300,000ファイルごとに手動の介入なしにこれを処理するのに十分なコンテナーが自動的に作成されることを保証するための推奨アプローチは何ですか?

テーブルの構造は次のとおりです。

CREATE TABLE [dbo].[Documents](
    [ContentPath] [uniqueidentifier] ROWGUIDCOL  NOT NULL,
    [FileContent] [varbinary](max) FILESTREAM  NULL,
 CONSTRAINT [UQ_IX_Documents_ContentPath] UNIQUE NONCLUSTERED 
(
    [ContentPath] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY] FILESTREAM_ON [FSFileGroup_1]

私たちはSQL Server 2012を使用しています。残念ながらEnterpriseではありません(最近、ファイルグループごとに複数のコンテナーをサポートすることを認識しました)。

更新を記録することはありませんが、書き込みの数は多く、おそらく読み取りの数と同じです。パターンは次のとおりです。一度に1つだけ、ContentPathで読み取り、特定のコンテナーまたは順序で書き込みを行いません。

6
Daniel Minnaar

私にとっては、テーブルを論理的に分割することをお勧めします。そのため、すべてのセクションが独自のフォルダーにあり、300k以下のファイル(=レコード)を持ちます。

SQL Serverでは、論理テーブルの分割は通常、パーティション分割で行われます(これはエンタープライズ機能です)。パーティション分割は基本的に、テーブルのセクション(パーティション)を物理ストレージ(ファイルグループ)にマップします。さまざまなパーティションを異なるファイルグループに割り当てることができます。 FILESTREAMは基本的にファイルグループのプロパティです。

設計

これはあなたのソリューションの背骨を構成します:

  • パーティションが異なるファイルグループに存在する
  • 各ファイルグループは、個別のFILESTREEAMフォルダー/コンテナーです
  • 300kレコード以下の各パーティションのサイズ

これが FILESTREAM列でテーブルを分割する方法 です。

主な利点:テーブル全体ではなく、パーティションごとにFILESTREAMデータを一度に管理できます。

あなたは必要になるでしょう:

  1. パーティションのサイズを追跡できる、または少なくともパーティション間のランダムな書き込みを許可しないID

    _[Id] [uniqueidentifier] ROWGUIDCOL NOT NULL DEFAULT (newsequentialid())
    _
  2. 最後のパーティションの空き容量を確認するメンテナンスジョブ、事前に新しいファイルグループとパーティションを作成する、パーティションごとにインデックスを再構築するなど。

  3. Insertオペレーションに対応するには、パーティションが300k未満になるため、インデックスは一度に1つのパーティションを再構築します。

この設計は、ほとんどの場合、最後に挿入が発生する読み取り専用テーブル用です。まだ行っていない場合は、書き込みと更新、およびそれらに対するパーティション分割の影響を考慮してください。

マイグレーション

テーブルをパーティション分割するには、インデックスを作成する必要があります。主に2つの方法があります。

  1. テーブル全体のインデックスを再構築します。テーブルのx2〜x3倍のスペースが必要です。多くの理由により、大きなテーブルには適していません。

  2. すでにパーティション分割されている新しいテーブルにデータを移行します。

これに対する私の好ましい方法:

  • ターゲットパーティションテーブルと同じ構造のテーブルを作成します。
  • 1つのパーティションに収まるデータの場合、_DELETE... OUTPUT DELETED ... INTO <intermediary table>_を使用してデータを挿入します。
  • 1つのトランザクションに対して行数が多すぎる場合は、これをループにラップします
  • パーティションスキームにインデックスを作成する
  • パーティションをターゲットテーブルに切り替える
  • 中間テーブルのインデックスを削除
  • ループにラップし、すべてのパーティション/データについて繰り返します

インサート

新しく挿入された行は、理想的には最後のパーティションに配置する必要があります。ただし、NEWSEQUENTIOALID()関数には注意点があります。

GUIDこれは、任意の値よりも大きいGUID Windowsの起動以降、指定されたコンピューター上でこの関数によって以前に生成されました。Windowsの再起動後、GUIDは低い範囲から再開できますが、それでもグローバルに一意です。

つまり、サーバーの最初の再起動まで、新しい書き込みは最後のパーティションにのみ行われます。そして、これは最終的に起こります。新しい行がテーブルの中央に挿入されます。しかし、今パーティションがあることを覚えていますか?一度に1つのパーティションのみが影響を受けます。それでも、ある時点で30万行を超えることになります。

ここでの主なオプションは、パーティションを分割することです。既存のパーティションは2つに分割され、右側の部分が新しいパーティションを形成します。新しいパーティションは新しいファイルグループに移動する必要があります。これはメタデータのみの操作ではありません:ファイルは物理的に別のパーティションにコピーされます。

回避策は、同じPSで行を移動(行を削除して中間テーブルに挿入)することです。パーティションを分割して行を戻します。ただし、いずれにしてもデータの移動が必要です。同じPSに中間テーブルがある場合、分割にはデータの移動が含まれます。そうでない場合、データをもう一度メインテーブルに戻す必要があります。

複数のFILESTREAMコンテナー

複数のFILESTRAMコンテナーは、エンタープライズバージョンの機能です。コンテナは、FILESTREAMコンテナでは「フォルダ」と呼ばれることがよくあります。実際には、FILESTREAMタイプのファイルグループ内のデータベースファイルです。

NTFSフォルダーごとに300k未満のファイルを保持するのに役立ちますが、これらのフォルダー全体で保存されたファイルを明示的に管理することは非常に困難です。

記事 ファイルグループ内のファイル間でのデータの再調整 2011からPaul Randallがファイルグループ内のファイルの使用に関するヒントを提供します。

[SQL Server]は、ファイルグループ内の他のファイルとの相対的な空き容量に応じて、ファイルからデータを割り当てることを目的とするプロポーショナルフィルと呼ばれるアルゴリズムも使用します。

...

つまり、ほとんどが完全なデータファイルを持つファイルグループに新しいデータファイルを追加する場合、比例的な塗りつぶしの重み付けは、新しいファイルが、古いファイルと同じレベルに達するまで割り当てが行われるファイルになるようになります。ファイル。本質的に、新しいファイルは割り当てホットスポットになります。

SQL Serverは、他のファイルと同じ%ageレベルになるまで、新しく追加されたファイルを最初に埋めます。

パーティショニングのより簡単な代替手段のように見えるかもしれませんが、そうではありません:

  1. 既存のコンテナに既に保存されているファイルについては何もできません。
  2. 単一のトランザクション内で管理する必要がある大きなテーブルがまだ1つあります

同時に、複数のFILESTREAMコンテナーをパーティション分割ソリューションにブレンドして、フォルダーをより小さく高速にすることができます。

Standard Edition(SE)の更新

SEには、パーティション化も複数のFILESTREAMコンテナーもありません。つまり、テーブルごとに1つのパーティションと1つのコンテナーしか持てません。

1つのオプションは、_UNION ALL_ビューを上部に持つ複数のテーブルを持つことです。

  • ほとんどの場合、テーブルの数は固定されます。すでにかなりの数のドキュメントを持っているので、GUIDの分布を見て、より低い密度でより低い密度のテーブルを作成し、下端で作成できます。
  • すべてのテーブルを_UNION ALL_するビューを作成します。 ヒント:すべてのテーブルのスキャンを回避するために、その特定のテーブルに属するIDのWHERE句を追加します。オプティマイザーが特定のテーブルが存在しないテーブルを除外するのに役立ちます。
_    Select * from Table1 where ID between 1 and 100 
    UNION ALL
    Select * from Table2 where ID between 101 and 10000 
    UNION ALL
    Select * from Table3 where ID between 10001 and 100000000 
_

GUID from _0000-...-0000_ to _FFFF-...-FFFF_)のすべての可能な値をカバーしていることを確認してください-このビューは更新可能であるため、次のコマンドを使用して関連するテーブルにデータを挿入できます ビューによるデータの変更 。-すべてのデータを既存のテーブルから新しいテーブルに物理的にコピーする必要があります。これは、マスタービューを介して実行できます。

追伸SQL Serverは、まずRDMSです。 VARBINARY(MAX)などの大量の非構造化データを管理する機能は、アドオンで比較的新しいものです。したがって、考慮する必要がある他の制限があります。

テーブルあたりの最大パーティション数:15 000最大ファイルグループORデータベースあたりのファイル数:32 767コンテナあたりの最大ファイル数:300 000(=この例ではファイルグループ、=複数のコンテナの場合はデータベースファイル)ファイルグループごと)

トランザクションログのサイズは、1つのトランザクションの制限と、トランザクションが完了するまでの時間です。合理的な時間内にロールバックするには、個々の操作を管理可能かつ可能な状態に保つ必要があります。

5
Stoleg