Tath SQL查询中的XPath

时间:2012-09-28 12:35:55

标签: sql-server xml tsql xpath sqlxml

我有两个表,XMLtablefilterTable

我需要来自XMLtable.ID的所有XMLtable值,其中Col_X中的数据包含MyElement,其内容与filterColumn中的filterTable相匹配}。

Col_X中每行的XML可能包含多个MyElement,如果这些元素中的任何一个与{{1}中的任何值匹配,我希望ID }。

问题是这些列实际上是filterColumn数据类型,并且表本身很大(如50GB巨大)。因此,此查询需要尽可能优化。

以下是我现在所处位置的示例,它仅返回第一个匹配元素等于我正在查找的行之一的行。由于过多的不同错误消息,我似乎无法将其更改为与我想要的所有相同的命名元素进行比较。

varchar(max)

...然后将结果与SELECT ID, CAST(Col_X AS XML).value('(//*[local-name()=''MyElement''])', N'varchar(25)') FROM XMLtable 进行比较。这已经花了5多分钟。

我想要达到的目标是:

filterTable

我目前唯一可以实现此目的的方法是使用LIKE运算符,这需要花费一千倍的时间。

现在,显然不能选择开始更改列的数据类型或其他任何内容。这是我必须要合作的。 :)

3 个答案:

答案 0 :(得分:3)

试试这个:

SELECT
  ID,
  MyElementValue
FROM 
  (
    SELECT ID, myE.value('(./text())[1]', N'VARCHAR(25)') AS 'MyElementValue'
    FROM XMLTable
      CROSS APPLY (SELECT CAST(Col_X AS XML)) as X(Col_X)
      CROSS APPLY X.Col_X.nodes('(//*[local-name()="MyElement"])') as T2(myE)
  ) T1
WHERE MyElementValue IN (SELECT filterColumn FROM filterTable)

和此:

SELECT
  ID,
  MyElementValue
FROM 
  (
    SELECT ID, myE.value('(./text())[1]', N'VARCHAR(25)') AS 'MyElementValue'
    FROM XMLTable
      CROSS APPLY (SELECT CAST(Col_X AS XML)) as X(Col_X)
      CROSS APPLY X.Col_X.nodes('//MyElement') as T2(myE)
  ) T1
WHERE MyElementValue IN (SELECT filterColumn FROM filterTable)

<强>更新

我认为你正在体验这里所描述的内容Compute Scalars, Expressions and Execution Plan Performance。转换为XML将延迟到对value函数的每次调用。您应该进行的测试是将Col_X的数据类型更改为XML

如果这不是一个选项,您可以从XMLTable查询所需的行到具有XML列的临时表中,然后针对临时表执行上述查询,而无需转换为XML。

CREATE TABLE #XMLTable
(
  ID int,
  Col_X xml
)

INSERT INTO #XMLTable(ID, Col_X)
SELECT ID, Col_X
FROM XMLTable

SELECT
      ID,
      MyElementValue
    FROM 
      (
        SELECT ID, myE.value('(./text())[1]', N'varchar(25)') AS 'MyElementValue'
        FROM #XMLTable
          CROSS APPLY Col_X.nodes('//MyElement') as T2(myE)
      ) T1
    WHERE MyElementValue IN (SELECT filterColumn FROM filterTable)


DROP TABLE #XMLTable

答案 1 :(得分:1)

你可以尝试这样的事情。我相信它至少在功能上做你想做的事。您必须根据经验探索其数据集的性能。

SELECT ID
FROM 
( 
   SELECT xt.ID, CAST(xt.Col_X AS XML) [content] FROM XMLTable AS xt
) AS src
INNER JOIN FilterTable AS f
ON f.filterColumn IN 
(
   SELECT 
      elt.value('.', 'varchar(25)')     
   FROM src.content.nodes('//MyElement') AS T(elt)
)

答案 2 :(得分:0)

我终于有了这个工作,并且性能远远超出我的预期。下面是最终在5-6分钟内产生正确结果的脚本。

SELECT ID, myE.value('.', N'VARCHAR(25)') AS 'MyElementValue'
FROM (SELECT ID, CAST(Col_X AS XML) AS Col_X
    FROM XMLTable) T1
CROSS APPLY Col_X.nodes('(//*[local-name()=''MyElement''])' T2(myE)
WHERE myE.value('.', N'varchar(25)') IN (SELECT filterColumn FROM filterTable)

感谢大家的帮助!