Dynamics AXには、テーブルをメモリにロードしてキャッシュするように構成できるキャッシュメカニズムがあります。このキャッシュは、メモリの問題を防ぐために、特定の量のKBに制限されています。私が話している設定はentiretablecache
と呼ばれ、単一のレコードが要求されるとすぐにテーブル全体をメモリにロードします。
最近まで、いくつかのスクリプトを使用して、この設定を持つテーブルのサイズを確認し、テーブルのサイズがこの制限を超えているかどうかを確認していました。
ただし、圧縮が機能し、 sp_spaceused または sys.allocation_units のようなものが、圧縮されたデータによって実際に使用されている領域を報告しているようです。
明らかに、アプリケーションサーバーは非圧縮データを処理しているため、SQL Serverのディスク上のデータサイズは関係ありません。非圧縮データの実際のサイズが必要です。
sp_estimate_data_compression_savings は知っていますが、名前が示すように、これは単なる見積もりです。
できるだけ正確なサイズにしたいと思います。
考えられる唯一の方法は、複雑な動的SQLが圧縮テーブルと同じ構造の非圧縮テーブルを作成し、そのシャドウテーブルに圧縮データを挿入してから、そのシャドウテーブルのサイズを確認することでした。
言うまでもなく、これは少し面倒であり、数百GBのデータベースで実行するには時間がかかります。
Powershellをオプションにすることもできますが、すべてのテーブルを繰り返し処理してselect *
を実行し、スクリプトのサイズを確認すると、キャッシュがいっぱいになるだけで、おそらく時間がかかります。
簡単に言えば、可能であれば、各テーブルのサイズを取得する方法が必要です。これは、一度圧縮解除され、アプリケーションに提示される方程式から断片化されるためです。私はさまざまなアプローチを受け入れていますが、T-SQLが推奨されますが、Powershellまたは他の創造的なアプローチに反対していません。
アプリケーションのバッファがデータのサイズであると想定します。 bigintは常にbigintのサイズであり、文字データ型は1文字(ユニコード)あたり2バイトです。 BLOBデータもデータのサイズを取ります。列挙型は基本的にintであり、数値データは数値(38,12)です。datetimeは日時のサイズです。また、NULL
値はなく、空の文字列1900-01-01
またはゼロとして格納されます。
これがどのように実装されているかについてのドキュメントはありませんが、前提条件は、PFEとサポートチームが使用するいくつかのテストとスクリプトに基づいています(チェックはアプリケーションに組み込まれており、アプリが判別できないため、圧縮も明らかに無視します)基になるデータが圧縮されている場合)テーブルサイズもチェックします。 このリンク 例の状態:
大きなテーブルにEntireTableキャッシュを使用しないでください(AX 2009では128 KBまたは16ページ以上、AX 2012では「テーブルキャッシュサイズ全体」アプリケーション設定(デフォルト:32KB、または4ページ))-代わりにレコードキャッシュに移動します。
非圧縮データの実際のサイズが必要です。
...
できるだけ正確なサイズにしたいと思います。
この情報への欲求は確かに理解できますが、特に「可能な限り正しい」という状況でこの情報を取得することは、誤った仮定のために誰もが予想しているよりも困難です。質問で言及されている非圧縮シャドウテーブルのアイデアを実行しているか、DBの復元とそこへの圧縮解除に関するコメントでの@sp_BlitzErikの提案を実行しているかにかかわらず、非圧縮テーブルのサイズ==メモリ内の上記データのサイズとは見なされません。アプリサーバー上:
all行がキャッシュされていますか?それとも範囲内ですか?ここでの仮定はそれがすべてであり、それが正しいかもしれないということですが、少なくとも、mightがそうではないことを言及する必要があると考えました(ドキュメントに特に記載がない限り、これはとにかくマイナーポイント、それが言及されたくないだけでした)。
質問が次の状態に更新されました:はい、すべての行がキャッシュされています。
構造オーバーヘッド
FILLFACTOR
が100(または0)であっても、行全体に十分ではないため、ページに未使用のスペースが残っている可能性があります。そしてそれはページヘッダーに追加されます。また、スナップショット分離機能が有効になっている場合は、バージョン番号が1行あたり13バイト余分に使用するため、見積もりが失われると思います。行の実際のサイズに関連する他の特徴点(NULLビットマップ、可変長列など)がありますが、これまでに説明した項目だけでポイントになります。DataTable
ですか?一般的なリストですか? SortedDictionary?コレクションのタイプごとに、耳に聞こえる量が異なります。特に大規模な場合、DB側のページと行のオーバーヘッドを必ずしもミラーリングするオプションはないと思います(少量の行では問題になるほど十分ではないかもしれませんが、違いを探していません。数百バイトまたはほんの数キロバイト)。CHAR
/VARCHAR
データは、文字あたり1バイトで格納されます(現時点では2バイト文字は無視されます)。 XML
は、テキスト表現が意味するほど多くのスペースを取らないように最適化されています。このデータ型は、要素と属性の名前のディクショナリを作成し、ドキュメント内のそれらへの実際の参照をそれぞれのIDで置き換えます(実際にはちょっといいです)。それ以外の場合、NCHAR
/NVARCHAR
と同様に、文字列値はすべてUTF-16(「文字」あたり2または4バイト)です。 _DATETIME2
_は6〜8バイトです。 DECIMAL
は5〜17バイトです(精度によって異なります)。VARCHAR
が保持するような8ビット文字列の最適化はありません。ただし、文字列は「インターン」することもできます。これは、何度も参照できる共有コピーです(ただし、これがコレクション内の文字列に対して機能するかどうか、またはすべてのタイプのコレクションに対して機能するかどうかはわかりません)。 XML
は、メモリに同じ方法で格納される場合とされない場合があります(これを調べる必要があります)。 DateTime
は常に8バイトです(T-SQL DATETIME
と同様ですが、DATE
、TIME
、または_DATETIME2
_とは異なります)。 Decimal
は 常に16バイト です。つまり、アプリサーバー側でfairly正確なメモリフットプリントサイズを得るために、DB側でできることはほとんどありません。特定のテーブルをロードした後、アプリサーバー自体に問い合わせる方法を見つける必要があるので、それがどれほど大きいかを知ってください。そして、デバッガーが、満たされたコレクションのランタイムサイズを表示できるかどうかはわかりません。そうでない場合、閉じるには、テーブルのすべての行を調べ、各列に適切な。NETサイズを乗算する(例: INT
= _* 4
_、VARCHAR
= DATALENGTH() * 2
、NVARCHAR
= DATALENGTH()
、XML
= ????など)ですが、それでもコレクションのオーバーヘッドとコレクションの各要素の問題が残ります。
質問にいくつかの新しい定義が与えられた場合、おそらく次のクエリを実行してかなり近づけることができます。そして、テーブルが圧縮されているかどうかは関係ありませんが、すべての行のスキャンが本番環境で適切かどうかを判断するのは各自の責任です(おそらく、復元から、またはオフピーク時に行います)。
_SELECT
SUM( DATALENGTH([NVarcharColumn_1]) + DATALENGTH([NVarcharColumn_N]) ) +
SUM( (DATALENGTH([VarcharColumn_1]) + DATALENGTH([VarcharColumn_N])) * 2 ) +
SUM(4 * [number_of_INT_columns]) +
SUM(8 * [number_of_BIGINT_and_DATETIME_columns]) +
SUM(16 * [number_of_DECIMAL/NUMERIC_and_UNIQUEIDENTIFIER_columns]) +
etc..
FROM [SchemaName].[TableName] WITH (NOLOCK) -- assuming no Snapshot Isolation
_
ただし、これはコレクションまたはコレクション要素のオーバーヘッドを考慮していません。デバッガーなしでその値を取得できるかどうか(またはILSpyのようなものかもしれませんが、mightが現地の法律に応じてEULAに違反しているため、私はそれをお勧めしません)。
あなたの質問から、あなたは最大キャッシュサイズS
があり、そのサイズを超えるキャッシュにテーブルをロードしたくないようです。それが本当なら、各テーブルの正確なサイズを知る必要はありません。テーブルが最大キャッシュサイズS
より大きいか小さいかを知る必要があるだけです。テーブルの列定義と行数によっては、これは非常に簡単な問題です。
圧縮されていないデータを調べるのは適切な方法ではなく、キャッシュ内のテーブルの実際のサイズを適切に概算することが難しい場合があるという点で、Solomon Rutzkyの素晴らしい答えに同意します。ただし、質問の枠組みの中で作業し、静的データ型の列定義と動的列の実際の長さに基づいて十分に近い数式を作成できると想定します。
キャッシュサイズへのデータタイプのマッピングがある場合、テーブル内のデータを見ることさえせずに、いくつかのテーブルを評価できるはずです。
sys.partitions
_を見て行数を概算し、列定義を使用してテーブルのサイズを計算できます。BIGINT
列を持つテーブルでは、10000000 *(8 + 8 + 8 + 8 + 8)= 400 Mバイトのサイズのデータがあり、キャッシュサイズの制限S
。文字列列がたくさんあるかどうかは関係ありません。BIGINT
列とNVARCHAR(20)
列を持つ100行のテーブルは、100 *(8 + 2 * 20)= 4800バイトを超えることはできません。S
の因数だけ大きい場合、キャッシュに収まる可能性が非常に低いことは事実です。このような値が存在するかどうかを調べるには、テストを行う必要があります。上記の基準のいずれにも適合しないテーブルのデータをクエリする必要がある場合があります。これによるパフォーマンスへの影響を最小限に抑えるために使用できるいくつかのトリックがあります。ここでは、競合する優先順位が2つあると思います。正確性を重視しますが、データベース内のすべてのデータをスキャンする必要もありません。ある種のバッファを計算に追加することが可能な場合があります。 S
の最大キャッシュサイズをわずかに下回るテーブルを除外するのか、最大キャッシュサイズをわずかに上回るテーブルを含めるのが適切かはわかりません。
以下は、テーブルデータをより速く参照するクエリを作成するためのアイデアです。
TABLESAMPLE
を使用できる場合があります。SUM()
を計算する方法を知りません。私はこれまでROW_NUMBER()
で機能することを見たことがあります。ただし、テーブルの最初の10%をスキャンし、計算されたデータサイズを節約し、次の10%をスキャンする、などとすることができます。キャッシュに対して大きすぎるテーブルの場合、このアプローチを使用すると、早期に終了することでかなりの量の作業を節約できる可能性があります。この回答にはSQLコードが含まれていないことに気づきました。ここで説明したアイデアのデモコードを作成するのに役立つかどうかをお知らせください。