2016-08-14 3 views
2

여러 CSV 파일에서 가져온 데이터로드를 관리하기 위해 응용 프로그램에서 TClientDataSet을 사용하고 있습니다. 이것은 전체적으로 백만 이상의 항목 일 수 있습니다. 특정 CSV 파일과 관련된 모든 데이터 세트 항목을 삭제할 수 있기를 원하지만 많은 수의 항목을 삭제하는 데 시간이 많이 걸립니다.Delphi ClientDataSet - 삭제 작업 - 왜 그렇게 느린가요?

내가 바보 같은 짓을하고 있다면 테스트 해보고 간단한 콘솔 응용 프로그램을 만들었습니다. 그것은 이라곤이다

CDS := TClientDataSet.Create(nil); CDS.FieldDefs.Add('ID', ftInteger); CDS.CreateDataSet; CDS.LogChanges := False;

  • 추가] 100,000 항목 (얻어 0.1 초) :

    for i := 1 to 100000 do begin CDS.AppendRecord([i]); end;

    • 정의 1 개 필드와 TClientDataSet의 인스턴스 (ID)를 만들기

    • 50,000 개 항목 삭제 (~ 4 초 또는 LogChanges=TRUE ~ 4.4 초 소요) :

    CDS.First; while CDS['ID'] <= 50000 do CDS.Delete;

    나는 내 데이터 세트에서 1.5M 항목이 있고 0.5M 항목 그것이 내가도를 측정 할 수있는이 방법으로 항목을 삭제 너무 오래 걸릴 것을 제거하고 싶어합니다.

    지금 해결 방법으로 새 ​​데이터 세트를 만든 다음 보관하려는 모든 항목을 새 복사본으로 복사하고 원본 복사본을 삭제해야합니다. 원래 데이터 집합의 항목 중 일부만 제거하는 것이 아니라면이 방법이 훨씬 빠릅니다.

    아마 데이터 집합에서 항목을 제거하는 데 가장 적절한 방법을 사용하지 않겠습니까? 내가 삭제 한 모든 항목에 대해 일련의 내부 처리가 트리거되고 있다고 생각합니다. 한번에 누락 된 항목을 삭제하는 방법이 있습니까? 아마도 인덱스를 기반으로 인덱스와 범위를 설정 한 다음 한 번의 작업으로 현재 범위의 모든 항목을 삭제할 수 있습니까?

    아마 ClientDataSet이 문제일까요? 아마도 다른 구성 요소를 사용해야 할 것입니다. 어떤 제안?

    +1

    아마도 ['LogChanges'] (http://docwiki.embarcadero.com/Libraries/Berlin/en/Datasnap.DBClient.TCustomClientDataSet.LogChanges)를 끄는 것을 잊었을 것입니다. –

    +0

    델타를 유지하는 것이 저렴하지 않기 때문에 흥미로운 점이 있습니다. –

    +0

    집계 및 색인을 언급 했으므로 이러한 문제가 원인 일 수 있습니다. 벌크 삭제 작업 전에 비활성화하고 다시 필요할 때 다시 활성화하십시오. (문제는 매번 삭제가 끝날 때마다 완전히 불필요한 업데이트가 발생하는 것일 수 있습니다.) –

    답변

    1

    생각 나는 똑같은 문제가있는 사람이 관심을 가지기 때문에 내 자신의 (일시적인/아마도 영구적 인) 해결 방법의 세부 사항을 제공 할 수도 있습니다.

    문제 : 큰 TClientDataSet (100k 이상의 레코드)에서 레코드의 많은 부분을 삭제하면 삭제 작업을 사용할 때 항목을 추가하는 초기 시간 (40 분의 1 이상)과 비교할 때 시간이 오래 걸립니다.

    해결 방법 : 삭제하지 않으려는 모든 레코드를 새 데이터 세트로 복사 한 다음 원본을 삭제하십시오. [단점 : 변경점 손실, 추가적인 RAM 요건]

    var 
    CDS: TClientDataSet; 
    
    // initialize new CDS instance 
    function CreateNewCDSInstance: TCLientDataSet; 
    begin 
    Result := TClientDataSet.Create(nil); 
    Result.FieldDefs.Add('ID', ftInteger); 
    Result.CreateDataSet; 
    Result.LogChanges := False; 
    end; 
    
    // close + free CDS instance 
    procedure CloseCDS; 
    begin 
    CDS.EmptyDataSet; 
    CDS.Close; 
    CDS.Free; 
    end; 
    
    // delete current record? 
    function CanDeleteCurrentRecord: boolean; 
    begin 
    Result := CDS['ID'] < 50001; //in this simple example 
    // in my application it would be more like: 
    // "CDS['FILE_ID'] = AFileIDToDelete" 
    end; 
    
    // delete block of records: 
    procedure DeleteRecords; 
    var 
    aNewCopy: TClientDataSet; 
    begin 
    aNewCopy := CreateNewCDSInstance; 
    CDS.First; 
    while not CDS.EoF do 
    begin 
        if not CanDeleteCurrentRecord then 
        begin 
        // NB: AppendRecord takes array of values corresponding to field defintions 
        aNewCopy.AppendRecord([CDS['ID']]); 
        end; 
        CDS.Next; 
    end; 
    CloseCDS; 
    CDS := aNewCopy; 
    //NB: If you have any aggregates/indexes defined, they must be redefined 
    end; 
    

    50K 항목을 제거하는 방법이 상기 제공된 예를 사용하는 대신 ~ 4 초 94 밀리 초 걸린다.

    그러나이 질문을하고 의견을 읽으면서이 솔루션은 치료법보다 붕대에 더 가깝다는 것을 알게되었습니다. 더 큰 문제는 내가 작업하고있는 시스템이 필요한 데이터의 양을 처리 할 수 ​​있도록 설계되지 않았기 때문입니다. 아마도 "TClientDataSet의 문제"가 "TClientDataSet을 사용하는 방식의 문제"가 아닐 수도 있습니다!삭제 속도에 대한 수정이 있어도 점점 더 많은 파일의 크기와 양을 가져 와서 해당 데이터를 관리하는 성능 문제는 여전히 남아 있습니다.

    어쩌면 비오는 날에 모든 데이터를 하나의 거대한 메모리 테이블로 튀기는 대신 가져온 각 파일을 보관하기 위해 별도의 데이터 집합을 사용하는 SilverWarior의 제안과 유사한 접근 방식을 살펴볼 것입니다. 그런 다음 파일을 삭제하면 데이터 세트가 삭제되므로 다른 잠재적 이점이 있습니다.

    관련 문제