В моем сценарии мне нужно записать 100 миллионов строк из файлов различного размера на сервер SQL с удаленной машины (в той же сети). Для повышения производительности я уже записываю файлы данных в формате CSV на диск моего компьютера SQL (Y :). Это фрагмент одного из файлов, которые я пытаюсь импортировать
786,166537,46,928024944,23224244.87759578,0.00000021
785,166537,46,923850272,15364.87759500,0.00100000
...
И это MyTable
CREATE TABLE [dbo].[MyTable](
[Id] [int] NOT NULL,
[Number1] [int] NOT NULL,
[Number2] [int] NOT NULL,
[BigNumber] [bigint] NOT NULL,
[DecimalNumber] [decimal](26, 8) NOT NULL,
[NullableDecimal] [decimal](26, 8) NULL
)
Примечание: NullableDecimal
имеет значение nullable, но всегда определяется как 0.0 когда пусто Кроме того, в таблице нет индекса.
После перемещения файла на сервер SQL я вызываю эту процедуру, передавая полные пути файла CSV и файла формата:
CREATE PROCEDURE usp_bulk_insert
@bcp_file AS NVARCHAR(200),
@format_file AS NVARCHAR(200)
AS
BEGIN
SET NOCOUNT ON
DECLARE @sql NVARCHAR(4000) = 'BULK INSERT dbo.MyTable
FROM''' + @bcp_file + '''
WITH
(
FORMATFILE = ''' + @format_file + ''',
TABLOCK
);';
EXEC(@sql);
END
EXEC usp_bulk_insert @bcp_file='Y:\bcp\test.csv', @format_file='Y:\fmt\format_file.xml'
Я также определил файл формата XML, чтобы помочь
<BCPFORMAT xmlns="http://schemas.microsoft.com/sqlserver/2004/bulkload/format" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RECORD>
<FIELD ID="1" xsi:type="CharTerm" TERMINATOR="," MAX_LENGTH="12"/>
<FIELD ID="2" xsi:type="CharTerm" TERMINATOR="," MAX_LENGTH="12"/>
<FIELD ID="3" xsi:type="CharTerm" TERMINATOR="," MAX_LENGTH="12"/>
<FIELD ID="4" xsi:type="CharTerm" TERMINATOR="," MAX_LENGTH="21"/>>
<FIELD ID="5" xsi:type="CharTerm" TERMINATOR="," MAX_LENGTH="41"/>
<FIELD ID="6" xsi:type="CharTerm" TERMINATOR="\n" MAX_LENGTH="41"/>
</RECORD>
<ROW>
<COLUMN SOURCE="1" NAME="Id" xsi:type="SQLINT"/>
<COLUMN SOURCE="2" NAME="Number1" xsi:type="SQLINT"/>
<COLUMN SOURCE="3" NAME="Number2" xsi:type="SQLINT"/>
<COLUMN SOURCE="4" NAME="BigNumber" xsi:type="SQLBIGINT"/>
<COLUMN SOURCE="5" NAME="DecimalNumber" xsi:type="SQLDECIMAL" PRECISION="26" SCALE="8"/>
<COLUMN SOURCE="6" NAME="NullableDecimal" xsi:type="SQLDECIMAL" PRECISION="26" SCALE="8"/>
</ROW>
</BCPFORMAT>
Независимо от того, что я пытаюсь, мне кажется, что я не могу сделать лучше, чем 30 секунд для файла 300Mb с 3 миллионов строк.
Я попробовал несколько советов с этого сайта ; рекомендуется использовать локальные именованные каналы, я пытался, и я не мог найти слишком много информации об этом. Есть ли что-нибудь, что я могу попытаться сделать лучше?
---------- РЕДАКТИРОВАТЬ
Я запускаю команду BULK INSERT
в новом сеансе и запускаю команду
select * from sys.dm_exec_session_wait_stats order by wait_time_ms desc
Здесь верх 10 результатов:
session_id wait_type waiting_tasks_count wait_time_ms
75 SOS_SCHEDULER_YIELD 7107 206
75 MEMORY_ALLOCATION_EXT 38934 111
75 PREEMPTIVE_OS_WRITEFILE 528 65
75 IMPPROV_IOWAIT 6 44
75 PAGEIOLATCH_EX 2 20
75 PREEMPTIVE_OS_CREATEFILE 10 7
75 WRITELOG 1 3
75 PREEMPTIVE_OS_FILEOPS 4 2
75 PAGEIOLATCH_UP 1 1
Я буду исследовать их!
---------- РЕДАКТИРОВАТЬ
У меня есть полный контроль над созданием файл, который я не могу изменить, это формат финальной таблицы