2011-01-03 2 views
5

는 PostgreSQL의 9.0에 다음과 같은 구조의 테이블을 상상해PostgreSQL의 : 스타 스키마로 데이터를로드 효율적으로

create table raw_fact_table (text varchar(1000)); 

단순화를 위해서 난 단지 하나의 텍스트 열을 언급, 그것은 다스가 현실에서. 이 테이블에는 100 억 개의 행이 있고 각 열에는 많은 중복이 있습니다. 테이블은 COPY FROM을 사용하여 플랫 파일 (csv)에서 작성됩니다.

create table fact_table (dimension_table_id int); 

내 현재의 방법

create table dimension_table (id int, text varchar(1000)); 

사실 테이블은 다음과 같은 사실 테이블로 대체 될 것이다 :

나는 다음과 같은 스타 스키마 구조로 변환 할 성능을 향상하려면 기본적으로 다음 쿼리를 실행하여 차원 테이블을 만듭니다.

Create table dimension_table (id int, text varchar(1000), primary key(id)); 

다음 차원 테이블을 채우기 만들기 위해 내가 사용

select id into fact_table from dimension inner join raw_fact_table on (dimension.text = raw_fact_table.text); 

그냥 몇 가지 다른 문자열로 모든 문자열을 비교하여 내가 얻을 끔찍한 성능을 상상 :

insert into dimension_table (select null, text from raw_fact_table group by text); 

는 그 후 나는 다음과 같은 쿼리를 실행해야 타임스.

MySQL에서는 COPY FROM 중에 저장 프로 시저를 실행할 수있었습니다. 이것은 문자열의 해시를 만들 수 있으며 모든 후속 문자열 비교는 긴 원시 문자열 대신 해시에서 수행됩니다. 이것은 PostgreSQL에서 가능하지 않은 것 같습니다. 그럼 어떻게해야합니까?

샘플 데이터는 다음과 같이 (I 정수 주위 또한 따옴표를 사용하고 복식)를 포함하는 CSV 파일 다음과 같습니다

"lots and lots of text";"3";"1";"2.4";"lots of text";"blabla" 
"sometext";"30";"10";"1.0";"lots of text";"blabla" 
"somemoretext";"30";"10";"1.0";"lots of text";"fooooooo" 
+0

소요 시간은 어느 정도입니까? 얼마나 걸릴 것으로 예상 했습니까? –

+0

언급 한 양의 데이터를 사용하여 끝내지는 않았습니다. 그러나 1 천 5 백만 행에 몇 시간이 걸렸습니다. 나는 모든 표준 서버 최적화 작업 (work_mem 등)을 이미 조사 했으므로 같은 결과를 얻는 다른 방법을 사용하고있다. – David

+0

샘플 데이터와 DDL을 게시하십시오. –

답변

2

질문 : - 1 또는 2 단계로 데이터를 변환해야합니까? - 변환하는 동안 테이블을 수정할 수 있습니까?

