Q&A

  • 아..아주 난감한 상황입니다. Insert를 어떻게 시켜야 빨리 될지..게다가 에러처리는..ㅠㅠ
Firebird와 Zeos를 사용하고 있는데요, 테이블에는 기존에 1000만껀의 레코드가 들어있는 상황입니다.

제가 시도했던 것부터 말씀드리면,

처음에는 TZTable.append를 사용해서 데이타를 넣었는데 그때는 그래도 괜찮았습니다. 그런데, 이제 데이타가 들어있는 상태에서 그것을 실행하려니 이게 속도가 장난아니게 떨어지는 겁니다.

그래서, TZQuery.append를 사용해서 데이타를 넣어보았는데 에러가 발생할 때 라이브러리 내부에서 무한루프를 도는 어이없는 씨츄에이션 발생하여, 이것도 포기...

마지막으로 TZQuery.ExecSQL을 사용하려고 하는데, ..

가장 문제가 되는 것은...추가로 넣으려는 데이타가 기존 것과 중복되는 것도 있다는 것입니다. 따라서, 기존 데이타베이스에 이미 중복된 넘이 들어있으면 그건 넣지 말거나 또는 새로운 것으로 대체하고 오류는 제껴버리면서 추가하고자 하는 데이타를 마지막것까지 다 넣는 것이죠.

TZTable에서 OnPostError를 쓸 때는 정상적으로 에러 처리가 잘 되지만, 그걸 사용하면 테이블을 모두 불어들이는 상황이 발생하므로 이제는 쓸 수가 없습니다. 결국 TZQuery를 사용해서 데이타를 입력할 수 밖에 없는 상황인데(혹시 제가 모르는 다른 입력 방법이 있나요?) TZQuery.Append는 OnPostError핸들러로 들어만 가면 무한루프에 빠져들어 버리거나 'Internal Error'라는 희한한 에러를 내고 죽어버리고..

TZQuery.ExecSQL로 실행할때는 OnPostError는 들어가지도 않고..ㅠㅠ

빨리 넣는 방법도 중요하고, 무엇보다 중복된 값이 들어가려고 할때 그것을 어떻게 처리할 것인가를 정해서 내부적으로 오류를 처리해서 입력작업을 계속 수행하는 ...그 방법....그것을 여쭤봅니다. ㅠㅠ

이게 진행이 안되니 다음 단계로 전혀 갈 수 없는 상황이네요. 어흑....
2  COMMENTS
  • Profile
    이중철 2005.10.28 02:57
    다른 DB에서는 Tempary Table을 지원합니다.
    전 주로 Informix 와 Sybase에서 사용했죠 오라클에는 없었어요(Version 6)
    이것을 이용한 방법인데
    Tempary Table(Drop하지 않아도 Session이 끊어지면 사라지는 테이블)이 없더라도 사용은 가능합니다.
    그냥 실제 Table을 만들면 되니깐요
    프로그램에서 입력하기 전에 클론 TABLE을 만듭니다.

    1. 입력할 테이블과 똑같은 구조의 테이블을 만든다. (CLON_TABLE 라고 정하자)
      - 인덱스는 없애는것이 좋습니다.

    2. 입력할 데이터의 중복성 검사를 한다.(저장할려고 하는 데이터 내의 중복 데이터 삭제)
      - DB가 아니라 로컬의 입력할 데이터중에서 입니다.

    3.  CRON_TABLE에 입력할 데이터를 입력한다. ( TTABLE도 좋고 TQUERY도 좋고)

    4. CRON_TABLE을 본래의 테이블에 입력한다 (본래 테이블 을 ORIGIN_TABLE 라고 정하자)

    4-1.  CRON_TABLE의 내용을 ORIGIN_TABLE에 저장합시다.(PRIMARY KEY Field는 KEY1, KEY2 라고 합시다)
      - EXECSQL로 하시면 됩니다. 다음과 같이요
       INSERT INTO ORIGIN_TABLE
       SELECT * FROM CRON_TABLE A WHERE NOT EXISTS
       (SELECT * FROM ORIGIN_TABLE B WHERE A.KEY1 = B.KEY1 AND A.KEY2 = B.KEY2)

    5. CRON_TABLE을 DROP 합는다.

    이 방법은 아주 고전적인 방법이에요 벌크 인서트하기 곤란할 때 와 본 테이블에 키가 많고 데이터가
    많을경우(약 100여건 .. 그 이상은 벌크가 좋죠) 하는 방법입니다.


  • Profile
    토니 2005.10.28 07:03
    네, 임시테이블에 데이타를 넣었다가 원테이블에 넣는 것을 설명해 주셨네요.

    제가 현재 처한 상황을 설명하자면, 기존에 들어있는 1천만(1천이 아니라  10000000)개의 레코드에 추가로 보통 최소 4,5천개 많으면 3,4만개의 데이타를 한꺼번에 추가로 집어넣습니다. 그런데 소스데이타 자체가 중복된 것들이 간간히 껴있어서 그걸 발견해 내서 빼내는 것도 일인 거 같습니다.(텍스트화일이라..쿨럭) 그리고 간혹 어떤 소스데이타 화일을 한꺼번에 입력을 시켜야만 하는데(데이타의 구분 단위 등의 특성때문에) 그게 일부는 DB에 들어가 있고 일부는 빠져있고(여러가지 원인으로 그러한 상태로 되어있더라구요..쩝) 그래서 기존에 들어있는 것은 그대로 놔두고 없는 것만 계속 넣어야 합니다.

    그러다보니 소스데이타를 정리해서 넣는 것도 만만치 않지만, 무엇보다 지금 넣으려는 데이타가 기존에 들어있는 지를 일일이 파악하는게 만만치 않은 일이라 그저 일단 밀어넣으면서 키값이 중복되면 무시하고 다음 레코드를 집어넣도록 하는 그런 식으로 처리하려는 것인데요,

    일단은 뽀록으로 해결은 대략 했습니다.

    처음엔
    <!--CodeS-->
    ...
    try
      while ... do begin
      ...
      ...
      qry.ExecSQL;
      ...
      end;
    finally
    ...
    end;

    procedure TForm1.qryPostError(..)
    ..
    <!--CodeE-->

    와 같은 구조로 처리했는데 에러 발생시 이벤트 발생을 쿼리 오브젝트에선 제대로 못하거나 이상한 오류를 발생시켜서 결국엔

    <!--CodeS-->
    while...do begin
    ...
      try
         qry.ExecSQL;
      except
         ...
      end;
    end;
    <!--CodeE-->
    와 같이 exception을 가로채서 에러에 대한 처리를 한 후(사실은 아무런 처리없이 걍 무시하는 걸로 했습니다. ^^:) while문을 계속 돌게했더니 이젠 루프는 제대로 돌게 만들었습니다.
    물론, 일전에 테스트를 해보니 TQuery.Append를 사용하는게 ExecSQL로 insert하는 것보다 빨랐지만, 이미 천만개가 넘는 데이타가 들어있는 상태라 TTable도 사용할 수 없고 TQuery.Append에선 에러 이벤트 핸들러가 이상하게 작동하고 해서 결국은 ExecSQL로 처리했습니다. 걍 입력에 걸리는 시간은 포기하는 걸로...ㅠㅠ

    자상한 답변에 다시 한번 감사드립니다.