带有不区分大小写标记的 XML 查询 - 这是最好的查询

IT *_*her 2 xml sql-server sql-server-2008-r2 xquery

我之前问过有关不区分大小写标记的 XML 查询的问题,我也找到了解决方案。但我也找到了一些其他的解决方案。所以桌子就像

DECLARE @myTable TABLE ( yourXML XML )  

INSERT INTO @myTable SELECT '<z><a><b>1</b><c>2</c></a></z>'
INSERT INTO @myTable SELECT '<Z><A><b>1</b><c>2</c></A></Z>' 
Run Code Online (Sandbox Code Playgroud)

以下所有解决方案都返回我想要的(不区分大小写的标签)

-----Solution 1----------

SELECT * FROM @myTable WHERE ( [yourXML].exist('for $x in /*[lower-case(local-name(.)) = "z"]/*[lower-case(local-name(.)) = "a"] where  ( ($x/*[lower-case(local-name(.)) = "b"][1]) = 1 )  return $x')>0 ) 

-------------------------
-----Solution 2----------

SELECT * FROM @myTable
WHERE
(CONVERT(XML,LOWER(CONVERT(VARCHAR(MAX),[yourXML]))).exist('for $x in /z/a where  ( ($x/b[1]) = 1 )  return $x')>0 )

-------------------------
-----Solution 3----------

SELECT * FROM @myTable WHERE 
([yourXML].exist('for $x in (/Z/A,/z/a) where  ( ($x/b[1],$x/B[1]) = 1 )  return $x') > 0 ) 
-------------------------
Run Code Online (Sandbox Code Playgroud)

现在我想通过考虑它的所有 X-query 命令(支持 value()、exist()、count()、query() 等)、性能、效率等来知道哪个更好用。

Mik*_*son 5

您可以轻松地自己测试性能。

创建一个常规表,您可以在其上测试您的查询。

create table myTable ( yourXML XML )  
Run Code Online (Sandbox Code Playgroud)

添加几行可以匹配。

INSERT INTO myTable SELECT '<z><a><b>1</b><c>2</c></a></z>'
INSERT INTO myTable SELECT '<Z><A><b>1</b><c>2</c></A></Z>' 
INSERT INTO myTable SELECT '<Z><A><B>1</B><c>2</c></A></Z>' 
Run Code Online (Sandbox Code Playgroud)

添加一大堆在 XML 的不同部分不匹配的行。

insert into myTable 
select top(10000) '<X><A><B>1</B><c>2</c></A></X>'
from sys.all_objects as o1, sys.all_objects as o2

insert into myTable 
select top(10000) '<Z><X><B>1</B><c>2</c></X></Z>'
from sys.all_objects as o1, sys.all_objects as o2

insert into myTable 
select top(10000) '<Z><A><X>1</X><c>2</c></A></Z>'
from sys.all_objects as o1, sys.all_objects as o2
Run Code Online (Sandbox Code Playgroud)

使用SET STATISTICS IO (Transact-SQL)SET STATISTICS TIME (Transact-SQL)并在 SQL Server Management Studio 中执行查询。

set statistics time on
set statistics io on

-----Solution 1----------

SELECT * FROM myTable WHERE ( [yourXML].exist('for $x in /*[lower-case(local-name(.)) = "z"]/*[lower-case(local-name(.)) = "a"] where  ( ($x/*[lower-case(local-name(.)) = "b"][1]) = 1 )  return $x')>0 ) 

-------------------------
-----Solution 2----------

SELECT * FROM myTable
WHERE
(CONVERT(XML,LOWER(CONVERT(VARCHAR(MAX),[yourXML]))).exist('for $x in /z/a where  ( ($x/b[1]) = 1 )  return $x')>0 )

-------------------------
-----Solution 3----------

SELECT * FROM myTable WHERE 
([yourXML].exist('for $x in (/Z/A,/z/a) where  ( ($x/b[1],$x/B[1]) = 1 )  return $x') > 0 ) 

-------------------------
-----Solution 4----------

select *
from myTable
where yourXML.exist('(Z/A,z/a)[(b,B)=1]') = 1
Run Code Online (Sandbox Code Playgroud)

切换到消息选项卡并评估执行时间和所需的读取。

据推测,您的数据库中有更好的数据可供测试。性能特征将根据您在现实世界中必须处理的 XML的实际结构而变化。

附带说明是,您的查询是不等价的。
第一个很容易适应更长的元素名称。
第二个查询更改元素的内容,而不仅仅是元素名称。
第三个查询并没有真正处理不区分大小写的元素名称,它只是枚举所有可能的元素名称,在这种情况下,这些元素名称仅在案例中有所不同。如果你想用你的第三个解决方案来处理一个 3 个字母的元素名称,你将有 8 个(我认为)不同的排列来处理。

我添加了第四个解决方案,主要是因为它简短漂亮,与您的第三个解决方案具有相同的局限性。在我的测量中,它比使用 FLWOR 略快。