Как повысить производительность Xpath в SQL Server при поиске элемента с определенным текстом - PullRequest
0 голосов
/ 23 марта 2012

Я должен удалить целые строки и часть 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 строк за раз, так что другие запросы могут обрабатываться между моими транзакциями. Общее количество строк для этого поставщика составляет около 5,5 миллионов, а общее количество строк в таблице - около 13 миллионов.

1 Ответ

0 голосов
/ 01 июня 2012

Раньше я не использовал xpath в SQL-сервере, но кое-что выделяется тем, что вы выполняете много операций чтения и записи в одной и той же команде (во втором выражении).Если возможно, измените ваши запросы на ..

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)

Это означает, что первый запрос только создаст новую временную таблицу, а не запишет ничего обратно, что займет немного больше времени, чем ваш оригинал, но ключДело в том, что ваш второй запрос будет только удалять записи, основанные на том, что находится в вашей временной таблице.

Вероятно, вы обнаружите, что он удаляет записи, постоянно перестраивает индексы и замедляет чтение.

Я бы также удалил / отключил все индексы /ограничения, которые на самом деле не помогают выполнить ваш запрос.

Кроме того, вы создаете свой кластерный первичный ключ по идентификатору, что не всегда является лучшим решением.Особенно, если вы выполняете много сканирований дат.

Можете ли вы также просмотреть примерный план выполнения для верхнего запроса, было бы интересно увидеть порядок, в котором он проверяет условия.Если он сначала делает дату, то это нормально, но если он делает xpath до того, как проверит дату, вам, возможно, придется разделить его на 3 запроса или добавить новый кластеризованный индекс для «proevedato, id».Это должно заставить запрос запускать xpath только для записей, которые действительно соответствуют дате.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...