ユーザーが結果をフィルターしたい特定のデータポイントを選択できるUIがあります。場所、部門などがあります。すべてのオプションを選択したら、ストアドプロシージャに渡すXML文字列を生成します。
そこから、たとえば場所の場合、一時テーブルを作成し、ユーザーが選択したすべての場所をそのテーブルにダンプします。このテーブルを後でデータに結合します。
実行プランを実行すると、フィルターデータを解析している5つほどのクエリのそれぞれに約12%のコストがかかることに気づきました。これは、フィルターするデータを決定するためだけのクエリの60%以上です。
DECLARE @tmLocations TABLE (
location VARCHAR (100));
BEGIN
INSERT INTO @tmLocations
SELECT ParamValues.x1.value('location[1]', 'VARCHAR(200)')
FROM @xml.nodes('data/teammateLocations/locations') AS ParamValues(x1);
END
実行にそれほどコストがかからないように、XMLからデータを抽出する別の方法、または上記のようなクエリを改善する方法はありますか?データの設定には、実際のデータのフィルタリングよりもコストがかかり、パフォーマンスが本当に低下します。
実行プランを実行すると、フィルターデータを解析している5つほどのクエリのそれぞれに約12%のコストがかかることに気づきました。これは、フィルターするデータを決定するためだけのクエリの60%以上です。
クエリのコストは、実際の実行プランでも見積もりに基づいています。クエリの実際の効率はわかりません。
推定値は統計に基づいており、それらは古くなり、誤った推定値とコストを与える可能性があります。
XMLクエリの見積もりは常に間違っています。 XML列の統計は生成されず、XMLパラメーターまたは変数の統計も生成されません。
このかなり単純なXMLクエリを見てください。
_declare @X xml;
select 1
from @X.nodes('*') as T(X);
_
推定クエリプラン
SQL Serverは、XMLに10000の要素があると想定し、そこから推測し続けます。 nodes()
関数を使用すると、200個が返されると想定されます。その前に、_@X is not null
_が推定行数を66に制限しているかどうかをチェックするフィルター演算子があります。純粋な推測であり、XMLに実際にあるデータにまったく影響されません。
クエリが十分かどうかを知るには、期間、読み取り回数、割り当てられたメモリなどを確認する必要があります。推定コストを使用しないでください。個々のクエリのパーセンテージを使用してパフォーマンスを比較しないでください。
Mister Magooがコメントで提案するように、XMLクエリを改善することができます。
_SELECT ParamValues.x1.value('(location/text())[1]', 'VARCHAR(200)')
FROM @xml.nodes('data/teammateLocations/locations') AS ParamValues(x1);
_
text()
ノードを指定しない場合、SQLサーバーは混合コンテンツXMLで機能するプランを生成し、サブノードからのすべてのノード値を連結する必要があります。