【发布时间】:2011-05-22 19:20:25
【问题描述】:
背景
最近我开始更多地使用 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 之类的东西来将列表传递到存储过程中,但相比之下,这就像呼吸新鲜空气!
【问题讨论】:
标签: sql-server sql-execution-plan cross-apply xml-column