It should be faster to use the native XML method .exist().
First create a mockup scenario to simulate your issue:
DECLARE @tbl TABLE(ID INT IDENTITY, SomeText VARCHAR(100),Properties XML);
INSERT INTO @tbl VALUES('John Doe exists'
,'<properties>
<property key="ActivityId" />
<property key="UserName">John Doe</property>
</properties>')
,('John Doe doesn''t exist'
,'<properties>
<property key="ActivityId" />
<property key="UserName">Someone else</property>
</properties>')
,('John Doe exists'
,'<properties>
<property key="ActivityId" />
<property key="UserName">John Doe</property>
</properties>');
--We can use variables to filter generically
DECLARE @SearchFor VARCHAR(100)='UserName';
DECLARE @FindThis VARCHAR(100)='John Doe';
--This is the query:
SELECT *
FROM @tbl t
WHERE t.Properties.exist('/properties/property[@key=sql:variable("@SearchFor") and text()[1]=sql:variable("@FindThis")]')=1;
The idea in short:
- We can use
.exist() directly in the WHERE clause.
- The WHERE is TRUE, when there is at least one hit at the given XPath
- The
=1 can be set to =0 in order to return the negative set
- The XPath uses a XQuery predicate to search for a
<property> with the given key and value.