0

我正在使用DataAdapterBatch 将批量大小 = 1000 插入到多对多表中

我有 3 张桌子

  1. 学校(ID、姓名)
  2. 学生(身份证,姓名)
  3. SCHOOL_STUDENT (SCHOOL_ID, STUDENT_ID)

我正在尝试向表 SCHOOL_STUDENT 插入大约 700K 行,但速度很慢我将学校名称和学生姓名传递给存储过程

    (
@schoolName varchar(100),
@studentName varchar(50)
)

AS
BEGIN transaction

    declare @scoolId int,@studentId int

    set @scoolId = (select ID from SCHOOL where [SCHOOL_NAME] = @schoolName)
    set @studentId = (select ID from STUDENT where STUDENT_NAME = @studentName)

    INSERT INTO [dbo].SCHOOL_STUDENT
                   (SCHOOL_ID,STUDENT_ID)
             VALUES
                   (@scoolId,@studentId)

commit transaction

但这需要大约 1 小时才能运行。我怎样才能加快速度,因为我事先也不知道school_Idstudent_Id所以我必须始终在存储过程中选择它们。(有没有更好的办法)

应用程序的流程是首先插入所有学生,然后插入所有学校,然后将它们链接到表 school_student 中。

4

3 回答 3

3

为了效率/影响和努力,也许尝试:

1-检查您正在阅读的表格上的索引。确保每个表的 ID 和名称列都有索引。

2-重构您的存储过程,如下所示:

 INSERT INTO dbo.School_Student(School_ID, Student_ID)
     SELECT SC.ID, ST.ID
     FROM dbo.School AS SC
     JOIN dbo.Student AS ST ON ST.Student_Name = @studentName
                            AND SC.School_Name = @schoolName;

3-从proc中删除事务

4-在调用此过程之前预加载所有学校 ID 和学生 ID。循环并传递 ID。

5- 调查 SQL 大容量复制操作。

于 2013-03-19T01:24:35.180 回答
2

您应该在 Student 和 School 表上创建索引以优化查找。我还将您的数据暂存到一个表中,并使用SqlBulkCopyC# 上传它。存储过程可以转换数据并插入键。

CREATE PROCEDURE spSchoolStudentTransform
AS
BEGIN

    INSERT INTO [dbo].[School_Student](School_Id, Student_Id)
    SELECT School.Id, Student.Id FROM SchoolStudent ss
    JOIN School
    ON School.School_Name = ss.SchoolName
    JOIN Student
    ON Student.Student_Name = ss.StudentName;

    TRUNCATE TABLE SchoolStudent;
END
GO

CREATE TABLE SchoolStudent
(
     Id INT IDENTITY PRIMARY KEY
    ,StudentName VARCHAR(50) NOT NULL
    ,SchoolName VARCHAR(100) NOT NULL
);
GO

CREATE NONCLUSTERED INDEX ixStudentIdStudentName
ON Student (Id, Student_Name);
GO

CREATE NONCLUSTERED INDEX ixSchoolIdSchoolName
ON School (Id, School_Name);
GO

using (var connection = new SqlConnection(connectionString))
{
    using(var sqlBulkCopy = new SqlBulkCopy(connection))
    {
        sqlBulkCopy.DestinationTableName = "SchoolStudent";
        sqlBulkCopy.EnableStreaming = true;
        sqlBulkCopy.BatchSize = 1000;

        sqlBulkCopy.WriteToServer(dataReader);
    }
}
于 2013-03-19T01:24:02.290 回答
0

该程序本身非常好。问题是你调用它 1000 次,你会得到性能成本,因为它会在每次调用时连接断开。

修改过程以接受 xml 或分隔语法,每个批次可以传递大约 100 到 500 个。

首先将其存储到临时表(虚拟,但物理),如果在批量插入期间发生某些事情,它不会损害事务/主表。存储学校名和学生名,插入时不要做任何选择。

最后,执行一个存储过程,它将所有记录从临时表插入到事务/主表。使用具有较大记录的从表中选择比执行 1 比 1 选择执行得更好。

不要忘记在从登台插入到事务/主表之前重新验证数据,检查空(未找到)数据、重复数据、由于字符串分隔符等导致的损坏数据等。

最后,正如您在评论中提到的,做一些索引和性能调整以获得更好的性能。如果处理得当,它应该会给你不到 10 分钟的执行时间。

于 2013-03-19T01:23:09.670 回答