查询在 xml 中搜索子字符串

IT *_*her 1 performance xml sql-server-2008-r2 xquery query-performance

我使用下面的查询来搜索整个 xml 中的子字符串(包括节点名称和节点值)

SELECT * 
FROM tablename
WHERE ( Charindex('abc',CAST([xmlcolumn] AS VARCHAR(MAX)))>0 ) 
Run Code Online (Sandbox Code Playgroud)

我想要一个性能比这更好的替代查询。所以请推荐一些。详情如下: 表:

CREATE TABLE [dbo].[tablename](
    [Sl_no] [int] NOT NULL,
    [Date] [date] NULL,
    [Operation] [nvarchar](max) NULL,
    [Allot] [nvarchar](50) NULL,
    **[xmlcolumn]** [xml] NULL,
    [By] [nvarchar](255) NULL,
    [Dept] [nvarchar](255) NULL,
    [Db] [varchar](255) NULL,
    [tabl] [varchar](255) NULL,
    [Remark] [varchar](5000) NULL,
    [Work] [int] NULL,
    [F2] [nvarchar](max) NULL,
    [F6] [nvarchar](max) NULL,
    [F5] [nvarchar](max) NULL,
    [F8] [nvarchar](max) NULL,
    [ListC] [nvarchar](255) NULL,
    [pro] [nvarchar](max) NULL,
    [Completed] [varchar](50) NULL,
    [WorkTime] [xml] NULL,
    [RelatedData] [varchar](255) NULL,
    [User] [xml] NULL,
    [TeBy] [xml] NULL,
    [Date1] [nvarchar](50) NULL,
    [Num1] [nvarchar](50) NULL,
 CONSTRAINT [PK_DBChanges] PRIMARY KEY CLUSTERED 
(
    [Sl_no] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)

行数:3000 列中的示例 xml:(节点数可能会略有变化。

<Root>
  <Row>
    <User>abs</User>
    <Rowid>1</Rowid>
  </Row>
  <Row>
    <User>xra</User>
    <Rowid>2</Rowid>
  </Row>
  <Maxrowid>2</Maxrowid>
</Root>
Run Code Online (Sandbox Code Playgroud)

预期搜索类型:在 xml 列“xmlcolumn”中搜索子字符串,然后返回包含该子字符串的完整行。

所以我使用的查询是

SELECT * 
FROM tablename
WHERE ( Charindex('abc',CAST([xmlcolumn] AS VARCHAR(MAX)))>0 ) 
Run Code Online (Sandbox Code Playgroud)

使用设置统计时间进行查询的IO

SQL Server Execution Times:
   CPU time = 62 ms,  elapsed time = 93 ms.
Run Code Online (Sandbox Code Playgroud)

我尝试了另一个查询(但它只会在节点值中搜索)

select *
from tablename
where xmlcolumn.exist('//*/text()[contains(., "abc")]') = 1
Run Code Online (Sandbox Code Playgroud)

统计输出为

 SQL Server Execution Times:
   CPU time = 63 ms,  elapsed time = 109 ms.
Run Code Online (Sandbox Code Playgroud)

Mik*_*son 5

要知道您将获得什么性能,您必须对数据进行测试。我显然不能这样做,所以我编写了自己的 xml 数据来测试您在这个问题中的两个查询。

创建一个包含 5000 行的表,其中包含 415 个节点、9475 个字符的 XML 文档:

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
Run Code Online (Sandbox Code Playgroud)

执行查询以搜索第一个节点 ( ) 中存在的值rpc和最后一个节点 ( ) 中存在的另一个值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
Run Code Online (Sandbox Code Playgroud)

不同查询的 IO 是相同的,因此这里是使用的输出set statistics time on

rpc使用 charindex搜索:

 SQL Server Execution Times:
   CPU time = 1435 ms,  elapsed time = 1434 ms.
Run Code Online (Sandbox Code Playgroud)

搜索rpcxml 存在

 SQL Server Execution Times:
   CPU time = 63 ms,  elapsed time = 68 ms.
Run Code Online (Sandbox Code Playgroud)

SERVER ROLE使用 charindex搜索

 SQL Server Execution Times:
   CPU time = 7316 ms,  elapsed time = 7321 ms.
Run Code Online (Sandbox Code Playgroud)

搜索SERVER ROLExml 存在

 SQL Server Execution Times:
   CPU time = 3245 ms,  elapsed time = 3244 ms.
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,XML 查询都是明显的赢家。它可以更好地扫描整个 XML,并且可以更好地在找到搜索字符串时提前终止。

对于上面使用 SQL Server 2012 的测试数据来说确实如此。您的数据和搜索字符串可能会有所不同。您必须进行测试才能知道什么最适合您。

注意:正如您的其他问题的答案中所述,上面的两个查询不会返回相同的结果,因为 XML 查询仅搜索节点值,而 charindex 查询搜索整个 XML 文档,包括节点名和标记。