2017-11-21 17 views
4

이 질문의 환경은 AWS RDS의 PostgreSQL 9.6.5입니다.인덱싱 된 비트 세트에 대한 대용량 대량 업데이트를위한 최적 접근 방식

문제는 다음과 같은 논리적 데이터 모델을 포함하는 3 억 개 행이 테이블에 대한 최적의 스키마 설계 및 배치 업데이트 전략에 관한 것입니다 :

  • 길이 40 자에 기본 키, 문자열 최대 :

    • idcode :
    • year 정수 999 : 정수 년
    • 플래그 : 변수 번호 (1000)의 이름과 관련된 각각의 새로운 플래그는 시간이 지남에 추가. 이상적으로, 깃발은 (null), (true/1) 및 off (false/0)의 세 값을 가진 것으로 생각해야합니다. 추가 업데이트 (아래 참조)를 사용하면 플래그를 간단한 비트 (on 또는 off, no absent)로 처리 할 수 ​​있습니다. "On"값은 일반적으로 매우 희박합니다 : < 1/1000.

    쿼리는 일반적으로 code 때때로 또한 참여 year와 (이름으로) 하나 개 이상의 플래그의 존재 여부에 대한 부울 표현식을 포함한다.

    데이터는 Apache Spark를 통해 일괄 적으로 업데이트됩니다. 즉, 업데이트는 플랫 파일 (예 : COPY 형식 또는 SQL 작업)로 표시 될 수 있습니다. 한 번에 하나의 업데이트 만 활성화됩니다. codeyear에 대한 업데이트는 매우 드뭅니다. 플래그를 업데이트하면 업데이트 당 행 수가 1 ~ 5 % (3 ~ 15 백만 행)에 영향을줍니다. 업데이트 행에는 모든 플래그와 해당 값, 업데이트 될 "on"플래그 또는 값이 변경된 플래그 만 포함될 수 있습니다. 전자의 경우, Spark는 플래그의 현재 값을 얻기 위해 데이터를 쿼리해야합니다.

    업데이트하는 동안 작은 읽기로드가 발생합니다.

    질문은 설명 된대로 & 쿼리를 지원하는 최적의 스키마 및 관련 업데이트 전략에 대한 것입니다. 지금까지 연구에서

    일부 댓글 : 1,000 인덱스를 요구, 일부 DDL의 복잡성뿐만 아니라, 매우 효율적인 행 표현을 만들 수 있지만 것입니다 1,000 부울 열을 사용

    • .

    • 개별 비트를 인덱싱 할 수있는 방법이 있다면 비트 문자열이 좋습니다. 또한, 그들은 결석 한 깃발을 나타내는 좋은 방법을 제공하지 않습니다. 이 접근법을 사용하려면 플래그 이름과 비트 ID 사이에 룩업 테이블을 유지해야합니다. 그러나 병합 업데이트는 ||으로 작동하지만 PostgreSQL의 MVCC에서는 전체 행을 대체하는 대신 플래그를 업데이트하는 것이별로 도움이되지 않습니다.

    • JSONB 필드는 색인 생성을 제공합니다. 그것들은 또한 null 표현을 제공하지만, 비용이 발생합니다 : "off"인 모든 플래그는 명시 적으로 설정되어야하며 이는 필드를 상당히 크게 만듭니다. null 표현을 무시하면 JSONB 필드는 비교적 작습니다. 추가 축소를 위해 조회 테이블에 짧은 1-3 자 필드 이름을 사용할 수 있습니다. 같은 코멘트가 비트 문자열처럼 병합됩니다.

    • tsvector/tsquery :이 데이터 유형에는 경험이 없지만 이론적으로 이름별로 "on"플래그 세트를 정확하게 표현한 것 같습니다. 형태소 분석으로 인한 충돌이 없는지 확인하기 위해 추가 요구 사항이있는 플래그 테이블 이름을 토큰에 매핑하는 조회 테이블을 사용해야합니다.

  • 답변

    1

    기본 테이블에 플래그를 저장하지 마십시오. 기본 테이블이 data라고 다음과 같이 정의된다고 가정

    : 새 플래그가 생성되면

    CREATE TABLE flag_names (
        id smallint PRIMARY KEY, 
        name text NOT NULL 
    ); 
    
    CREATE TABLE flag (
        flagname_id smallint NOT NULL REFERENCES flag_names(id), 
        data_id text NOT NULL REFERENCES data(id), 
        value boolean NOT NULL, 
        PRIMARY KEY (flagname_id, data_id) 
    ); 
    

    flag_names에 새 행을 삽입합니다.

    플래그가 TRUE 또는 FALSE으로 설정된 경우 flag 테이블에 행을 삽입하거나 업데이트하십시오.

    으로 flag을 결합하면 특정 플래그가 설정되어 있는지 테스트 할 수 있습니다.

    +0

    이 작업을 수행하는 데 필요한 성능상의 이유가 있음을 추가해야합니다. 큰 행의 업데이트가 느립니다. – AlexanderMP

    +0

    1 인당 1000 개 이상의 플래그가있을 때마다 매회 9 ~ 45 억 개의 행이 업데이트되어 3 천억 행의 테이블을 제안 하시겠습니까? 즉, "켜기"로 설정된 플래그 만 유지하려는 경우 값 열을 사용하는 이유는 무엇입니까? 하나의 큰 행을 업데이트하는 것보다 빠르게 1,000 개의 작은 행을 업데이트 할 것으로 기대하십니까? – Sim

    +0

    또한, 나는'A 또는 (B와 C) 플래그가 아닌 (D와 E)'플래그에 대한 쿼리가 스키마와 어떤 관계가 있는지 궁금합니다. 플래그 정보를 여러 행으로 분할하면 동일한 계정에 대한 플래그 종속성을 평가하는 추가 작업이 필요합니다. – Sim