2009-05-05 2 views
2

자주 검색하고 수정할 데이터를 만들고 저장하는 가장 좋은 방법은 무엇입니까?Delphi에서 대용량 데이터 세트를 자주 저장, 검색 및 수정하는 가장 좋은 방법

기본적으로 기존 데이터베이스에서 전화 번호를 검색하고 각 전화 번호가 사용 된 횟수, 사용 된 첫 번째 날짜 및 사용 된 최신 날짜를 추적하는 기능을 작성하고자합니다. 검색중인 데이터베이스는 기본적으로 주문을 처리하는 데 사용 된 전화 번호가 들어있는 주문의 로그입니다. 그것은 SQL 데이터베이스 또는 그러한 것들 (그것은 오래된 btrieve 데이터베이스)에 대해 쉽게 쿼리 할 수있는 것이 아니므로이 정보를 얻는 방법을 만들어야합니다 (결국 텍스트 파일로 출력).

전화 번호, 두 날짜 및 사용 된 횟수를 포함하는 레코드를 만든 다음 각 전화 번호에 대한 동적 배열에 레코드를 추가 할 생각입니다. 그런 다음 데이터베이스의 각 레코드에 대해 항목별로 항목을 검색하여 현재 레코드의 전화 번호가 이미 배열에 있는지 확인합니다. 그런 다음 필요에 따라 레코드를 업데이트하거나 만듭니다.

이것은 작동하는 것처럼 보이지만 데이터베이스에 수만 개의 항목이 있기 때문에 최선의 방법이 아니며 오히려 느리고 비효율적 인 방식으로 작동하지 않을 수 있습니다. 데이터베이스에서 수행 할 수있는 제한된 조치를 감안할 때 더 좋은 방법이 있습니까?

누군가는 배열을 사용하는 대신 MySQL 테이블을 사용하여 숫자를 추적하고 모든 데이터베이스 레코드에 대해 각 번호를 쿼리 할 것을 제안했습니다. 이것은 더 많은 오버 헤드처럼 보입니다!

시간 내 주셔서 감사합니다.

+0

데이터를 여러 번 검색해야하며 오랜 기간 유지해야합니까?또는 청크를 읽고 검색 한 다음 던져 버리면 다시 사용할 수 없습니까? –

답변

0

죄송합니다. 내 게시물을 편집 할 수 없습니다 (당시 등록되지 않았습니다). 데이터베이스의 모든 레코드가 반복되면 데이터가 버려집니다. 이 함수는 자주 호출되지 않습니다. 그것은 기본적으로 사람들이 우리가 이미 가지고있는 기록으로부터 일정 기간 동안 주문한 빈도를 결정하는 방법으로 사용되기 때문에 실제로 목록을 만들지 않아도됩니다.

데이터는 목록 작성 기간 동안 지속됩니다. 즉, 마지막 데이터베이스 레코드를 읽을 때까지 모든 전화 번호를 검색해야합니다.

1

전적으로 연결이 끊긴 TClientDataset (cds)에 집계를 등록하고 루프에서 값을 가져올 때 값을 업데이트합니다. Btrieve를 전화 번호별로 정렬 할 수 있다면 훨씬 좋습니다. 그런 다음 CD의 데이터를 사용하여 보고서를 생성하십시오.

