如何在搜索具有特定文本的元素时加快SQL Server中的Xpath性能

时间:2012-03-23 15:09:06

标签: sql-server performance xpath

我应该根据XML列中的特定值从具有XML列的表中删除整个行和部分XML文档。但是,该表包含数百万行,并在执行操作时被锁定。目前,它需要将近一周的时间来清理它,系统太过关键,不能长时间离线。

是否有任何方法可以优化此脚本中的xpath表达式:

declare @slutdato datetime = '2012-03-01 00:00:00.000'
declare @startdato datetime = '2000-02-01 00:00:00.000'
declare @lev varchar(20) = 'suppliername'
declare @todelete varchar(10) = '~~~~~~~~~~'

CREATE TABLE #ids (selId int NOT NULL PRIMARY KEY)
INSERT into #ids
select id from dbo.proevesvar
WHERE leverandoer = @lev
and proevedato <= @slutdato
and proevedato >= @startdato


begin transaction  /* delete whole rows */
delete from dbo.proevesvar
where id in (select selId from #ids)
and ProeveSvarXml.exist('/LaboratoryReport/LaboratoryResults/Result[Value=sql:variable(''@todelete'')]') = 1
and Proevesvarxml.exist('/LaboratoryReport/LaboratoryResults/Result[Value!=sql:variable(''@todelete'')]') = 0

commit
go

begin transaction /* delete single results */
UPDATE dbo.proevesvar SET ProeveSvarXml.modify('delete /LaboratoryReport/LaboratoryResults/Result[Value=sql:variable(''@todelete'')]')
where id in (select selId from #ids)
commit
go

表定义是:

CREATE TABLE [dbo].[ProeveSvar](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [CPRnr] [nchar](10) NOT NULL,
    [ProeveDato] [datetime] NOT NULL,
    [ProeveSvarXml] [xml] NOT NULL,
    [Leverandoer] [nvarchar](50) NOT NULL,
    [Proevenr] [nvarchar](50) NOT NULL,
    [Lokationsnr] [nchar](13) NOT NULL,
    [Modtaget] [datetime] NOT NULL,
    CONSTRAINT [PK_ProeveSvar] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY],
 CONSTRAINT [IX_ProeveSvar_1] UNIQUE NONCLUSTERED 
(
    [CPRnr] ASC,
    [Lokationsnr] ASC,
    [Proevenr] ASC,
    [ProeveDato] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

第一个插入语句非常快。我相信我可以通过一次提交50行来处理锁定,因此可以在我的事务之间处理其他请求。 该供应商的总行数约为550万,表中的总行数约为1300万。

1 个答案:

答案 0 :(得分:0)

我以前没有在SQL服务器中真正使用过xpath,但突出的是你在同一个命令中进行了大量的读写操作(在第二个语句中)。如果可能,请将您的查询更改为..

CREATE TABLE #ids (selId int NOT NULL PRIMARY KEY)
INSERT into #ids
select id from dbo.proevesvar
WHERE leverandoer = @lev
and proevedato <= @slutdato
and proevedato >= @startdato
and ProeveSvarXml.exist('/LaboratoryReport/LaboratoryResults/Result[Value=sql:variable(''@todelete'')]') = 1
and Proevesvarxml.exist('/LaboratoryReport/LaboratoryResults/Result[Value!=sql:variable(''@todelete'')]') = 0


begin transaction  /* delete whole rows */
delete from dbo.proevesvar
where id in (select selId from #ids)

这意味着第一个查询只会创建新的临时表,而不会写回任何内容,这将比原始查询略长,但关键是你的第二个查询只会根据内容删除记录。你的临时表。

你可能会发现它是因为它正在删除记录,它会不断地重建索引,并导致读取速度变慢。

我还会删除/禁用任何实际上无法帮助您运行查询的索引/约束。

此外,您正在ID上创建群集主键,这并不总是最好的事情。特别是如果你正在进行大量的日期扫描。

您是否还可以查看最高查询的估计执行计划,看看它检查条件的顺序会很有趣。如果它首先执行日期,那么这很好,但如果它在检查日期之前正在执行xpath,则可能必须将其分为3个查询,或者在'proevedato,id'上添加新的聚簇索引。这应该强制查询只运行实际匹配日期的记录的xpath。

希望这有帮助。