使用存储过程插入非常慢

时间:2013-03-19 01:02:14

标签: c# sql

我正在使用DataAdapter Batch来插入多对多表 批量大小= 1000

我有3张桌子

  1. 学校(身份证,姓名)
  2. 学生(身份证,姓名)
  3. SCHOOL_STUDENT(SCHOOL_ID,STUDENT_ID)
  4. 我正在尝试将约700K行插入到SCHOOL_STUDENT表中,但它非常慢 我将学校名称和学生姓名传递给存储过程

        (
    @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_Id student_Id,所以我必须始终在存储过程中选择它们。 (有更好的方法)

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

3 个答案:

答案 0 :(得分:3)

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

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

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-在调用此proc之前预加载所有学校ID和学生ID。循环并传递ID。

5-调查SQL批量复制操作。

答案 1 :(得分:2)

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

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);
    }
}

答案 2 :(得分:0)

程序本身非常好。问题是你称它为1000次,你将获得性能成本,因为它将连接 - 每次调用断开连接。

修改程序以接受xml或分隔语法,每个批处理可以传递100到500个。

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

最后,执行一个存储过程,该过程将所有记录从登台表插入到事务/主表。使用具有较大记录的表中的select比执行1 by 1 select更好。

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

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