(이 방법을 사용하는 경우 다른 유용한 정보와 함께 Andreas Hausladen' blog에서 Midas SpeedFix을 얻는 것이 좋습니다.)

0

메모리에 보관하고 멋진 것을 원하지 않는다면 찾기 기능을 사용할 수 있도록 TStringList를 사용하는 것이 좋습니다. 찾기는 Hoare의 선택 또는 O (n) 로케이터 인 빠른 선택을 사용합니다. 거기에 다음

type 
    TPhoneData = class 
     private 
     fPhone:string; 
     fFirstCalledDate:TDateTime; 
     fLastCalledDate:TDateTime; 
     fCallCount:integer; 
     public 
     constructor Create(phone:string; firstDate, lastDate:TDateTime); 
     procedure updateCallData(date:TDateTime); 
     property phoneNumber:string read fPhone write fPhone; 
     property firstCalledDate:TDateTime read fFirstCalledDate write fFirstCalledDate; 
     property lastCalledDate:TDateTime read fLastCalledDate write fLastCalledDate; 
     property callCount:integer read fCallCount write fCallCount; 
     end; 

{ TPhoneData } 

constructor TPhoneData.Create(phone: string; firstDate, lastDate: TDateTime); 
begin 
fCallCount:=1; 
fFirstCalledDate:=firstDate; 
fLastCalledDate:=lastDate; 
fPhone:=phone; 
end; 

procedure TPhoneData.updateCallData(date: TDateTime); 
begin 
inc(fCallCount); 
if fFirstCalledDate<date then fFirstCalledDate:=date; 
if date>fLastCalledDate then fLastCalledDate:=date; 
end; 

하고 작성 보고서 : 예를 들어, 유형을 정의

procedure TForm1.btnSortExampleClick(Sender: TObject); 
const phoneSeed:array[0..9] of string = ('111-111-1111','222-222-2222','333-333-3333','444-444-4444','555-555-5555','666-666-6666','777-777-7777','888-888-8888','999-999-9999','000-000-0000'); 

var TSL:TStringList; 
    TPD:TPhoneData; 
    i,index:integer; 
    phone:string; 
begin 
randseed; 
TSL:=TStringList.Create; 
TSL.Sorted:=true; 
for i := 0 to 100 do 
    begin 
    phone:=phoneSeed[random(9)]; 
    if TSL.Find(phone, index) then 
     TPhoneData(TSL.Objects[index]).updateCallData(now-random(100)) 
    else 
     TSL.AddObject(phone,TPhoneData.Create(phone,now,now)); 
    end; 
for i := 0 to 9 do 
    begin 
    if TSL.Find(phoneSeed[i], index) then 
     begin 
     TPD:=TPhoneData(TSL.Objects[index]); 
     ShowMessage(Format('Phone # %s, first called %s, last called %s, num calls %d', [TPD.PhoneNumber, FormatDateTime('mm-dd-yyyy',TPD.firstCalledDate), FormatDateTime('mm-dd-yyyy',TPD.lastCalledDate), TPD.callCount])); 
     end; 
    end; 
end; 
1

좋아, 여기에 잘 작동 잘 확장한다 이중 패스 구식 방법 (I입니다 이 접근법을 수백만 레코드 데이터베이스에 대해 한 번 사용했으나 시간이 걸리지 만 정확한 결과를 제공했습니다.)이 프로세스에 대해 아주 잘 작동 정렬 엔진 -

  1. 다운로드 터보 파워 SysTools를 설치합니다.
  2. 전화 번호가 고정 된 레코드 인 정렬을 만들려면 이것을 사용합니다.
  3. 레코드를 반복하면서 각 주문에 전화 번호를 정렬에 추가하십시오. 전화 번호가 마지막 한 읽기와 같은 경우
  4. 첫 번째 반복이 완료되면, 시작 종류에서 전화 번호를 보여주고, 그렇지 않으면 수를보고하고 카운터를 취소 카운터를 증가.

이 프로세스는 또한 모든 SQL 데이터베이스를 사용하여 수행 할 수 있지만 내 경험에 의하면 정렬 방법은 임시 테이블을 관리하는 것보다 빠르며 동일한 결과를 생성합니다.

EDIT - BTrieve 데이터베이스라고 말했습니까? 전화 번호에 키를 만든 다음 해당 키를 정렬하고이 테이블 (팝업 대신에 다음 단계)에 4 단계를 적용하는 것이 좋습니다. 어떤 방법 으로든 데이터베이스의 모든 레코드를 만져서 수를 늘려야하는 경우 색인/정렬을 사용하면 의사 결정 프로세스가 쉬워집니다.

예를 들어 고객 테이블에 결과가 저장 될 테이블과 다른 주문 테이블이있는 두 개의 테이블이 있다고 가정 해 보겠습니다. 두 전화 번호를 같은 전화 번호로 정렬하십시오. 그런 다음 두 목록의 상단에 커서를 시작하고 다음 psuedocode 적용

Count := 0; 
While (CustomerTable <> eof) and (OrderTable <> eof) do 
    begin 
    comp = comparetext(customer.phone, order.phone); 
    while (comp = 0) and (not orderTable eof) do 
     begin 
     inc(Count); 
     order.next; 
     comp = comparetext(customer.phone, order.phone); 
     end; 
    if comp < 0 then 
     begin 
     Customer.TotalCount = count; 
     save customer; 
     count := 0; 
     Customer.next; 
     end 
    else if (Comp > 0) and (not OrderTable EOF) then 
     begin 
     Order.Next; // order no customer 
     end; 
    end; 

// handle case where end of orders reached 
if (OrdersTable EOF) and (not CustomersTable EOF) then 
    begin 
    Customer.TotalCount = count; 
    save customer; 
    end; 

이 코드는 한 번에 두 목록을 걷는 이점이 있습니다. 두 목록이 모두 정렬되어 있기 때문에 필요한 조회가 없으므로 필요할 때만 조치를 취하여 위에서 아래로 걸을 수 있습니다. 유일한 요구 사항은 두 목록 모두 공통점이 있고 (이 예제에서는 전화 번호) 두 목록을 모두 정렬 할 수 있다는 것입니다.

주문이 있고 고객이없는 경우를 처리하지 못했습니다. 내 가정은 주문이 고객 없이는 존재하지 않으며 계산을 위해 건너 뛸 수 있다는 것입니다.

0

TStringList 대신에 DeCAL's (sf.net에서) DMap을 사용하여 메모리에 항목을 저장하는 것이 좋습니다. 전화가 키임을 지정하고 나머지 레코드가 들어있는 레코드/클래스 구조를 저장할 수 있습니다.

그래서 기록 클래스는 다음과 같습니다 코드에서 다음


    TPhoneData = class 
    number: string; 
    access_count: integer; 
    added: TDateTime. 
    ... 
    end; 

을 : 데이터 구조가 무료로 당신을 위해 키를 정렬 있도록


    procedure TSomeClass.RegisterPhone(number, phoneData); 
    begin 
    //FStore created in Constructor as FStore := DMap.Create; 
    FStore.putPair([number, phoneData]) 
    end; 
    ... 
    procedure TSoemClass.GetPhoneAndIncrement(number); 
    var 
    Iter: DIterator; 
    lPhoneData: TPhoneData; 
    begin 
    Iter := FStore.locate([number]); 
    if atEnd(Iter) then 
     raise Exception.CreateFmt('Number %s not found',[number]) 
    else 
    begin 
     lPhoneData := GetObject(Iter) as TPhoneData; 
     lPhoneData.access_count = lPhoneData.access_count + 1; 
     //no need to save back to FStore as it holds a pointer to lPhoneData 
    end; 
    end; 

DMAP은 빨강/블랙 트리를 구현합니다. 같은 효과와 (아마도) 증가 된 속도로 DHashMap을 사용할 수도 있습니다.

DeCAL은 제가 가장 좋아하는 데이터 구조 라이브러리 중 하나입니다. DeCAL은 누구든지 메모리 내 저장 작업을 수행 할 것을 권합니다.

도움이 되길 바랍니다.

관련 문제