现在的位置: 首页 > 综合 > 正文

SQL Server XML性能优化(Best Practices)

2013年07月11日 ⁄ 综合 ⁄ 共 3468字 ⁄ 字号 评论关闭

1. XML数据模型
XML存储与处理查询的性能取决于数据库的设计与XML数据的结构与粒度。是否要使用XML数据模型,看你

是不是有半结构化的数据,需要保留文档结构与层次结构的标记语言数据,或可变的结构。

1.1 标记 Markups
同样的数据可以以不同的方式来标记,视内容(element值)与元数据信息(attribute值)。越具体的

element名越易于阅读,且对生成有效的查询计划有帮助。冗长的标记会增加存储的成本。例如:
a.
<item type="book"><title>Writing Secure Code</title></item>
<item type="DVD"><title>The Godfather</title></item>
如果要查询book,需要写为:/item[@type = "book"]
b.
<book><title>Writing Secure Code</title></book>
<DVD><title>The Godfather</title></DVD>

如果要查询book,只需要写:/book ,这样效率更高也看起来更简单,而且减少了primary XML index(

主XML索引)的层数(少了item层)。这就是具体标记(Specific Markups)相对一般标记(Generic

Markups)的优点。

对于被类型化的的XML(typed XML),还可以缩减到两层:
<book title="Writing Secure Code"/>
<DVD title="The Godfather"/>

像<DVD><title>The Godfather</title></DVD>这种格式,称为element-centric markup,查询格式

为/DVD[title = "The Godfather"]
像<DVD title="The Godfather"/>这种格式,attribute-centric markup,查询格式为/DVD[@title =

"The Godfather"] ,可以减少一个JOIN。

1.2 Typed 和 Untyped XML(类型化与非类型化的XML)
非类型化的XML(untyped XML,没有以XML schema来表示)在SQL Server内部以Unicode字符串的形式存

储。对他们的操作需要数据转换到相应的类型。例如 (/book/price)[1] > 19.99,会有<price>转换为

decimal的过程。大量类似的比较就会非常耗资源,这就引出了XML schema中类型信息的重要性。
类型信息在以下几个方面起作用:
a. 插入更新的XML数据先被验证是否符合schema,然后以二进制形式存储,方便更快地转换
b. 类型化的值被存储在XML索引中
c. 类型化的数据还可以减少范围扫描,例如(/book/price)[1]中的序数[1]在XML schema规定了<price>

为单值时就是不必要的。

1.3 属性
可以使用UDF(用户自定义函数)来获得计算列(computed column)。可以在计算列上添加索引。由于计算列是预计算好的,查询速度更快。
范例:
书籍都有ISBN号,把ISBN单独作为计算列的过程如下
a. 定义获取ISBN号的函数
CREATE FUNCTION udf_get_book_ISBN (@xData xml) RETURNS varchar(20)
WITH SCHEMABINDING
BEGIN
   RETURN @xData.value('(/book/@ISBN)[1]', 'varchar(20)')
END
b. 添加计算列
CREATE TABLE docs (id int PRIMARY KEY, xCol XML)
ALTER TABLE docs ADD ISBN AS dbo.udf_get_book_ISBN(xCol)
c. 添加非聚类索引
CREATE INDEX COMPUTED_IDX ON docs (ISBN)
d. 写查询
如果不使用ISBN列,查询如下:
SELECT xCol
FROM   docs
WHERE  xCol.exist ('/book/@ISBN[. = "0-2016-3361-2"]') = 1
如果使用ISBN列
SELECT xCol
FROM   docs
WHERE  ISBN = '0-2016-3361-2'

还可以建立属性表(Property Table)

2. 批量载入XML数据
--可以使用BCP IN,BULK INSERT和OPENROWSET方法,因为和这次的case无关暂且略过。

3. XML索引
3.1 普通索引
推荐创建初级XML索引(primary XML index),实际上是创建了一个B+树。还可以对于PATH,PROPERTY,VALUE创建次级XML索引(secondary XML indexes)。
a. PATH索引
适用于有类似/book[@ISBN = "0-2016-3361-2"]的路径表达式,路径越长越有效
b. PROPERTY索引
适用于XML中的多properties查询
c. VALUE索引
适用于存在子轴(//操作符)和通配符(类似(/book[@* = "novel"]))的查询
维护索引的开销也是需要整体考虑的。

--关于XML部分更新和这次的case无关暂且略过。
--关于XML全文索引和这次的case无关暂且略过。

4. 查询优化
4.1 使用exist()方法来检测是否存在
尽可能使用exist()来代替value()
比如如下的查询:
SELECT *
FROM   docs
WHERE    xCol.exist('(/book/title/text())[.="Writing Secure Code"]') = 1

SELECT *
FROM   docs
WHERE  xCol.value('(/book/title)[1]', 'varchar(50)') = 'Writing Secure Code'

4.2 优化XML blobs(二进制XML)
更多的tempDB文件可以提供更好的可扩展性。
减少额外的XML数据类型转换

4.3 指定Singleton Elements(单件元素)
对于类型化的XML,默认是singleton的
非类型化的XML,需要加[1],xCol.query ('/book/title')会被自动转换为xCol.query ('(/book/title)[1]')。

4.4 对于非类型化的XML的text聚合
(/book/title[.="Writing Secure Code"])[1]需要聚合<title>下所有的text节点
如果<title> element只有一个text节点,那么可以使用(/book/title/text())[1][. = "Writing Secure Code"]更有效。

4.5 将XQuery和XML DML表达式参数化
XQuery和XML DML不会自动参数化,最好使用sql:column() 或sql:variable() 。

4.6 序数和预计的优化
减少语句的分支,如/book[@ISBN = "1-8610-0157-6"]/author/first-name,最好使用/book[author/first-name = "Davis"]这样的格式。
把序数移到路径的最后,/book[1]/title[1]等同于 (/book/title)[1]
使用Context Node(上下文节点)
如下的范例:
SELECT *
FROM   docs
WHERE  xCol.exist ('/book[@subject = "security"]') =  1
分别对/book和/book/@subject进行了评估,并检测了后者是否包含了值“security”
如果使用如下表达:
SELECT *
FROM   docs
WHERE  xCol.exist ('/book/@subject[. = "security"]') =  1
只会对/book/@subject 进行评估

动态查询与本次的case无关暂且略过。

具体案例等我做完这个case再详细阐述。

参考资料:
Performance Optimizations for the XML Data Type in SQL Server 2005
http://technet.microsoft.com/en-us/library/ms345118.aspx
XML Best Practices for Microsoft SQL Server 2005
http://technet.microsoft.com/en-us/library/ms345115.aspx

抱歉!评论已关闭.