SQL Server массовая вставка более 1 млн строк-требуется повышение производительности
Мне было поручено разработать метод для импорта текстовых файлов с 1 миллионом или более строк в таблицу. Каждая строка в таблице составляет 856 байт, разбитых примерно на 150 "столбцов" данных. Я использую SQL Server 2012 Standard Edition. Действие, связанное со вставками, является единственным действием в базе данных. Я построил хранимую процедуру, которая делает следующее:
GET LIST OF UNIMPORTED DATA FILES IN A SPECIFIC DIRECTORY
LOOP THROUGH LIST OF FILES
BULK INSERT INDIVIDUAL FILE DATA INTO (DISK-BASED) TEMP TABLE
LOOP THROUGH RECORD-LEVEL DATA IN TEMP TABLE
PARSE/WRITE RECORD-LEVEL DATA TO DETAILRECORD TABLE
IF ALL RECORDS FOR A GIVEN FILE ARE SUCCESSFULLY WRITTEN TO THE DETAIL RECORD TABLE
THEN
MOVE FILE TO IMPORTED_FILES DIRECTORY
WRITE SUCESS RECORD TO IMPORTLOG TABLE
ELSE
WRITE FAIL RECORD TO IMPORTLOG TABLE
MOVE ON TO NEXT FILE
Массовая вставка необработанного текстового файла во временную таблицу выполняется достаточно быстро, менее чем за 1 минуту. Однако мне нужно проанализировать эти необработанные данные и поместить их в таблицу назначения. Для ясности это означает, например, что данные из расположения строк 1-10 должны быть записаны в целевую таблицу, 11-13 должны быть записаны в целевую таблицу и т. д. Я делаю это, используя цикл WHILE вместо курсора и циклически проходя через каждую из 1 миллиона строк, а затем передавая необработанные данные в качестве параметра другой хранимой процедуре, которая затем анализирует необработанные данные и вставляет в целевая таблица. Я разбираю необработанные данные просто с помощью функции SUBSTRING, то есть SUBSTRING(@rawdata,1,10).
И, как я уже упоминал, в каждой строке есть примерно 150 полей. Однако выполнение шага синтаксического анализа/записи ужасно. Это заняло 10 часов, чтобы импортировать 170k строк.
В целевой таблице нет кластеризованных индексов. Модель восстановления настроена на простой режим. У меня включена функция" мгновенная инициализация файла".
Я рассматриваю возможность использования SSIS, но 1) я подозреваю, что производительность не может быть намного быстрее, и 2) устранение неполадок кажется более громоздким в SSIS.
Ищу мысли, блестящие идеи и очевидные предложения, которые я пропустил.EDIT (добавлен код внутри цикла WHILE):
WHILE @RecordCounter <= @FileRecordCount
BEGIN
SELECT @Record = record FROM CDR.tempFile WHERE id = @RecordCounter
EXEC [CDR].[usp_ImportCDRData_Record] @pRecord = @Record, @pCarrier = @carrier, @pLogid = @ImportLogID
SET @RecordCounter = @RecordCounter + 1
END
--Inside [CDR].[usp_ImportCDRData_Record]
INSERT INTO dbo.DetailRecord
(
LOGID ,
ACCOUNTNUMBER ,
CORPID ,
SERVICELOCATION ,
NETWORKINDICATOR ,
...
)
VALUES
(
@pLogID,
SUBSTRING(@pRecord, 1,10), -- ACCOUNTNUMBER
SUBSTRING(@pRecord, 11,8), -- CORPID
SUBSTRING(@pRecord, 19,8), -- SERVICELOCATION
SUBSTRING(@pRecord, 27,1), -- NETWORKINDICATOR
...
)
1 ответ:
Вместо использования цикла WHILE подумайте о решении, основанном на множестве, где вам не нужно обрабатывать каждую строку отдельно.
Если бы вы могли поделиться некоторой дополнительной информацией о том, какой код находится в цикле WHILE, мы могли бы значительно ускорить его. Даже без использования SSIS ; -)
На данный момент я бы не согласился, что есть "необходимость" разбирать одну строку за раз...