我正在使用DataAdapter
Batch来插入多对多表
批量大小= 1000
我有3张桌子
我正在尝试将约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表中。
答案 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分钟的执行时间。