Я пытаюсь вставить большой набор данных (около миллиона строк) из файла CSV с помощью приложения C# в базу данных с четырьмя таблицами. В файле CSV около 25% строк неверны из-за дублирования первичных ключей, и каждая строка разбивается на четыре таблицы. Вставка строки из CSV выполняется четырьмя процедурами (каждая для одной таблицы), упакованными в транзакцию с помощью оператора try-catch. Вставка 10000 строк занимает около одной минуты, так что это слишком долго. Существует ли более быстрый способ вставить большой набор данных и постоянно проверять целостность данных? Спасибо.
Обновлено: вот код моих процедур
USE semestralka
GO
CREATE PROCEDURE sp_vloz_ridice @crp nchar(9), @jmeno varchar(50)
AS
BEGIN
IF NOT EXISTS
(SELECT crp, jmeno FROM ridici
WHERE crp = @crp AND jmeno = @jmeno)
INSERT INTO ridici (crp, jmeno)
VALUES (@crp, @jmeno)
END
USE semestralka
GO
CREATE PROCEDURE sp_vloz_auto @SPZ nchar(8), @barva int, @vyrobce nvarchar(25), @model nvarchar(40)
AS
BEGIN
IF NOT EXISTS
(SELECT SPZ, barva, vyrobce, model FROM auta
WHERE SPZ = @SPZ AND barva = @barva AND vyrobce = @vyrobce AND model = @model)
INSERT INTO auta (SPZ, barva, vyrobce, model)
VALUES (@SPZ, @barva, @vyrobce, @model)
END
USE semestralka
GO
CREATE PROCEDURE sp_vloz_branu @brana_jmeno nchar(10), @typ varchar(10), @cena real, @gps_lattitude real, @gps_longtitude real
AS
BEGIN
IF NOT EXISTS
(SELECT jmeno, typ, cena, gps_lattitude, gps_longtitude FROM brany
WHERE jmeno = @brana_jmeno AND typ = @typ AND cena = @cena AND gps_lattitude = @gps_lattitude AND gps_longtitude = @gps_longtitude )
INSERT INTO brany (jmeno, typ, cena, gps_lattitude, gps_longtitude)
VALUES (@brana_jmeno, @typ, @cena, @gps_lattitude, @gps_longtitude)
END
USE semestralka
GO
CREATE PROCEDURE sp_vloz_prujezd @prujezd_datum_cas int, @fk_prujezd_spz nchar(8), @fk_prujezd_crp nchar(9), @fk_gps_lattitude real, @fk_gps_longtitude real, @tachometr_stav int, @palivo_stav real, @napeti_baterie real
AS
BEGIN
INSERT INTO prujezdy (prujezd_datum_cas, fk_prujezd_spz, fK_prujezd_crp, fk_gps_lattitude, fk_gps_longtitude, tachometr_stav, palivo_stav, napeti_baterie)
VALUES (@prujezd_datum_cas, @fk_prujezd_spz, @fK_prujezd_crp, @fk_gps_lattitude, @fk_gps_longtitude, @tachometr_stav, @palivo_stav, @napeti_baterie)
END
USE semestralka
GO
CREATE PROCEDURE sp_super_insert @SPZ nchar(8), @barva int, @vyrobce nvarchar(25), @model nvarchar(40),
@crp nchar(9), @jmeno varchar(50),
@brana_jmeno nchar(10), @typ varchar(10), @cena real, @gps_lattitude real, @gps_longtitude real,
@prujezd_datum_cas int, @tachometr_stav int, @palivo_stav real, @napeti_baterie real, @output bit OUTPUT
AS
BEGIN
SET @output = 0
BEGIN TRANSACTION
BEGIN TRY
EXEC sp_vloz_auto @SPZ, @barva, @vyrobce, @model
EXEC sp_vloz_ridice @crp, @jmeno
EXEC sp_vloz_branu @brana_jmeno, @typ, @cena, @gps_lattitude, @gps_longtitude
EXEC sp_vloz_prujezd @prujezd_datum_cas, @SPZ, @crp, @gps_lattitude, @gps_longtitude, @tachometr_stav, @palivo_stav, @napeti_baterie
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
RETURN @output
END CATCH
COMMIT TRANSACTION
SET @output = 1
RETURN @output
END
Вы пробовали SSIS? Правильный сервис ETL, вероятно, был бы «лучше», однако @TabAlleman прямо здесь, нам не с чем сейчас работать.
Вы можете использовать класс SQLBulkCopy. Вы можете установить для него KeepIdentity как часть аргумента bulkcopyoptions, но я считаю, что другая проверка данных должна выполняться отдельно. Вам нужно будет построить сопоставление столбцов перед вставкой, если ваши спецификации столбцов не совпадают. Это настоящий проект для SO-поста.
Другой вариант - выполнить массовую вставку хранимого процесса SQL Server в промежуточную таблицу, а затем (1) проверить данные и (2) запустить операторы insert into...select from из промежуточной таблицы. Однако SSIS предпочтительнее, если вы можете им управлять.





Используйте операции на основе наборов вместо построчных операторов (или курсора / foreach). В настоящее время вы выполняете хранимую процедуру, которая выполняет еще 4 хранимых процедуры внутри транзакции, просто чтобы вставить 4 строки в 4 разные таблицы. Выполнение этого тысячи раз чрезвычайно медленно по сравнению с базовым решением, в котором вы выполняете все строки одновременно, не жертвуя своими бизнес-правилами.
Используйте команду Bulk Insert (из вашего приложения C#) в промежуточную таблицу, которая представляет собой таблицу для хранения временных данных перед их вставкой в ваши конечные таблицы. В вашем случае у вас будет 4 разных промежуточных стола.
Эти промежуточные таблицы не будут иметь ограничений, ключей, триггеров или любого другого механизма, который может задержать операцию вставки. Массовые вставки на таких столах работают очень быстро.
После того, как вы вставите свой CSV в промежуточные таблицы, вы можете использовать SQL для проверки и вставки записей в конечную таблицу (на основе набора, а не 1 на 1). Вы можете создавать или включать (перестраивать) индексы в промежуточных таблицах, если вам нужно выполнить объединения или определенные фильтры для определенных столбцов.
Промежуточные таблицы могут быть непостоянными, поэтому при необходимости вы можете усекать их при каждом запуске.
Спасибо. Это решение намного быстрее.
Быстрее чем? Вы не сказали нам, что делают эти хранимые процедуры. Покажите нам свой код.