[SQL] JSON 배열의 요소를 찾기위한 색인
SQLJSON 배열의 요소를 찾기위한 색인
나는 모습이 좋아하는 테이블이 있습니다 :
CREATE TABLE tracks (id SERIAL, artists JSON);
INSERT INTO tracks (id, artists)
VALUES (1, '[{"name": "blink-182"}]');
INSERT INTO tracks (id, artists)
VALUES (2, '[{"name": "The Dirty Heads"}, {"name": "Louis Richards"}]');
이 질문에 관련이없는 여러 가지 다른 열이있다. 그들이 JSON으로 저장 한 이유가있다.
난 할 노력하고있어 특정 아티스트 이름 (일치)가 트랙을 조회합니다.
나는이 쿼리를 사용하고 있습니다 :
SELECT * FROM tracks
WHERE 'ARTIST NAME' IN
(SELECT value->>'name' FROM json_array_elements(artists))
예를 들면
SELECT * FROM tracks
WHERE 'The Dirty Heads' IN
(SELECT value->>'name' FROM json_array_elements(artists))
그러나, 이것은 전체 테이블 스캔을 수행하고, 매우 빠르게 없습니다. 나는 함수 names_as_array (예술가)를 사용하여 GIN 인덱스를 생성했는데, '아티스트 이름'= ANY names_as_array (예술가)를 사용하지만 인덱스는 사용되지 않으며 쿼리가 상당히 느린 사실이다.
해결법
-
==============================
1.새로운 바이너리 JSON 데이터 형식 jsonb으로, 포스트 그레스 9.4은 주로 인덱스 옵션을 개선 소개했다. 이제 직접 jsonb 배열에 GIN 인덱스를 가질 수 있습니다 :
새로운 바이너리 JSON 데이터 형식 jsonb으로, 포스트 그레스 9.4은 주로 인덱스 옵션을 개선 소개했다. 이제 직접 jsonb 배열에 GIN 인덱스를 가질 수 있습니다 :
CREATE TABLE tracks (id serial, artists jsonb); CREATE INDEX tracks_artists_gin_idx ON tracks USING gin (artists);
함수에 대한 필요가 배열을 변환 없습니다. 이 쿼리를 지원합니다 :
SELECT * FROM tracks WHERE artists @> '[{"name": "The Dirty Heads"}]';
@> 새로운 jsonb되는 것은 GIN 인덱스를 사용하여 조작자를 '포함'. (형태가 아닌 JSON에 대한 만 jsonb!)
아니면 인덱스에 대한보다 전문, 기본이 아닌 GIN 연산자 클래스 jsonb_path_ops을 사용합니다 :
CREATE INDEX tracks_artists_gin_idx ON tracks USING gin (artists jsonb_path_ops);
같은 쿼리.
현재는 jsonb_path_ops에서 @> 연산자를 지원합니다. 그러나 일반적으로 훨씬 더 작고 더 빠른입니다. 매뉴얼에 더 많은 인덱스 옵션 사항이 있습니다.
단지 텍스트 프리미티브로 값과 중복 키가 열 이름에있을 수 있습니다 : 예에 표시되는 아티스트 이름 만 보유하면,로 시작하는 덜 중복 JSON 값을 저장하는 것이 더 효율적이 될 것입니다.
JSON 객체와 기본 유형의 차이를 참고 :
CREATE TABLE tracks (id serial, artistnames jsonb); INSERT INTO tracks VALUES (2, '["The Dirty Heads", "Louis Richards"]'); CREATE INDEX tracks_artistnames_gin_idx ON tracks USING gin (artistnames);
질문:
SELECT * FROM tracks WHERE artistnames ? 'The Dirty Heads';
? 개체 값, 단지 키와 배열 요소 작동하지 않습니다. 또는 (이름은 종종 더 효율적으로 반복하는 경우) :
CREATE INDEX tracks_artistnames_gin_idx ON tracks USING gin (artistnames jsonb_path_ops);
질문:
SELECT * FROM tracks WHERE artistnames @> '"The Dirty Heads"'::jsonb;
이것은 불변의 기능을 작동합니다 :
CREATE OR REPLACE FUNCTION json2arr(_j json, _key text) RETURNS text[] LANGUAGE sql IMMUTABLE AS 'SELECT ARRAY(SELECT elem->>_key FROM json_array_elements(_j) elem)';
이 기능 인덱스를 만듭니다
CREATE INDEX tracks_artists_gin_idx ON tracks USING gin (json2arr(artists, 'name'));
그리고이 같은 쿼리를 사용합니다. WHERE 절에서 표현식은 지수의 하나와 일치해야합니다 :
SELECT * FROM tracks WHERE '{"The Dirty Heads"}'::text[] <@ (json2arr(artists, 'name'));
의견의 피드백 업데이트되었습니다. 우리는 GIN 인덱스를 지원하기 위해 배열 연산자를 사용합니다. 이 경우에는 오퍼레이터 @ < "에 포함된다."
당신은 json_array_elements ()가 아니었다되지 않은 경우에도 함수의 불변 선언 할 수 있습니다. 대부분의 JSON 기능은 안정 불변하지로 사용됩니다. 그 변화에 해커 목록에 대한 논의가 있었다. 대부분은 지금은 불변입니다. 확인 :
SELECT p.proname, p.provolatile FROM pg_proc p JOIN pg_namespace n ON n.oid = p.pronamespace WHERE n.nspname = 'pg_catalog' AND p.proname ~~* '%json%';
기능 인덱스는 불변적인 기능과 함께 작동합니다.
from https://stackoverflow.com/questions/18404055/index-for-finding-an-element-in-a-json-array by cc-by-sa and MIT license
'SQL' 카테고리의 다른 글
[SQL] 포함 된 VARCHAR 필드에 문자열의 발생 수를 계산? (0) | 2020.03.12 |
---|---|
[SQL] 집계 함수없이 TSQL 피벗 (0) | 2020.03.12 |
[SQL] SCOPE_IDENTITY (), 신원 (의 차이점은 무엇입니까), @@ IDENTITY 및 IDENT_CURRENT ()? (0) | 2020.03.12 |
[SQL] SQL 서버에 두 개의 서로 다른 서버에서 데이터 선택 (0) | 2020.03.12 |
[SQL] 어떻게 일대일, 일대 설계 테이블 동안 관계 및 다 대다을 구현하는 방법? (0) | 2020.03.12 |