查找xml列未使用的行

时间:2016-08-19 09:33:57

标签: sql sql-server xml tsql query-optimization

我有一个status表,我必须找到未使用的状态 状态代码可以在活动模板中使用,活动模板具有带有自定义公式的actionlist xml列。

到目前为止,我已经写过这个有效,但速度非常慢(超过一分钟就能获得5000行),我需要加快速度。

select *
from [status] s
where not exists (
    select top 1 1
    from Wf_ActivityTemplate at
    where at.actionlist.value('.', 'nvarchar(max)') like '%@GetStatusId("' + s.code + '")%'
)

actionlist列看起来像这样(删除了不相关的节点) 如您所见,我需要在//ActionTriplet/Argument节点中搜索,该节点本身是存储在文本中的xml节点。

<ArrayOfActionTriplet xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <ActionTriplet>
    <Priority>1</Priority>
    <Argument>&lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;&lt;string&gt;@SetProp("STATUS",@GetStatusId("INTERNAL DESIGN REVIEW"));True&lt;/string&gt;</Argument>
    <ActionCode>APPLY_FORMULA</ActionCode>
    <TriggerTaskCode />
    <TriggerTaskIsSecondary>false</TriggerTaskIsSecondary>
    <TriggerTaskConditionFormula />
  </ActionTriplet>
  <ActionTriplet>
    <Priority>2</Priority>
    <Argument>&lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;&lt;string&gt;@SetProp("STATUS",@GetStatusId("VALID"));True&lt;/string&gt;</Argument>
    <ActionCode>APPLY_FORMULA</ActionCode>
    <TriggerTaskCode />
    <TriggerTaskIsSecondary>false</TriggerTaskIsSecondary>
    <TriggerTaskConditionFormula />
  </ActionTriplet>
</ArrayOfActionTriplet>

1 个答案:

答案 0 :(得分:2)

您的代码正在获取XML的全部内容,将其转换为nvarchar并执行%x%-like-search,这总是很慢。文字越大,越慢......

为了展示另一种方法,我宣布一个表变量,它用两行来模拟你的表(参见ID)。我搜索@YourCode中给出的代码:

DECLARE @YourCode NVARCHAR(100)=N'INTERNAL DESIGN REVIEW';

DECLARE @YourTable TABLE(ID INT IDENTITY, actionList XML);
INSERT INTO @YourTable(actionList) VALUES(
'<ArrayOfActionTriplet xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <ActionTriplet>
    <Priority>1</Priority>
    <Argument>&lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;&lt;string&gt;@SetProp("STATUS",@GetStatusId("INTERNAL DESIGN REVIEW"));True&lt;/string&gt;</Argument>
    <ActionCode>APPLY_FORMULA</ActionCode>
    <TriggerTaskCode />
    <TriggerTaskIsSecondary>false</TriggerTaskIsSecondary>
    <TriggerTaskConditionFormula />
  </ActionTriplet>
  <ActionTriplet>
    <Priority>2</Priority>
    <Argument>&lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;&lt;string&gt;@SetProp("STATUS",@GetStatusId("VALID"));True&lt;/string&gt;</Argument>
    <ActionCode>APPLY_FORMULA</ActionCode>
    <TriggerTaskCode />
    <TriggerTaskIsSecondary>false</TriggerTaskIsSecondary>
    <TriggerTaskConditionFormula />
  </ActionTriplet>
</ArrayOfActionTriplet>')
,(
'<ArrayOfActionTriplet xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <ActionTriplet>
    <Priority>1</Priority>
    <Argument>&lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;&lt;string&gt;@SetProp("STATUS",@GetStatusId("INTERNAL DESIGN REVIEW"));True&lt;/string&gt;</Argument>
    <ActionCode>APPLY_FORMULA</ActionCode>
    <TriggerTaskCode />
    <TriggerTaskIsSecondary>false</TriggerTaskIsSecondary>
    <TriggerTaskConditionFormula />
  </ActionTriplet>
  <ActionTriplet>
    <Priority>2</Priority>
    <Argument>&lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;&lt;string&gt;@SetProp("STATUS",@GetStatusId("VALID"));True&lt;/string&gt;</Argument>
    <ActionCode>APPLY_FORMULA</ActionCode>
    <TriggerTaskCode />
    <TriggerTaskIsSecondary>false</TriggerTaskIsSecondary>
    <TriggerTaskConditionFormula />
  </ActionTriplet>
</ArrayOfActionTriplet>');

- 这是查询:您将返回所有Argument - 元素,此元素中的文字包含GetStatusId("TheCode")

SELECT s.ID
      ,arg.query('.')
FROM @YourTable AS s
CROSS APPLY actionList.nodes('/*:ArrayOfActionTriplet/*:ActionTriplet/*:Argument[fn:contains(.,fn:concat("GetStatusId(&quot;",sql:variable("@YourCode"),"&quot;)"))]') AS A(arg)

更新

使用此查询,您可以将内部XML从编码形式转换为实际XML并获取完整的字符串可读:

SELECT s.ID
      ,arg.query('.')
      ,InnerXml.value('string[1]','nvarchar(max)')
FROM @YourTable AS s
CROSS APPLY actionList.nodes('/*:ArrayOfActionTriplet/*:ActionTriplet/*:Argument[fn:contains(.,fn:concat("GetStatusId(&quot;",sql:variable("@YourCode"),"&quot;)"))]') AS A(arg)
CROSS APPLY (SELECT CAST(arg.value('.','varchar(max)') AS XML)) AS Casted(InnerXml)

更新2:更快,仅检查存在

如果你想要的不仅仅是检查,还是有<Argument>包含你的代码,你可能会这样做:

SELECT s.ID
FROM @YourTable AS s
WHERE actionList.exist('/*:ArrayOfActionTriplet/*:ActionTriplet/*:Argument[fn:contains(.,fn:concat("GetStatusId(&quot;",sql:variable("@YourCode"),"&quot;)"))]') =1

最终=1表示:字符串包含在内。使用=0,您将获得所有行,其中不包含此字符串