C #으로 SQL Server의 임시 테이블에 30,000 개의 행을 삽입하는 가장 빠른 방법

bulkinsert c# sql sqlbulkcopy sql-server

문제

C #을 사용하여 SQL Server의 임시 테이블에서 삽입 성능을 향상시킬 수있는 방법을 찾으려고합니다. 어떤 사람들은 SQLBulkCopy를 사용해야한다고 말하고 있지만 SQL 삽입 문자열을 작성하는 것보다 훨씬 느리게 작동하는 것처럼 잘못 처리해야합니다.

SQLBulkCopy를 사용하여 테이블을 생성하는 코드는 다음과 같습니다.

public void MakeTable(string tableName, List<string> ids, SqlConnection connection)
    {

        SqlCommand cmd = new SqlCommand("CREATE TABLE ##" + tableName + " (ID int)", connection);
        cmd.ExecuteNonQuery();

        DataTable localTempTable = new DataTable(tableName);

        DataColumn id = new DataColumn();
        id.DataType = System.Type.GetType("System.Int32");
        id.ColumnName = "ID";
        localTempTable.Columns.Add(id);

        foreach (var item in ids)
        {
             DataRow row = localTempTable.NewRow();
             row[0] = item;
             localTempTable.Rows.Add(row);
             localTempTable.AcceptChanges();
        }


        using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
        {
            bulkCopy.DestinationTableName = "##" + tableName;
            bulkCopy.WriteToServer(localTempTable);

        }
    }

이 방법은 내 인서트를 실행하는 데 오랜 시간이 걸립니다. 내 인서트가 다른 방식으로 더 빨리 작동하도록했습니다.

삽입 비트를 문자열로 작성한 후 SQL에 임시 테이블 명령문을 작성했습니다.

삽입 문자열 생성 :

public string prepareInserts(string tableName, List<string> ids)
    {
        List<string> inserts = new List<string>();

        var total = ids.Select(p => p).Count();
        var size = 1000;

        var insert = 1;

        var skip = size * (insert - 1);

        var canPage = skip < total;

        while (canPage)
        {
            inserts.Add(" insert into ##" + tableName + @" (ID) values " + String.Join(",", ids.Select(p => string.Format("({0})", p))
                        .Skip(skip)
                        .Take(size)
                        .ToArray()));
            insert++;
            skip = size * (insert - 1);
            canPage = skip < total;
        }

        string joinedInserts = String.Join("\r\n", inserts.ToArray());

        return joinedInserts;

    }

쿼리를 생성 한 후 SQL 문에서 사용 :

inserts = prepareInserts(tableName, ids);

var query = @"IF EXISTS
                                            (
                                            SELECT *
                                            FROM tempdb.dbo.sysobjects
                                            WHERE ID = OBJECT_ID(N'tempdb..##" + tableName + @"')
                                            )
                                                BEGIN
                                                    DELETE FROM ##" + tableName + @"
                                                END
                                            ELSE
                                                BEGIN
                                                    CREATE TABLE ##" + tableName + @"
                                                    (ID int)
                                                END " + inserts;

            var command = new SqlCommand(query, sqlConnection);
...

나는 사람들이 나를 (스택 교환에서) https://dba.stackexchange.com/questions/44217/fastest-way-to-insert-30-thousand-rows-in-sql-server/44222?noredirect= 1 # comment78137_44222 ) SQLBulkCopy 를 사용해야한다는 것이 더 빠를 것입니다. 제가하는 방식을 개선해야한다고 생각합니다. 따라서 누군가가 SQLBulkCopy 코드를 개선 할 수있는 방법을 제안 할 수 있거나 내 응용 프로그램의 성능을 향상시킬 수있는 더 나은 삽입 문이 있는지 말해 줄 수 있습니다.

수락 된 답변

귀하의 문제는 localTempTable.AcceptChanges(); 에있을 수 있습니다 localTempTable.AcceptChanges(); 변경 사항을 커밋하기 때문에.
당신이 다음 일을한다면, 나는 더 빨리 달릴 것이라고 생각한다.

    foreach (var item in ids)
    {
         DataRow row = localTempTable.NewRow();
         row[0] = item;
         localTempTable.Rows.Add(row);

    }

    localTempTable.AcceptChanges();

    using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
    {
        bulkCopy.DestinationTableName = "##" + tableName;
        bulkCopy.WriteToServer(localTempTable);

    }

MSDN - DataSet.AcceptChanges에서

이 데이터 세트가로드 된 이후 또는 마지막으로 AcceptChanges가 호출 된 이후 변경된 사항을 커밋합니다.


인기 답변

StopWatch 객체로이 코드를 직접 실행하여 시간을 측정합니다. 느리게 만드는 모든 반복에서 AcceptChanges가 있습니다.

public void MakeTable(string tableName, List<string> ids, SqlConnection connection)
{
    SqlCommand cmd = new SqlCommand("CREATE TABLE ##" + tableName + " (ID int)", connection);
    cmd.ExecuteNonQuery();

    DataTable localTempTable = new DataTable(tableName);

    DataColumn id = new DataColumn();
    id.DataType = System.Type.GetType("System.Int32");
    id.ColumnName = "ID";
    localTempTable.Columns.Add(id);

    System.Diagnostics.Stopwatch sw1 = new System.Diagnostics.Stopwatch();        

    sw1.Start();
    foreach (var item in ids)
    {
        DataRow row = localTempTable.NewRow();
        row[0] = item;
        localTempTable.Rows.Add(row);

    }
    localTempTable.AcceptChanges();
    long temp1 = sw1.ElapsedMilliseconds;
    sw1.Reset();
    using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
    {
        bulkCopy.DestinationTableName = "##" + tableName;
        bulkCopy.WriteToServer(localTempTable);

    }
    long temp2 = sw1.ElapsedMilliseconds;
}

AccretChanges가 foreach 루프 안에있을 때의 결과

여기에 이미지 설명을 입력하십시오.

그리고 그게 아니라면

여기에 이미지 설명을 입력하십시오.

차이는 3 단계입니다. :)



아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.