[postgresql] PostgreSQL LIKE 쿼리 성능 변화
LIKE
내 데이터베이스의 특정 테이블에 대한 쿼리 와 관련하여 응답 시간이 상당히 많이 변하는 것을 보았습니다 . 때로는 200-400ms (매우 수용 가능) 내에 결과를 얻을 수 있지만 결과를 반환하는 데 30 초 정도 걸릴 수도 있습니다.
LIKE
쿼리가 매우 리소스 집약적 이라는 것을 이해 하지만 응답 시간에 그렇게 큰 차이가있는 이유를 이해할 수 없습니다. owner1
필드 에 btree 인덱스를 만들었지 만 LIKE
쿼리에 도움이되지 않는다고 생각 합니다. 누구나 아이디어가 있습니까?
샘플 SQL :
SELECT gid, owner1 FORM parcels
WHERE owner1 ILIKE '%someones name%' LIMIT 10
나는 또한 시도했다 :
SELECT gid, owner1 FROM parcels
WHERE lower(owner1) LIKE lower('%someones name%') LIMIT 10
과:
SELECT gid, owner1 FROM parcels
WHERE lower(owner1) LIKE lower('someones name%') LIMIT 10
비슷한 결과가 있습니다.
테이블 행 수 : 약 95,000.
답변
FTS는 지원하지 않습니다 LIKE
이전에 허용 대답은 잘못되었습니다. 전체 텍스트 인덱스가있는 전체 텍스트 검색 은 연산자를 위한 것이 아닙니다.LIKE
자체 연산자가 있으며 임의의 문자열에 대해서는 작동하지 않습니다. 사전 및 형태소 분석을 기반으로 하는 단어로 작동합니다 . 그것은 않습니다 지원 단어에 대한 접두사 일치를 에 있지만 LIKE
운영자 :
Trigram 인덱스 LIKE
GIN 및 GiST 트라이 그램 인덱스 에 pg_trgm
대한 연산자 클래스를 제공 하는 추가 모듈 을 설치하여 왼쪽 앵커뿐만 아니라 모든 및 패턴 을 지원 합니다.LIKE
ILIKE
색인 예 :
CREATE INDEX tbl_col_gin_trgm_idx ON tbl USING gin (col gin_trgm_ops);
또는:
CREATE INDEX tbl_col_gist_trgm_idx ON tbl USING gist (col gist_trgm_ops);
쿼리 예 :
SELECT * FROM tbl WHERE col LIKE '%foo%'; -- leading wildcard
SELECT * FROM tbl WHERE col ILIKE '%foo%'; -- works case insensitively as well
트라이 그램? 짧은 문자열은 어떻습니까?
인덱싱 된 값 이 3 자 미만인 단어는 여전히 작동합니다. 매뉴얼 :
각 단어는 문자열에 포함 된 트라이 그램 집합을 결정할 때 접두사 2 개와 접미사 1 개 공백이있는 것으로 간주됩니다.
그리고 3 자 미만의 검색 패턴? 매뉴얼 :
LIKE
정규식 검색과 정규식 검색 모두 에 대해 추출 가능한 트라이 그램이없는 패턴은 전체 인덱스 스캔으로 저하된다는 점에 유의하십시오.
즉, 인덱스 / 비트 맵 인덱스 스캔은 여전히 작동하지만 (준비된 명령문에 대한 쿼리 계획은 중단되지 않음) 더 나은 성능을 얻을 수 없습니다. 일반적으로 1 자 또는 2 자 문자열은 선택성이 거의없고 (기본 테이블 일치의 몇 퍼센트 이상) 인덱스 지원으로 인해 전체 테이블 스캔이 더 빠르기 때문에 성능이 향상되지 않기 때문에 큰 손실이 없습니다.
text_pattern_ops
접두사 일치
단지를 들어 왼쪽 고정 된 패턴 당신은 적절한에 최적의 수 (더 와일드 카드를 선도 없음) 연산자 클래스 하십시오 BTREE 지수를 text_pattern_ops
나 varchar_pattern_ops
. 표준 Postgres의 두 내장 기능 모두 추가 모듈이 필요하지 않습니다. 성능은 비슷하지만 인덱스가 훨씬 작습니다.
색인 예 :
CREATE INDEX tbl_col_text_pattern_ops_idx ON tbl(col text_pattern_ops);
쿼리 예 :
SELECT * FROM tbl WHERE col LIKE 'foo%'; -- no leading wildcard
또는 ‘C’ 로케일로 데이터베이스를 실행해야하는 경우 (실제로 는 로케일 )로 어쨌든 모든 것이 바이트 순서에 따라 정렬되고 기본 연산자 클래스가있는 일반 btree 인덱스가 작업을 수행합니다.
dba.SE의 관련 답변에 대한 자세한 내용, 설명, 예제 및 링크 :
답변
아마도 빠른 것은 인덱스를 사용할 수있는 것과 같이 대소 문자를 구분하는 고정 된 패턴 일 것입니다. 즉, 일치 문자열의 시작 부분에 와일드 카드가 없으므로 실행 프로그램이 인덱스 범위 스캔을 사용할 수 있습니다. ( 문서의 관련 주석은 여기에 있습니다 ) Lower 및 ilike는 해당 목적을 위해 특별히 색인을 생성하지 않는 한 색인을 사용할 수있는 능력을 잃게됩니다 ( 기능 색인 참조 ).
필드 중간에있는 문자열을 검색하려면 전체 텍스트 또는 트라이 그램 인덱스를 살펴 봐야 합니다 . 첫 번째는 Postgres 코어에 있고 다른 하나는 contrib 모듈에서 사용할 수 있습니다.
답변
PostgreSQL에서 다른 유형의 인덱스 인 Wildspeed를 설치할 수 있습니다. Wildspeed는 % word % 와일드 카드와 함께 작동합니다. 문제 없습니다. 단점은 인덱스의 크기입니다. 이것은 매우 클 수 있습니다.
답변
postgresql에서 LIKE 쿼리 성능을 향상시키기 위해 아래 언급 된 쿼리를 실행하십시오. 더 큰 테이블에 대해 다음과 같은 색인을 작성하십시오.
CREATE INDEX <indexname> ON <tablename> USING btree (<fieldname> text_pattern_ops)
답변
그만한 가치 를 위해 Django ORM은 UPPER(text)
모든 사람들 에게 사용하는 경향이 있습니다.LIKE
쿼리에 대소 문자를 구분하지 않는 .
색인을 추가하면 UPPER(column::text)
다른 것과 달리 시스템 속도가 크게 빨라졌습니다.
선행 %까지는 인덱스를 사용하지 않습니다. 훌륭한 설명은이 블로그를 참조하십시오.
https://use-the-index-luke.com/sql/where-clause/searching-for-ranges/like-performance-tuning
답변
최근에 200000 개의 레코드가 포함 된 테이블에서 비슷한 문제가 발생하여 LIKE 쿼리를 반복해야합니다. 제 경우에는 검색중인 문자열이 수정되었습니다. 다른 분야는 다양했습니다. 그 때문에 다시 쓸 수있었습니다.
SELECT owner1 FROM parcels
WHERE lower(owner1) LIKE lower('%someones name%');
같이
CREATE INDEX ix_parcels ON parcels(position(lower('someones name') in lower(owner1)));
SELECT owner1 FROM parcels
WHERE position(lower('someones name') in lower(owner1)) > 0;
쿼리가 빠르게 돌아오고 인덱스가 EXPLAIN ANALYZE
다음 과 함께 사용되는지 확인했을 때 기뻤습니다 .
Bitmap Heap Scan on parcels (cost=7.66..25.59 rows=453 width=32) (actual time=0.006..0.006 rows=0 loops=1)
Recheck Cond: ("position"(lower(owner1), 'someones name'::text) > 0)
-> Bitmap Index Scan on ix_parcels (cost=0.00..7.55 rows=453 width=0) (actual time=0.004..0.004 rows=0 loops=1)
Index Cond: ("position"(lower(owner1), 'someones name'::text) > 0)
Planning time: 0.075 ms
Execution time: 0.025 ms
답변
유사한 쿼리는 다음과 같은 이유로 만든 색인을 사용할 수 없습니다.
1) LIKE 기준은 와일드 카드로 시작합니다.
2) LIKE 기준으로 함수를 사용했습니다.