2012-09-19 2 views
5

"upsert"유형의 질문이 있습니다. 그러나 내가 읽은 것보다 조금 다르기 때문에 거기에 버리고 싶습니다. 스택 오버플로.Postgres에서 레코드가 변경되었는지 확인하는 방법

기본 문제.

저는 MySQL에서 PostgreSQL 9.1.5 (Heroku에서 호스팅 됨)로 이동 중입니다. 그 일환으로 매일 여러 개의 CSV 파일을 가져와야합니다. 일부 데이터는 판매 정보이며 거의 새 것으로 보장되어 삽입해야합니다. 그러나 데이터의 다른 부분은 거의 동일하게 보장됩니다. 예를 들어 csv 파일 (복수 인용)은 POS (point of sale) 정보를 갖습니다. 이것은 거의 변경되지 않으며 추가를 통해서만 가능합니다. 그런 다음 제품 정보가 있습니다. 약 10,000 개의 제품이 있습니다 (대다수는 변경되지 않지만 추가 및 업데이트가 가능합니다).

마지막 항목 (중요 함)은 주어진 항목에 대한 감사 내역/정보를 제공 할 수 있어야한다는 것입니다. 예를 들어, 새 POS 레코드를 추가 할 경우 해당 레코드를 찾은 파일로 추적 할 수 있어야합니다. UPC 코드 나 제품 설명을 변경하면 다시 추적 할 수 있어야합니다 변경 사항이 발생한 가져 오기 (및 파일).

제가 생각하고있는 솔루션입니다.

데이터가 CSV를 통해 나에게 제공되었으므로 COPY가 가장 빠른/가장 빠른 방법이라는 생각을 가지고 작업하고 있습니다. 파일의 데이터 구조가 데이터베이스 (예 : 최종 목적지)에있는 것과 정확하게 일치하지 않습니다. 그래서 CSV와 일치하는 스테이징 스키마의 테이블에 이들을 복사합니다 (참고 : 데이터 소스 당 하나의 스키마). 스테이징 스키마의 테이블에는 삽입 이전 행 트리거가 있습니다. 이러한 트리거는 데이터로 수행 할 작업 (삽입, 업데이트 또는 무시)을 결정할 수 있습니다.

새 데이터를 포함 할 가능성이 가장 높은 테이블의 경우 먼저 삽입하려고 시도합니다. 레코드가 이미 있으면 NULL을 리턴하고 스테이징 테이블에 삽입을 중지합니다. 드물게 변경되는 테이블의 경우 테이블을 쿼리하고 레코드가 있는지 확인합니다. 그렇다면 필드가 변경되었는지 확인할 수있는 방법이 필요합니다. (기억하기 때문에, 레코드가 y 파일에서 import x에 의해 수정되었다는 것을 보여줄 필요가있다.) 분명히 코드를 보일러 판에 써서 각 열을 테스트 할 수있다. 그러나, 그것보다 조금 더 "웅변"이고 유지 보수가 가능한 것을 찾고있었습니다.

내가하는 일은 가져 오기 시스템과 감사 추적 시스템을 결합하는 것입니다. 따라서 감사 추적 조사에서 다음과 같은 내용을 검토했습니다. wiki.postgresql.org hstore가 변경 사항을 얻을 수있는 좋은 방법 인 것 같습니다 (예 : "last_modified"와 같이 중요하지 않은 테이블의 일부 열을 쉽게 무시할 수 있음)

나는 그것이 모두 작동 ... 나는 몇 가지 테스트 테이블 등을 만들었고 함께 놀았습니다.

내 질문에?

데이터베이스를 변경해야하는 10K 중에서 어쩌면 3 개의 레코드를 찾는이 작업을 더 잘 유지 관리 할 수있는 방법입니다. 필자는 파일을 읽고 각 레코드로 무엇을해야 할지를 알아 내려고하는 파이썬 스크립트 (또는 다른 것)를 작성할 수는 있지만 그다지 비효율적이며 왕복 여행을 많이하게 될 것입니다.

몇 마지막 일이 :

  1. 나는 입력 파일을 제어 할 수 없습니다. 그들이 삼각주 만 보냈다면 나는 그것을 좋아할 것이다. 그러나 그들은 그렇게하지 않는다. 그리고 그것은 나의 통제 또는 영향에서 완전히 벗어났다.
  2. 그는 시스템이 커지면서 새로운 데이터 소스가 추가되어 처리되는 데이터의 양이 크게 늘어날 수 있습니다. (따라서 작업을 효율적으로 유지하려고 노력하고 있습니다)
  3. 질문 ("파이썬으로 목록을 정렬하는 방법"과 같은)을 사용하지만, 저는 여러분이 어려운 질문을 할 수 있고 사람들이 어떻게 해결할 수있는 최선의 방법이라고 생각하는지에 대한 생각을 공유 할 것이라는 점에서 위대한 사안 중 하나가 있다고 생각합니다.
+0

