質問

バックグラウンド

最近、私はXMLをSQL Server2005のコラムとしてより多く使用し始めました。昨日の少しのダウンタイムの間に、私が本当に邪魔になった2つのリンクテーブルが邪魔になっていることに気付きました。いくつかの結合のために、さらにサポート構造コードを書いてください。

これら2つのリンクテーブルのデータを実際に生成するために、メインレコードを書き込む2つのXMLフィールドをストアドプロシージャに渡し、2つのXML変数を@Tablesに分割し、新しいテーブルに挿入します。 SCOPE_IDENTITY() マスターレコードから。

しかし、いくつかの後、私はそれらのテーブルを完全に廃止し、XMLをXMLフィールドに保存することにしました。今ここには、一般的なクエリパフォーマンスのような落とし穴があることを理解しています。 GROUP BY XMLデータでは機能しません。そして、クエリは一般的に少し混乱していますが、全体的に私は今一緒に仕事ができるのが好きです XElement データを元に戻したとき。

また、このようなものは変更されません。それはワンショットの出来事なので、変更を心配する必要はありません。

このデータを実際に取得するための最良の方法について疑問に思っています。私の質問の多くは、子供の基準やサブチャイルドレコードに基づいてマスターレコードを取得することです。データベース内のSPROCのほとんどはこれを行いますが、通常ははるかに精巧なスケールで、通常はUDFとサブクリーリーが効果的に機能する必要がありますが、データをクエリする些細な例をノックアップしました...

INSERT INTO Customers VALUES ('Tom', '', '<PhoneNumbers><PhoneNumber Type="1" Value="01234 456789" /><PhoneNumber Type="2" Value="01746 482954" /></PhoneNumbers>')
INSERT INTO Customers VALUES ('Andy', '', '<PhoneNumbers><PhoneNumber Type="2" Value="07948 598348" /></PhoneNumbers>')
INSERT INTO Customers VALUES ('Mike', '', '<PhoneNumbers><PhoneNumber Type="3" Value="02875 482945" /></PhoneNumbers>')
INSERT INTO Customers VALUES ('Steve', '', '<PhoneNumbers></PhoneNumbers>')

今、私はそれをつかむ2つの方法を見ることができます。

方法1

DECLARE @PhoneType INT
SET  @PhoneType = 2

SELECT ct.*
FROM Customers ct
WHERE ct.PhoneNumbers.exist('/PhoneNumbers/PhoneNumber[@Type=sql:variable("@PhoneType")]') = 1

本当に? SQL:変数は少し不健康に感じます。ただし、機能します。ただし、より意味のある方法でデータにアクセスすることは明確に困難です。

方法2

SELECT ct.*, pt.PhoneType
FROM Customers ct
  CROSS APPLY ct.PhoneNumbers.nodes('/PhoneNumbers/PhoneNumber') AS nums(pn)
  INNER JOIN PhoneTypes pt ON pt.ID = nums.pn.value('./@Type[1]', 'int')
WHERE nums.pn.value('./@Type[1]', 'int') = @PhoneType

これはもっと似ています。すでに私は簡単にそれを拡張して参加して、他のすべての良いことをすることができます。私は使用しました CROSS APPLY テーブルの価値がある機能の上で、それはとても良かったです。前のクエリとは対照的に、これの実行計画は非常に高度です。確かに、私はこれらのテーブルでインデックスなどを行っていませんが、バッチ全体の97%です。

方法2(拡張)

SELECT ct.ID, ct.CustomerName, ct.Notes, pt.PhoneType
FROM Customers ct
  CROSS APPLY ct.PhoneNumbers.nodes('/PhoneNumbers/PhoneNumber') AS nums(pn)
  INNER JOIN PhoneTypes pt ON pt.ID = nums.pn.value('./@Type[1]', 'int')
WHERE nums.pn.value('./@Type[1]', 'int') IN (SELECT ID FROM PhoneTypes)

良い IN ここで条項。私もようなことができます pt.PhoneType = 'Work'

ついに

だから私は基本的に私が望む結果を取得していますが、このメカニズムを使用して少量のXMLデータを尋問する際に私が知っておくべきことはありますか?精巧な検索中にパフォーマンスに落ちますか?そして、そのようなマークアップスタイルのデータのストレージはオーバーヘッドの大きすぎますか?

サイドノート

私はようなものを使用しました sp_xml_preparedocumentOPENXML 過去には、リストをSprocsに渡すだけでしたが、これは比較して新鮮な空気の息吹のようなものです!

役に立ちましたか?

解決

XML列内に保存されている重要な情報のいくつかについて取ったアプローチの1つは、計算された「親」テーブルの永続的なプロパティとして「表面化」することです。これは、少し保存された機能を使用して行われます。

XMLが変更されるたびに値が1回だけ計算されるため、それはうまく機能します。変化しない限り、再計算がなく、値は他の列と同様にテーブルに保存されます。

また、インデックスを作成できるので素晴らしいです!したがって、そのようなフィールドで検索および/または参加している場合 - それは魅力のように機能します!

したがって、基本的には、これに沿って保存された関数が必要です。

CREATE FUNCTION [dbo].[GetPhoneNo1](@DataXML XML)
RETURNS VARCHAR(50)
WITH SCHEMABINDING
AS BEGIN
      DECLARE @result VARCHAR(20)

      SELECT 
        @result = @DataXML.value('(/PhoneNumbers/PhoneNumber[@Type="1"]/@Value)[1]', 'VARCHAR(50)')
      RETURN @result
END

タイプ1の電話番号がない場合は、ヌルを取り戻すだけです。

次に、計算された持続列を使用して親テーブルを拡張する必要があります。

ALTER TABLE dbo.Customers
   ADD PhoneNumberType1 AS dbo.GetPhoneNo1(PhoneNumbers)

ご覧のとおり、単一のエントリには正常に機能しますが、残念ながら、プロパティのリスト全体を表示することはできません。ただし、IDなどの重要なアイテムがある場合、行のほとんどが期待されることを期待している場合、これはその情報をより簡単かつ効率的に取得するための非常に素晴らしく滑らかな方法です。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top