2016-06-03 1 views
1

Postgres 9.5를 사용하면 성능을 극대화하기 위해 GIN 인덱스를 결정적으로 활용하여 두 개의 JSON 필드를 조인하여 JSONB 열이있는 테이블을 어떻게 쿼리 할 수 ​​있습니까?Postgres JSONB - 두 개의 JSON 필드 간 조인

단일 플랫폼에서 다른 고객을 위해 서로 다른 스키마/데이터 모델을 수용 할 수있는 시스템을 프로토 타이핑하고 있습니다. Entity-Attribute-Value (EAV)는 이에 대한 일반적인 패턴이며 Postgres가 JSONB 데이터 유형을 사용하여 저장된 엔티티에 대한 쿼리를 얼마나 잘 처리 할 수 ​​있는지 벤치마킹하기를 열망하고 있습니다.

다른 유형의 엔티티를 저장하는 단일 테이블을 보유하고 있습니다. 고객, 판매 거래.

:

{"uuid": "8f8896c7-f41c-49f7-ad6e-4613f7b51a23", "email": "[email protected]", "lastname": "McCarthy", "createdAt": "May 27, 2015 12:06:45 PM", "firstname": "Nathan"} 

I 형 'sales_transaction'와 속성이 테이블에 판매 거래 기록을 가지고 :

CREATE TABLE entity_jsonb (
    id uuid PRIMARY KEY, 
    type text, 
    created_at timestamp without time zone, 
    properties jsonb, 
    org_id integer 
); 
CREATE INDEX entity_jsonb_created_at_idx ON entity_jsonb USING btree (created_at); 
CREATE INDEX entity_jsonb_org_id_idx ON entity_jsonb USING btree (org_id); 
CREATE INDEX entity_jsonb_type_idx ON entity_jsonb USING btree (type); 
CREATE INDEX entity_jsonb_properties_idx ON entity_jsonb USING gin (properties); 

나는 형 '고객'과 속성이 테이블에 고객 기록이

{"uuid": "54243d48-e69f-4bb6-ab33-6defb8a0f626", "amount": 99817, "status": 0, "paymentType": 1, "currencyCode": "USD", "customerUuid": "8f8896c7-f41c-49f7-ad6e-4613f7b51a23", "transactionId": "471170"} 

GIN 인덱스 (연산자 : @>,?,? &,? |)를 사용하면 트랜잭션을 효율적으로 쿼리 할 수 ​​있지만 고객과 합류하면 데이터를 반환 할 수 있습니다. 둘 다. 지난 7 일간의 거래 목록을 채우고 고객 이름과 거래 금액을 표시 하시겠습니까?

나는 및 관련 고객의 세부 사항 (양 = 99817에 대한) 트랜잭션 객체의 하위 집합 찾기 위해이 쿼리를 시도했다 :

SELECT t.properties AS transaction, c.properties AS customer 
FROM entity_jsonb t 
JOIN entity_jsonb c ON (c.properties->>'uuid' = t.properties->>'customerUuid' AND c.type = 'customer') 
WHERE t.type = 'sales_transaction' AND t.properties @> '{"amount" : 99817}'; 

그것은 작동을하지만 나는만큼 빨리 GIN 인덱스 즉,하지를 사용하지 않는 것 그것을 좋아한다. 나는 GIN @> containment 연산자를 사용하여이 접근법을 시도했지만 고객 세부 정보는 포함하지 않았다. 내가 도대체 ​​뭘 잘못하고있는 겁니까?

SELECT t.properties AS transaction, c.properties AS customer FROM entity_jsonb t LEFT JOIN entity_jsonb c ON (c.properties @> json_build_array(json_build_object('uuid', t.properties->'customerUuid'))::jsonb AND c.type = 'customer') WHERE t.type = 'sales_transaction' AND t.properties @> '{"amount" : 99817}'; 

나는이 전통적인 관계형 디자인과 비교하여 최적의 솔루션이 아닙니다하지만 난 쿼리가 JSON과 같은 엔티티 데이터를 저장하는 순수 할 수있는 방법을 효율적으로보고 관심이 있음을 이해합니다.

답변

1

내 검색어가 그리 멀지 않았습니다. 나는 json_build_array을 필요로하지 않았다. 이제 100K 고객의 데이터 세트에 대해 쿼리가 GIN 인덱스를 사용하지 않는 버전보다 10 배 더 빠르게 실행됩니다.

SELECT t.properties AS transaction, c.properties AS customer 
FROM entity_jsonb t 
JOIN entity_jsonb c ON (c.properties @> json_build_object('uuid', t.properties->'customerUuid')::jsonb AND c.type = 'customer') 
WHERE t.type = 'sales_transaction' AND t.properties @> '{"amount" : 99817}';