You have not specified the length of @id
. Using only varchar
will in this case give you a length of one so the content of @id
will be x
.
Your first query checks for nodes that contain x
and that matches all rows. The second query checks for nodes that has x
as value and no row has that.
Change the declaration of @id
to DECLARE @id varchar(3)
and everything will work as expected.
To know what performance you will have you have to test on your data. I obviously can't do that so I made up my own xml data to test the two queries you have in this question.
Create a table with 5000 rows containing an XML document of 9475 characters in 415 nodes:
create table T
(
ID int identity primary key,
XMLCol xml not null
)
declare @X xml =
(
select top 100 *
from master..spt_values
for xml path('row'), root('root'), type
)
insert into T(XMLCol)
select top(5000) @X
from master..spt_values as m1, master..spt_values as m2
Execute the queries to search for a value that is present in the first node (rpc
) and another value that is present in the last node (SERVER ROLE
).
select count(*)
from T
where charindex('rpc',cast(xmlcol as varchar(max))) > 0
select count(*)
from T
where XMLCol.exist('//*/text()[contains(., "rpc")]') = 1
select count(*)
from T
where charindex('SERVER ROLE',cast(xmlcol as varchar(max))) > 0
select count(*)
from T
where XMLCol.exist('//*/text()[contains(., "SERVER ROLE")]') = 1
The IO for the different queries is the same so here is the output from using set statistics time on
Search for rpc
with charindex:
SQL Server Execution Times:
CPU time = 1435 ms, elapsed time = 1434 ms.
Search for rpc
with xml exist
SQL Server Execution Times:
CPU time = 63 ms, elapsed time = 68 ms.
Search for SERVER ROLE
with charindex
SQL Server Execution Times:
CPU time = 7316 ms, elapsed time = 7321 ms.
Search for SERVER ROLE
with xml exist
SQL Server Execution Times:
CPU time = 3245 ms, elapsed time = 3244 ms.
Clear winner in both cases is the XML query. It does a better job of scanning the entire XML and it does a much better job of early termination when the search string is found.
This is true for the test data above using SQL Server 2012. It could be different for you with your data and your search strings. You have to test to know what is best for you.
NOTE: As stated in the answer to your other question, the two queries above will not return the same result bucause the XML query only search node values where the charindex query searches the entire XML document including nodenames and markup.
Best Answer
The exist() Method (xml Data Type) returns a
bit
.1
if at least one node is found and0
if no nodes are found (empty result set).To get the rows where neither
ABC
orXYZ
exist you just have to compare the result ofexist
with0
.Your FLWOR query can be rewritten using a predicate on the user node instead,
And for the
IN
version of the query you check ifexist
returns1
instead.