#sql-server #transactions
#sql-сервер #транзакции
Вопрос:
У меня есть пакетный процесс, который импортирует большие объемы данных. Я делаю это, читая большой текстовый файл и анализируя, а затем выполняя вставки, обновления и удаления в соответствии с данными. Это простые инструкции, выполняемые как хранимые процедуры. Пакет вызовов хранимых процедур помещается в транзакцию, чтобы убедиться, что файл полностью обработан, прежде чем двигаться дальше. Пакетный импорт выполняется раз в неделю. Если клиент отстает, может быть несколько крупных транзакций подряд. Когда это происходит, я иногда получаю тайм-ауты команд в транзакциях после первой. Я увеличил время ожидания команды до 120 секунд. Пока работает нормально, но на медленном компьютере это может быть не так. Я заметил, что тайм-аут часто возникает на:
Update <table> set <columns> where <pk = some value>
Я подумал, что, возможно, SQL все еще обновляет индексы в фоновом режиме. Есть идеи о том, что происходит?
Я понимаю, что мог бы использовать что-то вроде SqlBulkCopy, но сейчас это не вариант.
Спасибо, Скотт
Комментарии:
1. Вероятно, у вас где-то есть блокировка. Это ваша основная производственная транзакционная база данных, поскольку другие люди запрашивают ее, когда вы ее обновляете? Если это так, ваша транзакция может блокировать ее.
2. Я забыл упомянуть, что это фактически однопользовательская база данных. Мое тестирование, где я получаю тайм-аут, — это машина разработчика, на которой нет других пользователей. Как ни странно, увеличение времени ожидания привело к устранению проблемы.
Ответ №1:
Выполняется ли ваш sproc построчно или он выполняет вставки, ОБНОВЛЕНИЯ и так далее на основе наборов? Ответ на этот вопрос станет важным несколькими абзацами ниже.
Но, во-первых, проблема с увеличением времени ожидания — это проблема n 1, независимо от того, как долго вы это делаете, этот случай все равно будет повторяться. Таким образом, увеличение времени ожидания не является постоянным решением для сна по ночам, как у младенца. Гораздо лучше устранить необходимость в тайм-ауте, разбив задание.
Первое, что вы делаете, это устраняете эту завершающую транзакцию. Ресурсы, необходимые для поддержания блокировок, увеличиваются по мере увеличения количества строк в операции, так что пакетные операции, подобные этой, часто выполняются быстрее, если разбить их на более мелкие этапы, требующие меньших транзакций.
Следующий шаг, поскольку у вас больше нет этой завершающей транзакции, заключается в том, чтобы убедиться, что каждый отдельный шаг может быть безопасно перезапущен в случае неудачного задания, независимо от того, где находился процесс в момент сбоя. Это называется «идемпотентным», если вы хотите быть причудливым, или «перезапускаемым», если вы хотите использовать простой английский.
Теперь мы возвращаемся к вопросу, выполняется ли ваш sproc построчно или он выполняет ВСТАВКИ, которые влияют на многие строки, затем ОБНОВЛЕНИЯ и так далее.
Пошаговый АНАЛИЗ: самый простой, хотя, вероятно, и самый медленный. Поместите текстовый файл в таблицу «ВХОДЯЩИЕ» и добавьте столбец «Обработано», который равен Y / N. При переходе строка за строкой вы выполняете ВСТАВКУ, ОБНОВЛЕНИЕ или УДАЛЕНИЕ, затем обновляете строку в таблице входящих как обработанную = Y. Если вы отключите подключение на любом этапе, sproc просто возобновит просмотр необработанных строк, пока их не останется ни одной. Это дает вам тот же эффект, что и большая транзакция переноса, без накладных расходов. Вы можете запускать десятки файлов подряд, и время ожидания сервера никогда не истечет.
НА ОСНОВЕ НАБОРА РЕГИСТРОВ: Если вы используете DML на основе наборов, то вы изменяете ВСТАВКУ таким образом, чтобы она извлекалась из таблицы входящих сообщений и ВСТАВЛЯЛАСЬ в целевую таблицу для всех строк, которых там еще нет. Это делает его доступным для повторного запуска. Инструкции DELETE не нуждаются в этой проверке, если вы повторно запустите УДАЛЕНИЕ на основе набора, и оно уже запущено, оно просто не найдет ничего для удаления. ОБНОВЛЕНИЕ в основном такое же, как УДАЛЕНИЕ в.
Это общий совет, основанный на том, что вы заявили о своей проблеме. Чтобы уточнить, мне нужно было бы узнать больше об этом процессе.
Ответ №2:
Я бы посмотрел на фрагментацию ваших индексов и при необходимости перестроил их.
Также я бы запустил ваши запросы в SSMS и включил включить фактический план выполнения и посмотреть, есть ли у вас какие-либо проблемы.
Комментарии:
1. Вероятно, это будет моим краткосрочным решением.
Ответ №3:
Сначала вам нужно выяснить, что является причиной тайм-аута. Как и при любом исследовании производительности SQL Server, наилучшим подходом является методология ожидания и очередей. В принципе, вам нужно посмотреть на wait_type
, wait_time
и wait_resource
в sys.dm_exec_requests
для сеанса, который выполняет UPDATE
. Это покажет, что блокирует / замедляет ОБНОВЛЕНИЕ, и в соответствии с этим выводом вы можете выполнить соответствующее действие / решение. Если рискну предположить, выстрел в темноте, ты кидаешься в журнале авто-рост событий в процессе тестирования. Тем не менее, правильное решение — сначала измерить, а затем сократить: исследовать, чтобы определить основную причину тайм-аута, и только после этого приступить к изменениям.