Postgres가 순차 스캔을 고집 할 때 인덱스를 사용하도록 강제하는 방법은 무엇입니까?
Postgres가 순차 스캔을 고집 할 때 인덱스를 사용하도록 강제하는 방법은 무엇입니까?
답변:
많은 데이터베이스에서 발견되는 일반적인 "인덱스 힌팅"기능에 대해 질문한다고 가정하면 PostgreSQL은 이러한 기능을 제공하지 않습니다. 이것은 PostgreSQL 팀이 내린 의식적인 결정이었습니다. 이유와 대신 수행 할 수있는 작업에 대한 개요는 여기 에서 찾을 수 있습니다 . 그 이유는 기본적으로 데이터가 변경됨에 따라 나중에 더 많은 문제를 일으키는 경향이있는 성능 해킹 인 반면 PostgreSQL의 최적화 프로그램은 통계를 기반으로 계획을 재평가 할 수 있기 때문입니다. 즉, 오늘날 좋은 쿼리 계획이 될 수있는 것은 아마도 항상 좋은 쿼리 계획이 아닐 것이며 인덱스 힌트는 항상 특정 쿼리 계획을 강제합니다.
테스트에 유용한 매우 무딘 망치로 enable_seqscan
및 enable_indexscan
매개 변수를 사용할 수 있습니다 . 보다:
이들은 지속적인 용도로 사용하기에는 적합하지 않습니다 . 쿼리 계획 선택에 문제가있는 경우 쿼리 성능 문제 추적에 대한 설명서를 참조해야 합니다 . enable_
매개 변수를 설정 하고 떠나지 마십시오 .
색인을 사용하는 데 충분한 이유가 없다면 Postgres가 올바른 선택을 할 수 있습니다. 왜?
이 오래된 뉴스 그룹 게시물을 참조하십시오 .
아마도 사용하는 유일한 유효한 이유
set enable_seqscan=false
쿼리를 작성할 때 테이블에 많은 양의 데이터가있는 경우 쿼리 계획이 실제로 무엇인지 빠르게 확인하려는 경우입니다. 또는 데이터 세트가 너무 작기 때문에 쿼리가 인덱스를 사용하지 않는지 빠르게 확인해야하는 경우도 있습니다.
set enable_seqscan=false
, 쿼리를 실행하고 신속 실행 set enable_seqscan=true
(단지 개발, 생산에서이 작업을 수행하지 않는 분명히하고!) 적절한 행동에 PostgreSQL을을 반환
SET SESSION enable_seqscan=false
자신 만 영향을 미치는합니다
때때로 PostgreSQL이 특정 조건에 대한 최상의 인덱스 선택을하지 못합니다. 예를 들어, 특정 날짜에 대해 수백 개의 행이있는 트랜잭션 테이블이 있고 테이블에 transaction_id, client_id, date 및 description의 네 가지 인덱스가 있다고 가정합니다. 다음 쿼리를 실행하려고합니다.
SELECT client_id, SUM(amount)
FROM transactions
WHERE date >= 'yesterday'::timestamp AND date < 'today'::timestamp AND
description = 'Refund'
GROUP BY client_id
PostgreSQL은 transaction_date_idx 대신 transaction_description_idx 인덱스를 사용하도록 선택할 수 있습니다. 이로 인해 쿼리에 1 초 미만이 아닌 몇 분이 소요될 수 있습니다. 이 경우 다음과 같이 조건을 푸징하여 날짜에 인덱스를 강제로 사용할 수 있습니다.
SELECT client_id, SUM(amount)
FROM transactions
WHERE date >= 'yesterday'::timestamp AND date < 'today'::timestamp AND
description||'' = 'Refund'
GROUP BY client_id
your_wanted_index
postgresql 엔진이 대신 시퀀스 / 기본 키 스캔을 수행하도록 할 수 있습니다. 결론-PostgreSql 서버에 대한 일부 인덱스 사용을 강제하는 100 % 신뢰할 수있는 방법은 없습니다.
where
조건이 없지만 테이블이 두 개이거나 조인되고 Postgres가 인덱스를 가져 오지 못하면 어떻게 될까요?
이 문제는 일반적으로 인덱스 스캔의 예상 비용이 너무 높고 현실을 올바르게 반영하지 못할 때 발생합니다. random_page_cost
이 문제를 해결 하려면 구성 매개 변수를 낮춰야 할 수 있습니다 . 로부터 포스트 그레스 문서 :
이 값을 줄이면 [...] 시스템이 인덱스 스캔을 선호하게됩니다. 값을 올리면 인덱스 스캔이 상대적으로 더 비싸 보이게됩니다.
더 낮은 값이 실제로 Postgres가 인덱스를 사용하도록 할 것인지 여부를 확인할 수 있습니다 (그러나 테스트 용으로 만 사용 ).
EXPLAIN <query>; # Uses sequential scan
SET random_page_cost = 1;
EXPLAIN <query>; # May use index scan now
SET random_page_cost = DEFAULT;
다시 기본값으로 복원 할 수 있습니다 .
인덱스 스캔에는 비 순차적 디스크 페이지 가져 오기가 필요합니다. Postgres는 random_page_cost
순차 페치와 관련하여 이러한 비 순차 페치의 비용을 추정하는 데 사용 합니다. 기본값은입니다 4.0
. 따라서 순차 가져 오기와 비교 하여 평균 비용 요소 4 를 가정합니다 (캐싱 효과 고려).
그러나 문제는이 기본값이 다음과 같은 중요한 실제 시나리오에 적합하지 않다는 것입니다.
1) 솔리드 스테이트 드라이브
문서에서 인정하는대로 :
순차에 비해 임의 읽기 비용이 낮은 스토리지 (예 : 솔리드 스테이트 드라이브)는에 대해 더 낮은 값으로 모델링하는 것이 더 좋습니다
random_page_cost
.
PostgresConf 2018에서 발표 한이 슬라이드 의 마지막 요점 에 따르면는 솔리드 스테이트 드라이브 와 random_page_cost
사이의 값으로 설정되어야 합니다.1.0
2.0
2) 캐시 된 데이터
필요한 인덱스 데이터가 이미 RAM에 캐시 된 경우 인덱스 스캔은 항상 순차 스캔보다 훨씬 빠릅니다. 문서는 다음과 같이 말합니다.
따라서 데이터가 완전히 캐시에있을 가능성이있는 경우 [...] 감소
random_page_cost
가 적절할 수 있습니다.
문제는 물론 관련 데이터가 이미 캐시되었는지 여부를 쉽게 알 수 없다는 것입니다. 그러나 특정 인덱스가 자주 쿼리되고 시스템에 충분한 RAM이 있으면 데이터가 캐시 될 가능성이 높 random_page_cost
으므로 더 낮은 값으로 설정해야합니다. 다양한 값을 실험하고 무엇이 자신에게 적합한 지 확인해야합니다.
명시 적 데이터 캐싱을 위해 pg_prewarm 확장 을 사용할 수도 있습니다 .
그 자체에 대한 질문은 매우 잘못되었습니다. 강제 (예 : enable_seqscan = off)는 매우 나쁜 생각입니다. 더 빠른지 확인하는 것이 유용 할 수 있지만 프로덕션 코드는 이러한 트릭을 사용해서는 안됩니다.
대신 쿼리 분석을 설명하고 읽고 PostgreSQL이 잘못된 계획을 선택한 이유를 알아보십시오.
웹에는 Explain 분석 출력을 읽는 데 도움이되는 도구가 있습니다. 그중 하나는 Explain.depesz.com 입니다.
또 다른 옵션은 freenode irc 네트워크의 #postgresql 채널에 가입 하여 도움을 줄 수있는 사람들과 대화하는 것입니다. 쿼리를 최적화하는 것은 "질문을하고 답을 얻으십시오. 확인해야 할 사항이 많고 배워야 할 사항이 많은 대화와 비슷합니다.
OFFSET 0
하위 쿼리에 추가하는 seqscan을 선호하도록 postgres를 푸시하는 트릭이 있습니다.
이는 필요한 모든 것이 첫 번째 / 마지막 요소 n 개뿐 일 때 크고 거대한 테이블을 연결하는 요청을 최적화하는 데 유용합니다.
100k (또는 그 이상) 항목이있는 여러 테이블이 포함 된 처음 / 마지막 20 개 요소를 찾고 있다고 가정 해 보겠습니다. 검색하려는 항목이 처음 100 개 또는 1000 개에있을 때 모든 데이터에 대한 모든 쿼리를 구성 / 연결하지 않습니다. 항목. 예를 들어이 시나리오에서는 순차 스캔을 수행하는 것이 10 배 이상 빠릅니다.
Postgres가 하위 쿼리를 인라인하지 않도록 하려면 어떻게해야합니까?를 참조하십시오 .