2015-01-05 3 views
4

나는 약 3000 행의 datatable 있습니다. 각 행은 데이터베이스 테이블에 삽입되어야합니다. 현재, 나는 아래로 foreach 루프를 실행하고 있습니다 : 데이터베이스에 C# 여러 개의 병렬 삽입

obj_AseCommand.CommandText = sql_proc; 
obj_AseCommand.CommandType = CommandType.StoredProcedure; 
obj_AseCommand.Connection = db_Conn; 
obj_AseCommand.Connection.Open(); 

foreach (DataRow dr in dt.Rows)     
{ 
    obj_AseCommand.Parameters.AddWithValue("@a", dr["a"]); 
    obj_AseCommand.Parameters.AddWithValue("@b", dr["b"]); 
    obj_AseCommand.Parameters.AddWithValue("@c", dr["c"]); 

    obj_AseCommand.ExecuteNonQuery(); 
    obj_AseCommand.Parameters.Clear(); 
} 

obj_AseCommand.Connection.Close(); 

는 위의 방법은 3000 행을 삽입하기 위해 약 10 분 정도 소요됩니다 이후이 평행 데이터베이스에 SP를 수행 할 수있는 방법을 알려 주시기 바랍니다 수 있습니다. 그것은 또한 각 연결에 대한 쓰레드를 소비하므로 DB 삽입을 병렬화하는 Parallel.ForEach를 사용하여 돌이켜에서

+1

의이다 다만, 데이터베이스에 대한 datatable를 기록? 이것이 어떤 입력 파일에서 온 것이라면, 어떤 관리 도구로 데이터베이스로 직접 가져 오지 않겠습니까? – ShayD

+0

데이터 테이블은 다른 데이터베이스 (마스터 데이터베이스)에서 채워집니다. 내 목표는 마스터 데이터베이스에서 데이터를 가져오고 내 데이터베이스에 삽입하는 것입니다. 저장 프로 시저 내 데이터베이스에 데이터를 삽입하는 데 사용됩니다. – Harsh

+3

대량 삽입물 또는 링크 서버를 사용하고 SQL에서 데이터를 가져 와서 삽입하지 마시오. – 3dd

답변

8

편집

는 약간 낭비입니다. 대체로 더 나은 병렬 솔루션은 ExecuteNonQueryAsync과 같은 System.Data Db Operations의 비동기 버전을 사용하여 동시에 실행을 시작한 다음 await Task.WhenAll()을 사용하여 완료시 대기합니다. 그러면 호출자에 대한 스레드 오버 헤드가 방지되고, 전반적인 Db 성능은 더 빨라지지 않을 것입니다. More here

원래 대답, 데이터베이스에 여러 개의 병렬 삽입은

