2つの名前列を持つテーブルがあります。
CREATE TABLE Test
(
TestID int identity primary key clustered
, Name_Eng nvarchar(50)
, Name_Nat nvarchar(50)
)
このName
列を,
で区切って取得するには、次のようにクエリが必要です。
DECLARE @NameColumns NVARCHAR(1024)
SET @NameColumns = STUFF(
(SELECT ',' + 'Test.' + name AS [text()]
FROM ( SELECT c.name
FROM sys.columns c
INNER JOIN sys.tables t ON t.object_id = c.object_id
WHERE t.name = 'Test'
AND c.name LIKE 'Name_%'
) AS D
FOR XML PATH('') ,
TYPE).value('.[1]', 'VARCHAR(MAX)'), 1, 1,
N'')
select @NameColumns
ただし、このクエリの実行プランには警告があります。
この警告を削除する方法はありますか?
XML関数value()
が原因で警告が表示されます。 value()
の2番目のパラメーターは、XMLに格納されている値の変換先です。これは実際に暗黙的な変換ではなく、発生を要求しているため、非常に明示的な変換であると主張できます。おそらく、接続アイテムがMicrosoftに提案するものです。
あなたが見るものを再現する最も簡単な方法。
_declare @X xml;
select @X.value('text()[1]', 'int');
_
これらの2つの警告を表示します。
_<Warnings>
<PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(int,XML Reader with XPath filter.[lvalue],0)" />
<PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(int,XML Reader with XPath filter.[value],0)" />
</Warnings>
_
ご覧のとおり、intでも同様に取得し、value()
を呼び出すたびに2つ取得します。
_declare @X xml;
select @X.value('text()[1]', 'int'),
@X.value('text()[1]', 'bit');
_
_<Warnings>
<PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(int,XML Reader with XPath filter.[lvalue],0)" />
<PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(int,XML Reader with XPath filter.[value],0)" />
<PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(bit,XML Reader with XPath filter.[lvalue],0)" />
<PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(bit,XML Reader with XPath filter.[value],0)" />
</Warnings>
_
このような値を計算するStream Aggregateオペレーターで変換が行われます。
_MIN(CASE WHEN [@X] IS NULL
THEN NULL
ELSE
CASE WHEN datalength(XML Reader with XPath filter.[value])>=(128)
THEN CONVERT_IMPLICIT(int,XML Reader with XPath filter.[lvalue],0)
ELSE CONVERT_IMPLICIT(int,XML Reader with XPath filter.[value],0)
END
END)
_
テーブル値関数の結果は、lvalue
またはvalue
列に返されます。式は、datalength
を使用してチェックし、どこからフェッチするかを確認してから、目的のデータ型に変換します。
この警告を削除する方法はありますか?
はいあります。 _FOR XML PATH
_ステートメントからTYPE
ディレクティブを削除し、value()
関数の呼び出しを削除します。そうすることの副作用は、_&<>
_のようなXMLでエンコードする必要がある文字を含む連結した値が結果でエンコードされることです。
@Kinのデータ型については同意しますが、この警告はあなたが思っているほど厄介ではないと思います。いずれにしても、変換よりも桁違いにコストがかかるグループ化された連結を実行しています(そして、Danielが言ったように、物理メモリよりも大きいなど、カタログビューが大量でない限り、それは、見積もり)。
私はvarchar文字列(文字列リテラルのN
プレフィックスを省略しないことも意味する)を使用しないように注意しながらクエリをこのように記述します ステートメントターミネータを使用することを保証 :
_DECLARE @NameColumns nvarchar(max); -- why 1024 when you use max below?
SET @NameColumns = STUFF(
(SELECT N',Test.' + name AS [text()] FROM
(
SELECT c.name FROM sys.columns AS c
INNER JOIN sys.tables AS t
ON t.object_id = c.object_id
WHERE t.name = N'Test'
AND c.name LIKE N'Name_%'
) AS D FOR XML PATH(N''),
TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'');
SELECT @NameColumns;
_
それでも、Mikaelが提案したようにTYPE
/value()
を回避して出力を変更せずに暗黙的な変換を回避する方法はないと思います。これがクエリのパフォーマンスに重大な影響を与えることを実際に証明できる場合、私はこれについて心配するでしょう。私のテストでは、2つの異なる形式は同じように動作しました(毎回10ミリ秒未満で話しています)が、もちろん_Sales & Stuff
_という名前のテーブルがある場合、暗黙的な変換なしで_Sales & Stuff
_になります。
クエリプランの警告は、暗黙的なデータ型変換があるため、SQL Serverが返される行の正しい数を正確に推測できず、その結果mightがより小になることを意味します-最適な計画。
これは通常、大量のデータを処理するため、適切に実行する必要があるクエリでは重要ですが、sys.tables
とsys.columns
をクエリしているだけなので、状況によってはそうではないようです。
あなたの質問への短い答えは、データベースに数百万、数百万のテーブルと列がなければ、問題ではありません。