2012-01-20 2 views
4

файл ошибок Windows Server 2008 R2 Enterprise, SQL Server 2008 X64, SP3, разработчик изданиеОдновременная SQL BULK Вставки генерировать сбои при использовании опции

я строю и динамически выполнять (через sp_executesql) команду BULK INSERT. Общая форма:

BULK INSERT #HeaderRowCheck 
from "\\Server\Share\Develop\PKelley\StressTesting\101\DataSet.csv" 
with 
(
    lastrow = 1 
    ,rowterminator = '\n' 
    ,tablock 
    ,maxerrors = 0 
    ,errorfile = 'C:\SQL_Packages\TempFiles\#HeaderRowCheck_257626FB-A5CD-41B8-B862-FAF8C591C7A9.log' 
) 

(файл ошибки имя основано на настроенную локальную папке, таблица загружается и GUID генерируется свеж для каждой объемной перспективы вставки - это подпрограмма, завернутая в своей собственной хранимую процедуре .)

Внешний процесс (был агент SQL, теперь является службой WCF) запускает DTEXEC, который запускает пакет SSIS, который вызывает хранимые процедуры в базе данных, которая осуществляет цикл через множество, строит запрос и запускает его для каждого. Одновременно может быть запущено до четырех нагрузок из/в данную базу данных, и одновременно могут работать несколько баз данных на экземпляре SQL, хотя исторически объем был низким, и у нас обычно был только один экземпляр, выполняющий это за раз. Мы делаем это очень много, и он работает безупречно уже более двух лет - безопасность настроена правильно, необходимы файлы и папки, все обычное. (Luck? Мне нравится думать не так.)

Теперь мы ожидаем серьезных нагрузок, поэтому мы проводим некоторые стресс-тесты, в которых я запускаю 8 прогонов, каждый из которых имеет четыре процесса, в которых набор из четырех будет разделяться и один за другим обрабатывают файлы для загрузки (т. е. выполняется до 32 одновременных объемных вставок. Как я уже сказал, стресс-тестирование). Низкий уровень и, если он запущен, один или несколько не будут работать во время выполнения, с ошибкой сообщение как:

Error #4861 encountered while loading header information from file "DataSet.csv": Cannot bulk load because the file "C:\SQL_Packages\TempFiles\#HeaderRowCheck_D0070742-76A5-4175-A1A7-16494103EF25.log" could not be opened. Operating system error code 80(The file exists.).

от прогона к прогону, ошибка не происходит того же файла, набор данных, или точка-в-общем-обработки.

На первый взгляд кажется, что два процесса пытаются получить доступ к одному и тому же файлу ошибок, что означает, что они независимо генерируют одно и то же guid (!). Я понимаю, что это должно быть почти невозможно. Альтернативная теория - так много происходит одновременно (возможно, до 32 одновременных команд BULK INSERT), SQL и/или ОС каким-то образом запутываются (я администратор базы данных, а не администратор сети). Я мог бы обойтись, построив блок try-catch, чтобы проверить ошибку 4861 и повторить попытку до трех раз, но я бы предпочел избежать такого клонирования.

С тех пор я бросил в рутину, которая записывает имя файла ошибки (с помощью guid) в таблицу перед ее использованием. После многих прогонов и нескольких сбоев я вижу, что (а) файл с ошибкой + guid записывается в мою таблицу и (б) не регистрируются повторяющиеся записи.

Кто-нибудь знает, что может быть?

Филипп

ответ

6

Я открыл дело с Microsoft технической поддержки, и после того, как не небольшое количество возвратно-поступательный, Прадипом М.М. (Технический руководитель технической поддержки SQL Server) полностью справился.

Общий процесс: прочитайте в списке файлов в папке и один за другим выполните серию объемных вставок на эти файлы (сначала для чтения первой строки, которую мы анализируем для столбцов, а затем для чтения данных из вторых + строк). Все массивные вставки используют параметр «ErrorFile», чтобы предоставить пользователям какую информацию мы можем, когда их данные неверно отформатированы. Процесс работал уже 3 года, но в условиях недавних стресс-тестов (до 8 одновременных прогонов, выполненных одним экземпляром SQL Server, с надлежащим образом отформатированным файлом), мы получили ошибки, перечисленные выше.

Первоначально, хотя из-за этой «уже открытой» ошибки были ошибки при генерации GUID, но эта идея была в конечном счете отброшена - если функция newid() не функционировала должным образом, гораздо больше людей будет иметь много более серьезные проблемы.

