0

I'm using DataAdapter Batch to insert to many to many table the batch size = 1000

i have 3 tables

  1. SCHOOL (ID, Name)
  2. STUDENT (ID,Name)
  3. SCHOOL_STUDENT (SCHOOL_ID, STUDENT_ID)

I'm trying to insert around 700K rows to the table SCHOOL_STUDENT but it's very slow i'm passing the school name and the student name to the stored procedure

    (
@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

but this takes around 1 hour to run. How can i speed this, as i don't know the school_Id neither the student_Id in advance, then i have to always select them inside the stored procedure. (is there a better way)

the flow of the application is first inserting all students, then insert all schools then link them in the table 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 回呼び出すことです。呼び出しごとに接続と切断が行われるため、パフォーマンス コストが発生します。

バッチごとに約 100 から 500 を渡すことができる xml または区切り構文を受け入れるように手順を変更します。

バッチ挿入中に何かが発生した場合にトランザクション/マスター テーブルに害を及ぼさないように、最初にステージング テーブル (ダミーですが物理) に格納します。学校名と生徒名を保存し、挿入中に選択を行わないでください。

最後に、ステージング テーブルからトランザクション/マスター テーブルにすべてのレコードを挿入するストア プロシージャを実行します。より大きなレコードでテーブルから選択を使用すると、1 つずつ選択するよりもパフォーマンスが向上します。

ステージングからトランザクション/マスター テーブルへの挿入を行う前に、データを再検証することを忘れないでください。null (見つからない) データ、重複データ、文字列区切り文字による破損データなどをチェックしてください。

最後に、コメントで述べたように、パフォーマンスを向上させるためにインデックス作成とパフォーマンスの調整を行います。正しく処理された場合、実行時間は 10 分未満になります。

于 2013-03-19T01:23:09.670 に答える