2 가지 질문 : 1) 삭제 했습니까? 입력이 "증분"입니까? 2) 데이터 보호 공급자 * 안정적인 키 * (키 업데이트 없음)의 공급자가 될 수 있습니까? – wildplasser

+0

데이터 소스 및 데이터 유형에 따라 다양합니다. 데이터를 처리 할 때 "방어적인"자세를 취해야하며, 무엇이든 준비가되어 있어야합니다.즉, 나는 삭제할 수 있다고 생각하지만 (드문 경우), 키 *가 안정되어야한다고 생각합니다 (즉, POS 레코드의 ID는 업로드간에 동일하게 유지되어야합니다). –

답변

7

비슷한 작업이 많이 있습니다. - 임시 ANALYZE 실행

CREATE TEMP TABLE target_tmp AS 
SELECT * FROM target_tbl LIMIT 0; -- only copy structure, no data 

COPY target_tmp FROM '/path/to/target.csv'; 

의 성능을 : 내가하는 일은 COPY임시 스테이징 테이블입니다. 테이블은 자동 진공으로 분석되지 않습니다!

ANALYZE target_tmp; 

또한 성능을 위해 임시 테이블에 인덱스 또는 2 개를 만들거나 데이터에서 허용하는 경우 기본 키를 추가 할 수도 있습니다.

ALTER TABLE ADD CONSTRAINT target_tmp_pkey PRIMARY KEY(target_id); 

작은 가져 오기에는 성능이 필요하지 않습니다.

그런 다음 전체 SQL 명령 범위를 사용하여 새 데이터를 요약합니다. 예를 들어
, 목표 테이블의 기본 키가 target_id 경우 ..

어쩌면 DELETE가없는 더 이상 무엇을?

DELETE FROM target_tbl t 
WHERE NOT EXISTS (
    SELECT 1 FROM target_tmp t1 
    WHERE t1.target_id = t.target_id 
); 

그런 다음 UPDATE은 이미 무엇을 : 전체 행이 관련이있는 경우,

... 
AND col1 IS DISTINCT FROM t1.col1; -- repeat for relevant columns 

을 또는 :

UPDATE target_tbl t 
SET col1 = t1.col1 
FROM target_tmp t1 
WHERE t.target_id = t1.target_id 

업데이트를 피하려면 추가

새로운 기능 그리고

INSERT : 세션이 (임시 테이블이 자동으로 세션의 끝에서 삭제됩니다)에가는 경우

INSERT INTO target_tbl(target_id, col1) 
SELECT t1.target_id, t1.col1 
FROM target_tmp t1 
LEFT JOIN target_tbl t USING (target_id) 
WHERE t.target_id IS NULL; 

정리 :

DROP TABLE target_tmp; 

또는 함께 ON COMMIT DROP 또는 유사한을 사용하여 CREATE TEMP TABLE.
코드는 테스트되지 않았지만 오타를 제외한 최신 버전의 PostgreSQL에서 작동해야합니다.

+0

답장을 보내 주셔서 감사합니다. 좋은 본보기/세부 사항; 이것이 어떤 사람들을 도울 것이라고 확신합니다. 그리고 그것은 내가해야 할 일에 매우 가깝습니다. 나를 얻는 하나의 요구 사항은 "일괄 ID"가져 오기를 추적하여 실제로 레코드를 변경하는 것입니다. 다시 말해, 나는 항상 레코드를 새로 고치거나 레코드를 새로 고치고 싶지 않습니다. 변경 사항이있는 경우에만 업데이트합니다. 내가 할 수있을 것 같아. 그런 다음 테이블에 업데이트 트리거를 설정하고 레코드가 실제로 변경된 경우이를 확인하십시오. 그렇다면 감사 추적 레코드를 추가하십시오. 합리적으로 보입니까? 더 좋은 방법이 있니? –

+0

@DavidS : 예상보다 간단 할 수 있습니다. 나는 UPDATE 섹션에 약간을 추가했다. 어쨌든 빈 업데이트를 제외하는 것이 거의 항상 좋은 생각입니다. 감사 추적이 필요하면'DELETE' /'UPDATE' 전에 오래된 버전 (타임 스탬프 포함)을 히스토리 테이블에 복사하는 것이 좋습니다. –

+0

좋은 의견과 답변을 업데이트 해 주셔서 감사합니다. 감사를 위해 hstore (x. *)를 사용하여 archive_table (데이터 + 타임 스탬프의 전체 사본)을 복사하여 audit_trail/history 유형 테이블의 텍스트 필드에 저장하는 것을 선호하십니까? 아카이브 테이블의 주요 장점은 쉽게 쿼리 할 수 ​​있다는 것입니다. hstore 접근법의 주요 장점은 스키마가 변경되면 유연성이있는 것 같습니다. 나는 주제가 약간 떨어져서 자신의 질문 일 수 있지만 당신의 생각에 호기심이 있다는 것을 압니다. 감사! –

관련 문제