Согласно Pradeep, вот шаг за шагом, как Bulk Insert Works:

  1. BULK INSERT Команда передается и обрабатывается для синтаксических ошибок
  2. Затем BULK INSERT Команда компилируется для генерации Исполнение План же
  3. во время фазы компиляции, если в запросе, если мы определили параметр, то файл ошибок мы создадим ErrorFile.log и ErrorFile.Error.Txt в папке, указанной (важно вещи, чтобы понять здесь файл будет иметь 0KB размер)
  4. После создания файла завершается удаляет оба файл с помощью Windows API вызовов
  5. После того, как план выполнения будет готов мы переходим к фазе исполнения и попробуйте выполнить команду «Массовая вставка» в качестве части ее, мы будем заново создать файл ErrorFile.log и ErrorFile.Error.Txt в указанную папку (так как в документации по электронной документации в Интернете файлов не должно быть в этом или мы не сможем выполнить наш http://msdn.microsoft.com/en-us/library/ms188365.aspx
  6. После того, как выполнение завершено, если e - любые ошибки в Вставка в массе Соответствующие ошибки записываются в файлы ошибок , созданные, если ошибок нет, эти 2 файла будут удалены.

Запуск ProcMon (Process Monitor) во время неудачных прогонов показал, что ErrorFile был успешно создан и открыт на шаге 3, но НЕ был закрыт на шаге 4, в результате чего шаг 5 породил ошибку, которую мы видели. (Для успешных запусков файл был создан и закрыт, как ожидалось.)

Дальнейший анализ ProcMon показал, что еще один процесс, выполняющий CMD.EXE, выполнял операции «закрыть дескриптор» в файле после попытки объемной вставки. Мы используем процедуру, включающую команду xp_cmdshell, чтобы получить список файлов, которые будут обработаны, и это станет причиной процесса CMD.EXE. Вот кикер:

... есть некоторая бизнес-логика, которая запускает CMD.EXE внутри SQL Server, и поскольку CMD.EXE является дочерним процессом, он наследует все дескрипторы, открытые родительским процессом (так что, вероятно, это какой-то выбор времени проблема, когда в CMD.EXE хранятся дескрипторы файлов, которые открыты, когда они запущены, и все те файлы, которые обрабатываются CMZ.EXE, не могут быть удалены и могут быть освобождены только после уничтожения CMD.EXE)

И вот и все. Один запуск никогда не затрагивает эту проблему, так как его вызов xp_cmdshell завершается до выпуска объемных вставок. Но параллельно работает, особенно с большим количеством параллельных трасс (я только ударил проблему с 5 или более текущим), вопрос времени произошел такие, что:

  1. Один из SSIS пакет выполняется и вызывает хранимую процедуру , которая внутренне использует XP_CMDSHELL и запускает CMD.EXE для перечисления Файлы
  2. То же соединение с сервером SQL завершает файл перечисления , а затем запускает Bulk Insert активность, и это в Сборнике фаза для BULK INSERT Command
  3. В соответствии с конструкцией Bulk Insert мы делаем создать файл ошибок на этапе компиляции, а затем удалить его после компиляции фаза делается
  4. в то же время другой SSIS пакет запускается на выполнение, и это вызывает хранимая процедура, которая внутренне использует xp_cmdshell и запускает CMD.EXE, чтобы перечислить все файлы
  5. CMD.EXE является дочерним процесс, который был запущен под Parent Process sqlservr.exe поэтому по умолчанию он наследует все ручки созданных sqlservr.e (Так что этот процесс становится всеми ручками для в файле ошибки, которые были созданный BULK INSERT в первом Connection)
  6. Теперь при первом подключении фаза компиляции снова и поэтому мы пытаемся удалить файл, в течение которого мы должны закрыть все ручки, мы видим, что CMD. EXE удерживает дескриптор файла , и он все еще открыт, и поэтому мы не можем удалить файл. Итак, , не удаляя файл, мы переходим на фазу выполнения и в на этапе выполнения мы пытаемся создать новый ERRORFILE с таким же именем , но так как файл уже существует, мы с ошибкой «Код ошибки операционной системы 80 (Файл существует.).

Моим краткосрочным обходным путем было: (1) реализовать цикл повтора, создать новое имя ErrorFile и попытаться добавить новую объемную вставку до трех раз, прежде чем сдаться, и (2) создание другой процедуры для наших ночных процессов для удаления всех файлов, найденных в нашей папке «ErrorFile».

Долгосрочное исправление заключается в том, чтобы пересмотреть наш код, чтобы не перечислить файлы через xp_cmdshell. Это представляется выполнимым, поскольку весь процесс ETL завершается и управляется пакетом SSIS; В качестве альтернативы, могут быть построены и обработаны подпрограммы CLR. Пока что, учитывая нашу ожидаемую рабочую нагрузку, рабочая обстановка достаточна (особенно учитывая все остальное, над чем мы сейчас работаем), поэтому может быть немного до того, исправить.

Опубликовано для потомков, если это когда-нибудь случится с вами!

+0

+1 сложная проблема – Omar

Смежные вопросы