MSSQL 2017 - 有效插入大型数据集

时间:2018-05-08 13:32:19

标签: c# sql-server performance insert

我正在尝试使用C#应用程序将CSV文件中的大量数据(大约一百万行)插入到具有四个表的数据库中。在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

1 个答案:

答案 0 :(得分:1)

使用基于集合的操作而不是逐行(或游标/ foreach)语句。您当前正在执行一个存储过程,该事务在事务中执行另外4个存储过程,只是在4个不同的表中插入4行。与设置的基本解决方案相比,执行此操作数千次是极其缓慢的,其中您可以同时执行所有行,而不会牺牲业务规则。

使用批量插入命令(来自您的C#应用​​程序)进入临时表,该表是在将时间数据插入最终表之前保存时态数据的表。在您的情况下,您将有4个不同的临时表。

这些临时表没有约束,键,触发器或任何其他可能会延迟插入操作的机制。批量插入在这些表格上运行得非常快。

在登台表上插入CSV后,您可以使用SQL验证并在最终表格中插入记录(基于集合,而不是1乘1)。如果需要在某些列上执行连接或特定过滤器,则可以在登台表上创建或启用(重建)索引。

登台表可能是易变的,因此如果需要,您可以在每次运行时截断它们。