SBB*_*SBB 4 sql-server-2008 sql-server stored-procedures t-sql execution-plan
我有一个用户界面,允许用户选择他们想要过滤结果的某些数据点。有位置、部门等内容。一旦他们选择了所有选项,我就会生成一个 XML 字符串,并将其传递给我的存储过程。
从那里,例如,对于位置,我创建了一个临时表并将用户选择的所有位置转储到该表中,然后我稍后加入我的数据。
在运行执行计划时,我注意到解析过滤器数据的 5 个左右的查询中的每一个都花费了大约 12%,这超过了查询的 60%,只是为了确定我们将要过滤的数据。
DECLARE @tmLocations TABLE (
location VARCHAR (100));
BEGIN
INSERT INTO @tmLocations
SELECT ParamValues.x1.value('location[1]', 'VARCHAR(200)')
FROM @xml.nodes('data/teammateLocations/locations') AS ParamValues(x1);
END
Run Code Online (Sandbox Code Playgroud)
是否有另一种从 XML 中提取数据的方法或改进上述查询的方法,以便运行成本不高?设置数据比实际过滤数据的成本更高,这确实会降低性能。
在运行执行计划时,我注意到解析过滤器数据的 5 个左右的查询中的每一个都花费了大约 12%,这超过了查询的 60%,只是为了确定我们将要过滤的数据。
即使在实际执行计划中,查询成本也是基于估计的。他们不会告诉您查询的实际效率如何。
估计反过来又基于统计数据,这些可能会过时,为您提供错误的估计和成本。
XML 查询的估计总是错误的。没有为 XML 列生成统计信息,当然也没有为 XML 参数或变量生成统计信息。
看看这个相当简单的 XML 查询。
declare @X xml;
select 1
from @X.nodes('*') as T(X);
Run Code Online (Sandbox Code Playgroud)
估计的查询计划
SQL Server 假设 XML 中有 10000 个元素,并不断从那里猜测。使用该nodes()
函数假定将返回其中的 200 个。在此之前,有一个 Filter 运算符,用于检查是否@X is not null
将估计行数限制为 66。纯猜测,完全不受 XML 中实际数据的影响。
要知道查询是否足够好,您应该查看持续时间、读取次数和分配的内存等内容。不要使用估计成本,也不要使用单个查询的百分比来比较性能。
您可以按照 Magoo 先生在评论中的建议改进 XML 查询。
SELECT ParamValues.x1.value('(location/text())[1]', 'VARCHAR(200)')
FROM @xml.nodes('data/teammateLocations/locations') AS ParamValues(x1);
Run Code Online (Sandbox Code Playgroud)
如果不指定text()
节点,SQL Server 必须生成一个使用混合内容 XML 的计划,连接子节点中的所有节点值。