背景
最近,我开始更多地使用 XML 作为 SQL Server 2005 中的列。在昨天的一段时间停机期间,我注意到我使用的两个链接表真的很碍事,不得不让我无聊到流泪为几个连接编写更多支持结构代码。
为了实际为这两个链接表生成数据,我将两个 XML 字段传递给我的存储过程,它写入主记录,将两个 XML 变量分解为 @tables 并将它们插入到实际表SCOPE_IDENTITY()
中记录。
不过,经过一段时间后,我决定完全取消这些表,并将 XML 存储在 XML 字段中。现在我知道这里有一些缺陷,比如一般查询性能,GROUP BY
不适用于 XML 数据。查询通常有点混乱,但总的来说,我喜欢XElement
当我取回数据时现在可以使用它。
而且,这些东西不会改变。这是一次性事件,所以我不必担心修改。
我想知道实际获取这些数据的最佳方法。我的很多查询都涉及根据子记录甚至子记录的标准获取主记录。数据库中的大多数存储过程都这样做,但规模要复杂得多,通常需要 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>')
现在我可以看到两种抓取方式。
方法一
DECLARE @PhoneType INT
SET @PhoneType = 2
SELECT ct.*
FROM Customers ct
WHERE ct.PhoneNumbers.exist('/PhoneNumbers/PhoneNumber[@Type=sql:variable("@PhoneType")]') = 1
真的吗?sql:variable 感觉有点不健康。但是,它确实有效。然而,以更有意义的方式访问数据显然更加困难。
方法二
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_preparedocument
,OPENXML
只是将列表传递给存储过程,但相比之下,这就像呼吸新鲜空气!