당신은 병렬 사용 TPL, 예를 들어,이 작업을 수행 할 수 있습니다 특히 localInit 과부하가 Parallel.ForEach 인 경우 당신이 정말로 당신이 알고하지 않으면

  • :

    Parallel.ForEach(dt.Rows, 
        // Adjust this for optimum throughput vs minimal impact to your other DB users 
        new ParallelOptions { MaxDegreeOfParallelism = 4 }, 
        () => 
        { 
         var con = new SqlConnection(); 
         var cmd = con.CreateCommand(); 
         cmd.CommandText = sql_proc; 
         cmd.CommandType = CommandType.StoredProcedure; 
         con.Open(); 
    
         cmd.Parameters.Add(new SqlParameter("@a", SqlDbType.Int)); 
         // NB : Size sensitive parameters must have size 
         cmd.Parameters.Add(new SqlParameter("@b", SqlDbType.VarChar, 100)); 
         cmd.Parameters.Add(new SqlParameter("@c", SqlDbType.Bit)); 
         // Prepare won't help with SPROCs but can improve plan caching for adhoc sql 
         // cmd.Prepare(); 
         return new {Conn = con, Cmd = cmd}; 
        }, 
        (dr, pls, localInit) => 
        { 
         localInit.Cmd.Parameters["@a"] = dr["a"]; 
         localInit.Cmd.Parameters["@b"] = dr["b"]; 
         localInit.Cmd.Parameters["@c"] = dr["c"]; 
         localInit.Cmd.ExecuteNonQuery(); 
         return localInit; 
        }, 
        (localInit) => 
        { 
         localInit.Cmd.Dispose(); 
         localInit.Conn.Dispose(); 
        }); 
    

    주 : 당신은 거의 확실하게 당신이 당신의 데이터베이스를 범람하지 않도록 MaxDegreeOfParalelism을 조정하여 병렬 처리의 양을 조절보고 싶을 것 일반적으로 우리는 TPL을 떠나 병렬 처리 정도를 결정해야합니다. 그러나 리소스에 대한 경합 (데이터베이스 작업에 대한 읽기 : 잠금)에 따라 동시 작업의 상한을 제한해야 할 수도 있습니다 (시행 착오가 유용 할 수 있습니다. 예 : 4, 8, 16 동시 작업 등의 동시 작업으로 대부분의 처리량을 제공하는 참조와 SQL 서버의 잠금 및 CPU 부하를 모니터링 할 수 있습니다.

  • 을 마찬가지로, TPL의 기본 파티션 프로그램이 작업에 걸쳐 데이터 행을 분할 할만큼 일반적으로 좋은 떠나.
  • 각각의 작업은 자신의 별도의 SQL이 필요합니다 연결
  • 각 호출마다 명령을 작성하고 삭제하는 대신 작업 당 한 번만 작성한 다음 동일한 명령을 계속 사용하면서 매번 매개 변수를 업데이트하십시오.
  • LocalInit/Local Finally 람다를 사용하여 명령 및 연결 삭제와 같은 작업 설정 및 정리 작업을 수행합니다.
  • 당신은 또한 당신의 Ad-Hoc SQL을 사용하거나 Sql versions prior to 2005
  • 것은 내가 DataTable's 행을 열거하는 스레드 안전 있으리라 믿고있어 경우 .Prepare() 사용을 고려할 수 있습니다. 물론 이것을 다시 확인하고 싶을 것입니다.

사이드 참고 : 3000 행에 대한

10 분에도 넓은 테이블과 단일 스레드와 과도한이다. 귀하의 proc은 무엇을합니까?나는 처리가 사소한 것으로 생각하지 않으므로 SPROC가 필요하다고 생각했지만 간단한 삽입을 수행하는 경우 @ 3dd의 설명에 따르면 SqlBulkCopy은 합리적으로 좁은 테이블에서 분당 ~ 1M 행의 삽입을 생성합니다.

+0

안녕 스튜어트, 입력에 감사드립니다. 나는 우리가 Sybase 데이터베이스를 가지고 있기 때문에 AseBulkCopy를 사용하여 아래 코드를 사용해 보았다. AseBulkCopy obj_AseBulkCopy = new AseBulkCopy (db_Conn); obj_AseBulkCopy.DestinationTableName = "db_table"; obj_AseBulkCopy.BatchSize = 1000; db_Conn.Open(); obj_AseBulkCopy.WriteToServer (dt); db_Conn.Close(); 그러나 여전히 실행하는 데 동일한 시간이 걸렸습니다. 이 코드에서 뭔가 빠졌습니까? – Harsh

+0

BulkCopy가 3000 행에 대해 10 분이 걸리면 RDBMS에서 이상한 점이 있습니다. 난 많은 논리를하고있는 삽입 된 테이블에 트리거가 있거나 잠금 경합이 많거나 많은 제약 조건, 규칙, 인덱스가 있으며 테이블이 매우 넓다고 생각합니다. 당신은 DBA가 테이블 삽입 기술을 심각하게보아야하고 병행 성이 부족한 것이 병목 현상이 아닙니다 : ( – StuartLC

4

당신이 정확하게 당신이 할 수있는 저장 프로 시저에 사용하면 데이터 테이블

CREATE TYPE EmpType AS TABLE 
(
    ID INT, Name VARCHAR(3000), Address VARCHAR(8000), Operation SMALLINT //your columns 
) 

와 일치하는 테이블 유형을 만들 필요가

데이터베이스에
obj_AseCommand.CommandText = sql_proc; 
obj_AseCommand.CommandType = CommandType.StoredProcedure; 
obj_AseCommand.Connection = db_Conn; 
obj_AseCommand.Connection.Open(); 
obj_AseCommand.Parameters.AddWithValue("@Parametername",DataTable); 
obj_AseCommand.ExecuteNonQuery(); 

데이터베이스에 전체 데이터 테이블을 통과하는 것이 좋습니다 다음과 같이하십시오.

create PROCEDURE demo 

@Details EmpType READONLY // it must be read only 
AS 
BEGIN 
    insert into yourtable //insert data 
    select * from @Details 
    END 
0

Sq 당신은 SqlBulkCopy을 사용할 수 있습니다 lBulkCopy

가이드는 here

+0

이것은 답변보다 더 많은 코멘트입니다 – 3dd

+0

Ok 죄송합니다, 저는 새로운 사용자입니다 :) –

+2

좋은 답변이 아니더라도 유효한 대답입니다. 이유 및 방법에 대한 설명을 추가하면 개선 될 수 있습니다. –

3

입니다. 아래 샘플 코드를 참조하십시오. 왜 저장 프로 시저와 함께 데이터베이스에 3000 개 행을 추가합니다 - WriteToServer 방법은, 그들은 같은 매핑 그냥 호기심 중

using (SqlBulkCopy bulkCopy = new SqlBulkCopy(ConSQL)) { 
if (ConSQL.State == ConnectionState.Closed) { 
    ConSQL.Open(); 
} 

bulkCopy.ColumnMappings.Add(0, 0); 
bulkCopy.ColumnMappings.Add(1, 1); 
bulkCopy.ColumnMappings.Add(2, 2); 

bulkCopy.DestinationTableName = "dbo.TableName"; 

bulkCopy.WriteToServer(dataTable); 

bulkCopy.Close(); //redundant - since using will dispose the object 

}