Обновление SQL очень медленное (около 20-50 секунд), выбор занимает менее 1 секунды

У меня есть SQL Tab "Документ", который содержит много строк (до нескольких миллионов).

Когда я выполняю оператор Select, это занимает около 0,5 секунды. Но когда я выполняю обновление с тем же предложением WHERE, это занимает от 20 до 50 секунд, в зависимости от количества затронутых строк.

Вот мои выписки.

//Выбирать

SELECT * FROM Document 
WHERE (State=20 OR State=23) AND 
LetterClosed IS NOT NULL AND 
TYPE=0 AND
SendLetter=1

//Обновлять

UPDATE Document set State=32 
WHERE (State=20 OR State=23) AND 
LetterClosed IS NOT NULL AND 
TYPE=0 AND
SendLetter=1

OR-Mapper внутренне отправляет этот оператор обновления в базу данных следующим образом:

exec sp_executesql N'Update
Document
SET
    State=@p4
WHERE
(
  (
    (
      (Document.State = @p0 OR Document.State = @p1) 
      AND Document.LetterClosed IS NOT NULL
    ) 
    AND Document.Type = @p2
  ) 
  AND Document.SendLetter = @p3
)'
,N'@p0 int,@p1 int,@p2 int,@p3 bit,@p4 int',@p0=20,@p1=23,@p2=0,@p3=1,@p4=32

