我应该根据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万。
答案 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。
希望这有帮助。