2011-03-05 3 views
4

행당 ~ 1800 개의 레코드가있는 고정 폭 원본 파일이 있습니다.COPY FROM stdin을 사용하여 테이블을로드하고 입력 파일을 한 번만 읽음

이 파일을 Postgres 8.3.9의 인스턴스에서 5 개의 다른 테이블에로드해야합니다.

내 딜레마는 파일이 너무 크기 때문에 한 번만 읽어야한다는 것입니다.

이것은 일반적으로 INSERT 또는 COPY를 사용하여 충분히 간단하지만 TRUNCATE를 포함하는 트랜잭션에 COPY FROM 문을 포함하여로드 속도 향상을 얻으려고합니다. 로깅을 피하는 것이 좋습니다. 상당한 부하 속도 증가 (http://www.cirrusql.com/node/3에 따라). 내가 이해하는 한, Postgres 9.x에서 로깅을 비활성화 할 수 있지만 8.3.9에서는 옵션이 없습니다.

아래 스크립트는 필자가 입력 파일을 두 번 읽는 것을 말합니다. 필자는 입력 파일을 한 번만 읽음으로써이를 수행 할 수있는 방법을 피하고 싶습니다. 배시 일 필요는 없습니다. psycopg2를 사용해 보았습니다 만, 아래에 나와있는 것처럼 파일 출력을 COPY 문으로 스트리밍하는 방법을 알 수 없습니다. 나는 그것을 즉시 구문 분석해야하기 때문에 파일에서 복사 할 수 없습니다.

#!/bin/bash 

table1="copytest1" 
table2="copytest2" 

#note: $1 refers to the first argument used when invoking this script 
#which should be the location of the file one wishes to have python 
#parse and stream out into psql to be copied into the data tables 

(echo 'BEGIN;' 
    echo 'TRUNCATE TABLE ' ${table1} ';' 
    echo 'COPY ' ${table1} ' FROM STDIN' 
    echo "WITH NULL AS '';" 
    cat $1 | python2.5 ~/parse_${table1}.py 
    echo '\.' 
    echo 'TRUNCATE TABLE ' ${table2} ';' 
    echo 'COPY ' ${table2} ' FROM STDIN' 
    echo "WITH NULL AS '';" 
    cat $1 | python2.5 ~/parse_${table2}.py 
    echo '\.' 
    echo 'COMMIT;' 
) | psql -U postgres -h chewy.somehost.com -p 5473 -d db_name 

exit 0 

고마워요!

+0

나는 Python에서 파싱을 사용하고 STDIN을 통해 PostgreSQL로 스트리밍을 사용하여 비슷한 것을 구현했습니다. 나는 PSYCOPG2를 사용하지 않고 추한 방법으로 해냈습니다. 내 문제는 내가 당신의 코드를 이해하지 못한다는 것이다. 이 코드는 어떻게 5 가지 테이블에 무언가를로드 할 수 있습니까? 파이썬 프로그램에서 무슨 일이 일어나고 있는지. – David

+0

안녕하세요 @ David - 미안하지만 분명히해야합니다. 위의 코드는 5 대신 2 개의 표만 사용하는 단순화 된 예제입니다. @ 존 바움의 유용한 팁을 토대로 위의 방식을 버렸습니다. 아래를 참조하십시오. 위에서 말한 내용에 관해서는 위의 코드에 몇 가지 주석을 추가하여 조금 더 명확하게 설명 할 것입니다. 위의 Python 스크립트는 표준 입력 스트림에서 고정 폭 입력을 읽고 탭으로 구분 된 값의 문자열로 분리 한 다음 파이프를 사용하여 psql로 리디렉션되는 표준 출력 스트림으로 전송합니다. ". – Stew

답변

2

익명 파이프 대신 named pipes을 사용할 수 있습니다. 이 개념을 사용하면 python 스크립트가 다른 psql 프로세스를 통해 테이블을 해당 데이터로 채울 수 있습니다.

만들기 파이프 :

mkfifo fifo_table1 
mkfifo fifo_table2 

실행 psql의 인스턴스 :

psql db_name < fifo_table1 & 
psql db_name < fifo_table2 & 

파이썬 스크립트에 대해 너무 (의사 코드) 보일 것이다

SQL_BEGIN = """ 
BEGIN; 
TRUNCATE TABLE %s; 
COPY %s FROM STDIN WITH NULL AS ''; 
""" 
fifo1 = open('fifo_table1', 'w') 
fifo2 = open('fifo_table2', 'w') 

bigfile = open('mybigfile', 'r') 

print >> fifo1, SQL_BEGIN % ('table1', 'table1') #ugly, with python2.6 you could use .format()-Syntax  
print >> fifo2, SQL_BEGIN % ('table2', 'table2')  

for line in bigfile: 
    # your code, which decides where the data belongs to 
    # if data belongs to table1 
    print >> fifo1, data 
    # else 
    print >> fifo2, data 

print >> fifo1, 'COMMIT;' 
print >> fifo2, 'COMMIT;' 

fifo1.close() 
fifo2.close() 

아마이 가장 우아한 아니다 솔루션이지만 작동해야합니다.

+0

이것은 어떻게해야하는지에 대해 궁금해하며, 성공적으로 구현했습니다. 이 가져 오기 스크립트의 이전 버전은 실행하는 데 몇 시간이 걸렸습니다. 이 접근법으로 쓴 것은 54 분이 걸렸습니다. 감사! – Stew

+0

에 대해 익숙하지 않은 사람들은 파일과 같이 영속적입니다. 따라서 파일을 사용하면 파일을 제거하는 문장을 만들 것을 고려해야합니다 :'os.system ("rm fifo_table1")'예를 들어, OS 모듈. – Stew

2

왜 두 번째 테이블에 COPY를 사용합니까? 나는 다음과 같이 가정한다 :

 
INSERT INTO table2 (...) 
SELECT ... 
FROM table1; 

COPY를 사용하는 것보다 빠르다.

편집
서로 다른 테이블에 다른 행을 가져올 수 있지만 같은 소스 파일에서, 어쩌면 준비 테이블에 모든 것을 삽입 한 후 목표 테이블에 거기에서 행 삽입이 빠른해야하는 경우 :

가져 오기 하나 스테이징 테이블에 전체 * 텍스트 파일 : 그 단계 이후

 
COPY staging_table FROM STDIN ...; 

는 전체 입력 파일 staging_table

그럼들만을 선택하여 각각 대상 테이블에 준비 테이블의 행을 복사에 즉, 해당 테이블에 대한 자격 :

 
INSERT INTO table_1 (...) 
SELECT ... 
FROM staging_table 
WHERE (conditions for table_1); 

INSERT INTO table_2 (...) 
SELECT ... 
FROM staging_table 
WHERE (conditions for table_2); 

이것은 물론 당신이 주변에 준비 테이블을 유지하기 위해 데이터베이스에 충분한 공간이있는 경우에만 가능하다.

+0

나는 당신이 맞다고 생각하는데, @a_horse_with_no_name,하지만 나는 내 질문에 명확하지 않다. 파일의 각 라인은 5 개의 테이블 각각에 대해 1 행의 데이터를 포함한다. table2는 table1 데이터에서 파생되지 않습니다. 중복되지 않습니다. 이것이 라인이 다른 파이썬 스크립트로 파싱되는 이유입니다. 재 : 제 2자를 잘라 - 네가 맞아, 우연히 그걸 버렸다. 감사! – Stew

+0

@ 스튜 : 아하구나. 그럼 분명히 해결책이 아닙니다. –

+0

@a_horse_with_no_name 실제로, 내가 그것에 대해 생각할 때, 이것은 다음과 같이 할 수있는 잠재적 인 해결책이 될 수있었습니다. – Stew

관련 문제