Проблема в том, что я получаю исключение Timeout-Exception через 30 секунд от моего LightSpeed ​​(база данных OR-Mapper в С#).

Может ли кто-нибудь помочь мне здесь?

Редактировать:

А это наши индексы, автоматически созданные SQL-сервером:

CREATE NONCLUSTERED INDEX [_dta_index_Document_9_133575514__K42_1_2_3_4_5_6_7_8_9_11_12_13_14_15_16_17_18_19_20_21_22_23_24_25_26_27_28_29_30_31_32_33_34_] ON [Document] 

(
    [State] ASC
)
INCLUDE ( 
[Id],[DocumentId],[SendLetter],[SendFax],[Archive],[Crm],[Validation],[CreationDate],[PageCount],
[InformationLetter],[TermsOfDelivery],[DeliveryTypeNo],[SeparateDelivery],[FormName],[FormDescription],[TemplateFileName],[RecipientType],
[HealthInsuranceNo],[FamilyHealthInsuranceNo],[PensionInsuranceNo],[EmployerCompanyNo],[RecipientName1],[RecipientName2],[RecipientName3],
[RecipientStreet],[RecipientCountryCode],[RecipientZipCode],[RecipientCity],[RecipientFaxNo],[AuthorId],
[AuthorName],[AuthorEmailAddress],[CostcenterDepartment],[CostcenterDescription],[MandatorNo],[MandatorName],[ControllerId],
[ControllerName],[EditorId],[EditorName],[StateFax],[Editable],[LetterClosedDate],[JobId],[DeliveryId],[DocumentIdExternal],[JobGroupIdExternal],
[GcosyInformed]) WITH (SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]
go

CREATE NONCLUSTERED INDEX [_dta_index_Document_9_133575514__K2_1_46] ON [Document] 
(
    [DocumentId] ASC
)
INCLUDE ( [Id],
[JobId]) WITH (SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]
go

CREATE NONCLUSTERED INDEX [_dta_index_Document_9_133575514__K46_K2] ON [Document] 
(
    [JobId] ASC,
    [DocumentId] ASC
)WITH (SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]
go



CREATE NONCLUSTERED INDEX [Document_State_Id] ON [Document] 
(
    [State] ASC,
    [Id] ASC
)WITH (SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]
go

CREATE NONCLUSTERED INDEX [Document_State_CreationDate] ON [Document] 
(
    [State] ASC,
    [CreationDate] ASC
)WITH (SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]
go

Изменить 2. Теперь у меня есть графический план выполнения: План выполнения: https://skydrive.live.com/redir?resid=597F6CF1AB696567!444&authkey=!ABq72SAWXOoAXfI

Сведения об обновлении указателя плана выполнения: https://skydrive.live.com/?cid=597f6cf1ab696567&id=597F6CF1AB696567%21445&sff=1&authkey=!ADDPWvxB2JLLvWo

Выполнение этого обновления SQL заняло около 35 секунд. Обычно это обновление занимает всего 0,3 секунды. Кажется, что другой процесс заблокировал этот. Я видел некоторые другие выборки, которые начались в середине этого обновления, и ждал, пока обновление не будет завершено, пока они не завершили выполнение выбора.

Таким образом, кажется, что сам индекс правильный (обычно выполнение 0,3 секунды). Все выборки (из java/jtds, php, .net) являются зафиксированными на уровне изоляции (по умолчанию). Поможет ли мне здесь изменить все выборки для чтения незафиксированных, чтобы избежать этой блокировки во время обновления индекса?

Спасибо, Тоби.


person Tobias Koller    schedule 11.01.2013    source источник
comment
Сколько строк возвращает SELECT? Какую СУБД вы используете? (Я предполагаю, что SQL-сервер из sp_executesql) Можете ли вы показать оператор CREATE TABLE (и существующие индексы)? Можете ли вы добавить план выполнения?   -  person ypercubeᵀᴹ    schedule 11.01.2013
comment
Мы используем MSSQL-Server 2005. Я постараюсь опубликовать план выполнения и отчет о создании.   -  person Tobias Koller    schedule 11.01.2013
comment
Также включите любые индексы в эту таблицу, вам нужно сделать это, чтобы получить точный ответ, это будет либо слишком много индексов, либо слишком мало, или вам просто нужно немного изменить один. Когда вы получаете план выполнения в SSMS, он может даже предложить индекс, который ускорит его.   -  person Chris Diver    schedule 11.01.2013
comment
У вас одинаковое время выполнения, если вы запускаете запросы из своего приложения и из SSMS?   -  person Grzegorz Gierlik    schedule 11.01.2013
comment
Обычно люди прикрепляют скриншот с планом, но для больших планов это не сработает.   -  person Grzegorz Gierlik    schedule 11.01.2013
comment
смотрите мои ссылки выше. они указывают на скриншоты моего плана выполнения.   -  person Tobias Koller    schedule 12.02.2013


Ответы (3)


У меня была эта проблема однажды на связанных серверах SQL Server 2008 и SQL Server 2014. Обходной путь для меня заключался в том, чтобы сохранить результаты «Выбрать» во временной таблице и использовать ее для обновления, а не выполнять сложные запросы и обновление одновременно.

В вашем случае это будет:

--Select

SELECT * FROM Document
into #temp 
WHERE (State=20 OR State=23) AND 
LetterClosed IS NOT NULL AND 
TYPE=0 AND
SendLetter=1

--Update

UPDATE Document set State=32 
from #temp
WHERE #temp.id = Document.id 
--assuming that id is your PK
person nbougiou    schedule 23.01.2018
comment
Это сработало и для меня. Я не знаю, почему? Может ли кто-нибудь пролить свет на это поведение? - person Ashish Kumar Jaryal; 08.09.2020

Без плана выполнения мы можем только догадываться, что происходит.

Я бы начал с:

  1. Проверьте, сколько индексов у таблицы document (но трудно поверить, что обновление индексов занимает столько времени).
  2. Проверьте, выполняются ли какие-либо триггеры при обновлении.

Все это должно быть видно на плане выполнения.

Другая причина может заключаться в том, что механизм SQL имеет один план выполнения для запроса SELECT и другой план для запроса UPDATE...

ОБНОВИТЬ

После изучения индексов.

На мой взгляд, индекс _dta_index_Documentstate133575514__K42_1_2_3_4CLUSTERED6CLUSTERED8state11_12_13_14_15_16_17_18_19_20_21_22_23_24_25_26_27_28_29_30_31_32_33_34_ совершенно неверен.

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

Попробуйте удалить его или заменить индексом CLUSTERED в столбце state. CLUSTERED index* include* (имеет прямой доступ) ко всем столбцам записи без дополнительных чтений.

Вероятно, его следует объединить с одним из других индексов, начинающихся со столбца state — я предполагаю, что state имеет всего несколько значений.

К сожалению, я не могу интерпретировать план выполнения в текстовом формате.

person Grzegorz Gierlik    schedule 11.01.2013

Возможно у вас есть индексы на таблицу Document. Индексы ускоряют выбор, но замедляют операции обновления/вставки/удаления.

Попробуйте удалить ненужные индексы.

person semao    schedule 11.01.2013
comment
Возможно, но нужно обновить только один индекс (State; если он вообще проиндексирован).. - person ; 11.01.2013
comment
Вероятно, это вызвано отсутствием индексов, а не их наличием. - person ypercubeᵀᴹ; 11.01.2013
comment
Когда я создал таблицу, я провел несколько тестов, зарегистрировал каждый оператор с помощью профилировщика и использовал SQLServer DatabaseOptimizer для создания своих индексов. - person Tobias Koller; 11.01.2013
comment
@pst почему только один индекс? Вы предполагаете, что существуют только индексы с одним столбцом? Что, если State является частью многих индексов? Без плана мы не знаем, но я не думаю, что вы можете утверждать, что это повлияет только на один индекс. - person Aaron Bertrand; 11.01.2013
comment
привет Аарон. Я уже разместил XML-Executionplan. Может быть, вы можете взглянуть на него? его графический и должен быть легче читать. вот снова ссылка: Редактировать 2: Теперь у меня есть графический план выполнения: План выполнения: ссылка Детали обновления указателя плана выполнения: ссылка - person Tobias Koller; 12.02.2013