한 가지 방법이 될 것입니다 성능 (그리고 그 일을하는 동안 서버로드)를 향상시킬 수보다 더 간단 쿼리를 실행 :

  1. dimension_table 생성 (내가 제대로 이해한다면, 당신은 필요가 없습니다 (아마도 임시 부울 필드를 추가하면 ...)
  2. repeat : dimension_table에서 이전에 선택하지 않은 항목을 하나 선택하고 raw_fact_table에서 모든 행을 선택하여 fact_table에 삽입합니다. 마크 dimension_table 완료로 기록하고, 다음은 ... 당신은 저장 프로 시저로이 쓸 수, 그리고 (아마도 더 나은) ... 최소한의 자원을 먹고, 백그라운드에서

또는 다른 데이터를 변환 할 수 있습니다

  1. raw_fact_table 및 하나의 dimension_id에서 모든 레코드로 fact_table을 작성하십시오.
  2. 없는 경우
  3. 가 dimension_table
  4. 에 새로운 레코드를 생성 fact_table에 dimension_text위한
    • 검색 :
    • 가 dimension_table
    • 어느 fact_table위한 삽입 트리거 후에를 만들면된다 (그래서 dimension_text 및 dimension_id 행을 포함) dimension_id를이 ID로 업데이트
  5. simle 루프에서 raw_fact_table에서 fact_table까지 모든 레코드를 삽입
+0

제안 해 주셔서 감사합니다. 나는 이것을 지정하지 않았지만 모든 데이터를 가능한 한 빨리 처리하기 때문에 백그라운드에서 뭔가를 실행해도 설정에 영향을 미치지 않습니다 (다른 상황에서는 매우 현명합니다). 두 번째 방법의 문제점은 COPY FROM에서 트리거가 트리거되지 않는다는 것입니다. 그래서 나는 방아쇠를 당길 이유가 없다고 생각합니다. 귀하의 접근 방식은 여전히 ​​커서를 사용하여 매우 유효합니다. 나는 성능에 대해 불확실하지만 : http://stackoverflow.com/questions/4776127/postgres-surprising-performance-on-updates-using-cursor – David

+0

첫 번째 접근 방식에 관해서는, 나는 생성의 성능을 시간 초과하지 않았다. 차원 테이블 (나는 이것을해야한다). 나는 당신의 접근 방식이 다른 방향으로 생각하는 것을 좋아한다. 나는 당신의 접근 방식을 바탕으로 새로운 의견을 제시 할 것입니다. – David

+0

테이블 만들기 dimension_table (ID 일련 번호, 텍스트 varchar (1000), raw_fact_table_id bigint [], 기본 키 (id)) ------------------- dimension_table에 삽입 (텍스트 , raw_fact_table_id) (텍스트를 선택하여 raw_fact_table 그룹에서 텍스트, array_agg (raw_fact_table.id)); 이후에 raw_fact_table_id의 id를 기반으로 raw_fact_table을 업데이트하는 방법을 찾아야합니다. 어떻게 생각해? – David

2

당신은 마지막에 거기에 몇 가지 세부 사항을 생략됩니다, 그러나 나는 것을 볼 수 없습니다 반드시 문제가있다. 모든 문자열이 실제로 다른 모든 문자열과 비교된다는 것은 증거가 아닙니다. 조인을하면 PostgreSQL은 해시 조인과 같은 더 똑똑한 조인 알고리즘을 선택할 수 있습니다.이 알고리즘은 MySQL 솔루션에서 구현하는 것과 동일한 해싱을 제공합니다. (다시 말하지만, 당신의 세부 사항은에 흐릿한 있습니다.)

+0

답변 해 주셔서 감사합니다. 나는 누락 된 세부 사항으로 지금 질문을 업데이트했다. – David

6

그냥 무서운 성능을 상상 나는 모든 다른 문자열을 여러 번 모든 문자열을 비교하여 얻을.

이 작업을 수행하다가 성능 상상을 멈추고 측정을 시작합니다. "조기 최적화는 모든 악의 뿌리입니다."

"10 억"은 무엇을 의미합니까? 나에게 미국에서는 1,000,000,000 (또는 1e9)을 의미합니다. 그게 사실이라면, 아마도 1 테라 바이트에서 7 테라 바이트의 데이터를 보게 될 것입니다.당신이 될거야에 대한 정수를 사용하는 테이블에 100 억 개 행을 맞게되는 방법

Create table dimension_table (id int, text varchar(1000), primary key(id)); 

:

내 현재의 방법은 기본적으로 가 차원 테이블을 만들려면 다음 쿼리를 실행하는 것입니다 기본 키? 행의 절반이 중복된다고합시다. 당신이 그것을 할 때 그 산술은 어떻게 작동합니까?

생각하지 마세요. 먼저 읽으십시오. 그럼 테스트 해봐.

Data Warehousing with PostgreSQL을 읽으십시오. 나는이 프리젠 테이션 슬라이드가 당신에게 몇 가지 아이디어를 줄 것이라고 생각합니다.

또한 Populating a Database을 읽고 구현할 제안 사항을 고려하십시오.

"나누기 및 정복"프로세스에 따라 백만 (1e6) 행으로 테스트합니다. 즉, 한 번에 백만을로드하려고 시도하지 마십시오. 그것을 작은 덩어리로 분해하는 절차를 작성하십시오. 실행

EXPLAIN <sql statement> 

적어도 99 % 중복 행을 추정했다고 말했습니까? 대체로 반드시 속는 데이터베이스 내부

  1. , 당신이 생산을 위해 사용하는 것과 동일한 플랫폼을 제거하는 방법에는 두 가지가 있습니다, 말하기.
  2. 데이터베이스 외부, 파일 시스템에서 반드시 프로덕션에 사용하는 것과 동일한 파일 시스템 일 필요는 없습니다.

아직로드 한 텍스트 파일이있는 경우 먼저 데이터베이스 외부에서 시도해보십시오. 이 awk one-liner는 각 파일에서 고유 한 행을 출력합니다. 데이터를 한 번 통과시키는 것이 상대적으로 경제적입니다.

awk '!arr[$0]++' file_with_dupes > file_without_dupes 

당신이 정말로 99 % 속는이있는 경우,이 과정의 말에 당신이 50 기가까지 당신의 1 ~ 7 테라 바이트를 감소해야한다. 또한 데이터웨어 하우스에 복사하기 전에 각 고유 한 줄에 번호를 매기고 탭으로 구분 된 파일을 만들 수도 있습니다. 당신이 Windows에서이 작업을 수행해야하는 경우

awk '{printf("%d\t%s\n", NR, $0);}' file_without_dupes > tab_delimited_file 

, 내가 Cygwin을 사용하십시오 : 그것은 또 다른 한 줄입니다.

데이터베이스에서이 작업을 수행해야한다면 프로덕션 데이터베이스 또는 프로덕션 서버를 사용하지 않는 것이 좋습니다. 하지만 어쩌면 너무 조심스러워. 몇 테라 바이트를 이동하는 것은 비용이 많이 드는 일입니다.

하지만 GROUP BY를 사용하기 전에

SELECT DISTINCT ... 

을 테스트 할 것입니다. 대용량 데이터에 대해 몇 가지 테스트를 수행 할 수 있지만 이번 주에는 그렇지 않을 수 있습니다. (저는 보통 테라 바이트 크기의 파일로 작업하지 않습니다. 재미있을 것 같습니다.)

+0

나는 끔찍한 성능을 얻고 있으며 특정 문제를 해결하기위한 구체적인 조언을 구하고 있습니다. raw_fact_table에는 기본 키의 정수가 없습니다. fact_table에는 99.XX % 중복이있는 차원 테이블 만 있습니다. 나는 이미 당신이 보낸 링크에서 모든 조언을 구현했습니다. – David

+0

"ETL"의 "T"가 당신을 죽이고 있습니다. 99 % 중복은 약 100,000,000 개의 행을 목표로한다는 것을 의미합니다. 내 대답을 편집 할게. –

+0

예제를 단순화하기 위해 raw_fact_table에는 텍스트 열이 하나만 있다고 언급했습니다. 사실 그것은 12 개가 있기 때문에 중복을 제거하는 방법은 효과가 없을 것입니다. 그러나이를 지적 해 주셔서 감사합니다. 나는 그 질문을 갱신 할 것이다. raw_fact_table에는 정수 값과 double 값도 있습니다. – David

1

나는 16 진수 결과를 반환 문자열의 MD5 해시 계산) PostgreSQL의 MD5 (문자열의 MD5 기능이 있습니다 널 선택 (dimension_table, MD5로

삽입 문제 를 해결하는 몇 가지 방법을 참조 텍스트 의해 raw_fact_table 그룹 (텍스트), 텍스트)

이너 (dimension.md5 = raw_fact_table.md5)에 가입 raw_fact_table 차원에서 fact_table로 raw_fact_table뿐만 선택 자료로 MD5 필드를 추가; MD5에

인덱스뿐만 아니라

도움이 될 제출 또는 데이터를로드하는 동안 당신은 즉시 MD5를 계산할 수 있습니다. 예를 들어, ETL 도구 인 Advanced ETL 프로세서를 사용하여 수행 할 수 있습니다. 플러스 그것은 동시에 여러 테이블에 데이터를로드 할 수 있습니다. 이 하나가 천천히 변화하는 차원을

http://www.dbsoftlab.com/online-tutorials/advanced-etl-processor/advanced-etl-processor-working-with-slow-changing-dimension-part-2.html

+0

데이터를로드하는 데 권장되는 방법 인 COPY FROM을 실행하는 동안 MD5를 계산할 수 있다고 생각하지 않습니다. 이것이 당신의 도구가 COPY FROM을 사용하지 않는다는 것을 의미한다면, 이것 없이는 로딩이 오래 걸릴 것이므로 쓸모 없다고 생각합니다. 코드가없는 ETL 솔루션에 대해서는 회의적입니다. 단지 표준적인 것들을 할 필요가있는 한 괜찮습니다. 그러나 제가 특별한 경우에 문제가 생기면 다시 돌아갈 코드가 없습니다. – David

+0

전적으로 동의합니다 COPY FROM은 PostgreSQL에 데이터를로드하는 가장 빠른 방법입니다. 우리는이를 Advanced ETL Processor에서 내부적으로 사용합니다. PostgreSQL의 문서에서 : COPY TABLE_NAME에서 STDIN까지 (STDIN 클라이언트 응용 프로그램에서 입력을 지정합니다.) –

+0

가능한 한 빨리 처리하도록 최선을 다했습니다. 모든 데이터베이스에 대해 우리는 데이터를 단식 적으로로드합니다. (직접/일반 경로 oracle, bcp for SQL Server, Copy from PostgreSQL 등) 실제로 중요한 코드를 인쇄하고 모든 비효율적 인 부분을 표시하고 제거했습니다. 우리는 프로파일 러를 사용하고 성능을 최적화했습니다. 우리는 끊임없이 개선 작업을하고 있습니다. (지원 포럼을 살펴보고 큰 문제를 해결하는 데 걸리는 시간이나 새로운 기능을 소개하는 데 걸리는 시간을 메모하십시오.) –

2
-- add unique index 
CREATE UNIQUE INDEX uidx ON dimension_table USING hash(text); 
-- for non case-sensitive hash(upper(text)) 

시도 해시 (텍스트)을로드 보여줍니다 예를 들어 웹 사이트 볼 온라인 자습서의 숫자가있다

; btree (텍스트)를 사용하여 어느 것이 더 빠르는지 확인하십시오.