pg hint 계획 및 단일 테이블 기준 수정

다음은 PostgreSQL 조회 기획기의 기수를 설정하기 위한 pg hint plan에 대한 작은 게시물입니다.정확한 통계 데이터를 제공할 때postgres 최적화기는 좋은 평가를 할 수 있다. 이런 원가 기반의 최적화는 데이터의 변화에 적응할 수 있기 때문이다.그러나 OLTP 애플리케이션의 안정적인 상태를 유지해야 합니다.검색에서 기수를 제공하는 것이 이를 실현하는 방법일 수도 있다.정확한 줄 수를 제공할 필요는 없지만 데이터 접근 순서와 경로와 관련된 모델을 제공해야 합니다.
$ psql postgres://franck:[email protected]:5433/yb_demo_northwind
psql (14beta1, server 11.2-YB-2.7.1.1-b0)
Type "help" for help.

yb_demo_northwind=>
이것은 우리가 통계 데이터가 없는 예다.분산 문서 저장소(DocDB)를 PostgreSQL에 삽입하여 외부 데이터 패키지를 통해 조회하는 데 사용합니다YugabyteDB.나는 주제에 대한 관심을 유지하기 위해 이곳의 일을 지나치게 간소화했다.
관건은 현재 버전(YB-2.7)에서 우리는 표 통계 정보가 없고 조회 계획기는 기본 1000줄을 사용한다.
yb_demo_northwind=> explain (analyze, summary false) select * from orders;

                                                 QUERY PLAN
-------------------------------------------------------------------------------------------------------------
 Seq Scan on orders  (cost=0.00..100.00 rows=1000 width=472) (actual time=128.102..129.019 rows=830 loops=1)
(1 row)

yb_demo_northwind=> explain (analyze, summary false) select * from orders where ship_country='Switzerland';

                                                QUERY PLAN
----------------------------------------------------------------------------------------------------------
 Seq Scan on orders  (cost=0.00..102.50 rows=1000 width=472) (actual time=90.315..91.300 rows=18 loops=1)
   Filter: ((ship_country)::text = 'Switzerland'::text)
   Rows Removed by Filter: 812
(3 rows)
EXPLAIN 및 다음을 사용합니다.
  • TRUE를 분석하여 문장을 운행하고 집행 통계 데이터와 Planner 추정
  • 을 수집한다.
  • VERBOSE FALSE와 SUMMARY FALSE, 이 글을 쓰는 작은 출력을 얻고 재미있는 내용에만 주목
  • 기본값은 Trust, Trust, Format 텍스트
  • WAL과 버퍼는 여기에서 상관이 없습니다. Yugybyteb의 테이블과 인덱스 저장소는 DocDB층에서 관리하기 때문입니다.
  • 따라서 하나의 줄 집합을 읽을 때, 검색 계획기가 유일한 제약 때문에 한 줄만 알고 있는 경우를 제외하고는, 추정값은 rows=1000입니다.이것은 너무 간단한 것 같지만:
  • YugabyteDB는 새로운 것으로 분포식 엔진의 분석과 통계 최적화는 여전히 적극적으로 개발 중이다.
  • 현재 생산 중인 사용자는 OTLP 작업 부하를 사용하는데 이것은 충분하다. (Oracle에서 작업한 20년 동안 나는 거의 모든 ERP가 규칙 최적화기 모드로 운행하거나 소형 최적화기 index cost adj를 사용하여 같은 작업을 수행하는 것을 보았다)
  • 개발자들은 의외의 사고를 피하기 위해 방문 경로를 제어하는 것을 좋아한다. pg hint plan은 문제가 발생할 수 있는 상황을 해결할 수 있도록 허락한다. 이것이 바로 본고
  • 의 원인이다.

    pg 프롬프트 계획


    PostgreSQL에서 pg hint plan 확장을 설치하고 활성화해야 합니다.PostgreSQL 커뮤니티는 잘못 사용될까 봐 걱정하고, 검색 계획기를 유지하는 커뮤니티에 최적화기가 오류를 평가할 때 발생하는 문제를 보고하지 않는다.위험은 사람들이 암시를 통해서만 문제를 해결할 뿐 근본적인 원인을 해결하지 못한다는 데 있다.설령 개원된 것이라 할지라도Yugabyte 서로 다른 위치에 있다.사용자는 이 데이터베이스가 새롭고 매우 활발한 개발 중이며 Slack 또는 GitHub를 통해 우리와 상호작용을 하고 있음을 알고 있다.그리고 힌트를 사용하여 서로 다른 계획을 테스트하고 문제를 보고하며 힌트를 단기 해결 방안에 남겨 두었다.이외에도 YugabyteDB는 easyrolling upgrade를 지원하는 분포식 데이터베이스이기 때문에 고정 버전은 정지하지 않고 배치하기 쉽다.
    YugabyteDB에서는 기본적으로 pg hint 스케줄을 설치하고 활성화합니다.
    yb_demo_northwind=> show pg_hint_plan.enable_hint;
     pg_hint_plan.enable_hint
    -------------------------------
     on
    (1 row)
    
    yb_demo_northwind=> show pg_hint_plan.message_level;
     pg_hint_plan.message_level
    ---------------------------------
     log
    (1 row)
    
    pg hint plan 확장은 계획 작업(스캔 또는 인덱스 액세스, 연결 순서 및 방법)을 제어하는 프롬프트를 추가할 수 있지만 "Rows"프롬프트를 사용하여 기준 추정치를 수정할 수도 있습니다. Oracle의 OPT ESTIMATE() 프롬프트로 간주할 수 있습니다.그러나 현재 버전에서는 pg hint plan Rows() hint가 연결 결과만 조작합니다.
    yb_demo_northwind=> explain (analyze, summary false) select /*+ Rows(o #42) */ * from orders o where ship_country='Switzerland';
    INFO:  pg_hint_plan: hint syntax error at or near " "
    DETAIL:  Rows hint requires at least two relations.
                                                     QUERY PLAN
    -----------------------------------------------------------------------------------------------------------------
     Seq Scan on orders o  (cost=0.00..102.50 rows=1000 width=472) (actual time=26.114..27.103 rows=18 loops=1)
       Filter: ((ship_country)::text = 'Switzerland'::text)
       Rows Removed by Filter: 812
    (3 rows)
    
    이것은 문법 오류를 표시하고 알림을 무시합니다.프롬프트를 사용할 때는 항상 메시지를 보고 결과를 확인합니다.여기에 나는 여전히 기본 줄 = 1000을 가지고 있다.

    단표 기수


    나는 이곳에서 글을 쓰는 것이 조금도 만족스럽지 않다.단기적인 해결 방안을 언급하여 더 좋은 방법이 있거나 pg hint 계획에 이 기수 수정을 추가하는 데 도움이 될 수 있는지 살펴보겠습니다.그리고 어쨌든 그 결과를 알았을 때 추악한 변통 방법은 잠시 사용할 수 있다.
    yb_demo_northwind=> explain (analyze, summary false)
      /*+ Leading(dummy o) Rows(dummy o #42) */
      select * from (select 1 limit 1) dummy, orders o where ship_country='Switzerland';
                                                        QUERY PLAN
    -----------------------------------------------------------------------------------------------------------------------
     Nested Loop  (cost=0.00..112.52 rows=42 width=476) (actual time=24.733..25.807 rows=18 loops=1)
       ->  Limit  (cost=0.00..0.01 rows=1 width=4) (actual time=0.671..0.673 rows=1 loops=1)
             ->  Result  (cost=0.00..0.01 rows=1 width=4) (actual time=0.001..0.001 rows=1 loops=1)
       ->  Seq Scan on orders o  (cost=0.00..102.50 rows=1000 width=472) (actual time=23.997..25.066 rows=18 loops=1)
             Filter: ((ship_country)::text = 'Switzerland'::text)
             Rows Removed by Filter: 812
    (6 rows)
    
    yb_demo_northwind=> explain (analyze, summary false)
     /*+ Leading(dummy o) Rows(dummy o #42) */
     with dummy as (values (1))
     select o.* from dummy, orders o where ship_country='Switzerland';
                                                        QUERY PLAN
    -----------------------------------------------------------------------------------------------------------------------
     Nested Loop  (cost=0.01..112.53 rows=42 width=472) (actual time=24.089..25.115 rows=18 loops=1)
       CTE dummy
         ->  Result  (cost=0.00..0.01 rows=1 width=4) (actual time=0.001..0.002 rows=1 loops=1)
       ->  CTE Scan on dummy  (cost=0.00..0.02 rows=1 width=0) (actual time=0.004..0.005 rows=1 loops=1)
       ->  Seq Scan on orders o  (cost=0.00..102.50 rows=1000 width=472) (actual time=24.070..25.091 rows=18 loops=1)
             Filter: ((ship_country)::text = 'Switzerland'::text)
             Rows Removed by Filter: 812
    (7 rows)
    
    subselect와 with 자문(CTE)에서 두 가지 변체를 볼 수 있다.이 두 가지 방법은 모두 끼워 넣는 순환을 추가하여 실제 원가를 무시할 수 있어도 예상 원가의 기초 위에서 10을 증가시킬 것이다.
    Rows()는 절대 값이 아닌 보정을 수행할 수 있습니다.만약 당신이 이미 통계 데이터가 있는 표에서 그것을 사용한다면, 예상 원가를 조정하여 표의 증가를 따르게 하고, 수정을 유지하는 것이 가장 좋다.만나다pg_hint_plan documentation
    한 시계의 정정은 아마도 매우 유용하지 않을 것이다.그러나 진일보한 가입이 있을 때 큰 영향을 미친다.
    다음 예는 다음과 같습니다.
    yb_demo_northwind=> explain (analyze, summary false)
      select o.* from orders o join order_details d using (order_id) where ship_country='Switzerland';
                                                               QUERY PLAN
    --------------------------------------------------------------------------------------------------------------------------------------
     Nested Loop  (cost=0.00..218.88 rows=1000 width=472) (actual time=190.386..3890.738 rows=52 loops=1)
       ->  Seq Scan on order_details d  (cost=0.00..100.00 rows=1000 width=2) (actual time=11.991..14.555 rows=2155 loops=1)
       ->  Index Scan using orders_pkey on orders o  (cost=0.00..0.12 rows=1 width=472) (actual time=1.656..1.656 rows=0 loops=2155)
             Index Cond: (order_id = d.order_id)
             Filter: ((ship_country)::text = 'Switzerland'::text)
             Rows Removed by Filter: 1
    (6 rows)
    
    여기에 통계 데이터가 없기 때문에 조회 계획기는 모든 줄 수가 1000인 표를 추정하고'order details'표부터 시작하기로 결정합니다.그러나 이것은 효율적이지 않다. 모든 주문서의 상세한 정보를 읽고'주문서'에 가입해야'발송국'을 필터할 수 있다.
    2000개의 순환은 시간을 필요로 하는데, 특히 분포식 데이터베이스에서 줄은 서로 다른 노드에서 나올 수 있다.나는 아주 작은 기계에서 OCI 자유층에서 운행하고 있다. 나는 열린 상태를 유지하기 때문에 연결 문자열을 포함하여 모든 것을 복사하고 붙여넣을 수 있다.물론 YugabyteDB도 쉽게 설치할 수 있습니다: https://docs.yugabyte.com/latest/quick-start
    검색 계획기에 "ship country"필터링에 대한 선택성이 높다는 것을 알려 줄 수 있는 유사 줄 (위o*0.2) 의 알림을 추가할 수 있습니다.
    yb_demo_northwind=> explain (analyze, summary false)
     /*+ Rows(dummy o *0.2) Rows(dummy d *1) */
     with dummy as (values (1))
     select o.* from dummy, orders o join order_details d using (order_id) where ship_country='Switzerland';
                                                                                                                               QUERY PLAN
    -----------------------------------------------------------------------------------------------------------------------------------
     Hash Join  (cost=115.03..220.78 rows=200 width=472) (actual time=32.111..33.552 rows=52 loops=1)
       Hash Cond: (d.order_id = o.order_id)
       CTE dummy
         ->  Result  (cost=0.00..0.01 rows=1 width=4) (actual time=0.001..0.002 rows=1 loops=1)
       ->  Seq Scan on order_details d  (cost=0.00..100.00 rows=1000 width=2) (actual time=6.930..8.147 rows=2155 loops=1)
       ->  Hash  (cost=112.52..112.52 rows=200 width=472) (actual time=25.141..25.141 rows=18 loops=1)
             Buckets: 1024  Batches: 1  Memory Usage: 11kB
             ->  Nested Loop  (cost=0.00..112.52 rows=200 width=472) (actual time=24.171..25.123 rows=18 loops=1)
                   ->  CTE Scan on dummy  (cost=0.00..0.02 rows=1 width=0) (actual time=0.003..0.004 rows=1 loops=1)
                   ->  Seq Scan on orders o  (cost=0.00..102.50 rows=1000 width=472) (actual time=24.139..25.086 rows=18 loops=1)
                         Filter: ((ship_country)::text = 'Switzerland'::text)
                         Rows Removed by Filter: 812
    
    여기의 실행 속도가 훨씬 빨라서 "order details"의 중첩 순환을 피할 수 있습니다.모든 '주문 상세 정보' 가 스캔되고 산열되는 것을 놀라게 할 수도 있지만, 이것은 분포식 데이터베이스이며, 이 테이블은 많은 태블릿PC에 분할되어 있다는 것을 기억하십시오.더 낮은 선택성을 사용한다. 예를 들어 줄(위o#5)은'주문서'에서 온 다섯 줄을 최적화시켜 그곳에서 끼워 넣는 순환을 볼 수 있다.Dalibo plan visualizer:

    이것은 올바른 접근입니다. 이 가상 CTE를 추가하는 것 외에, 제가 해야 할 일은 20%의 알 수 없는 선택성을 언급하는 것입니다."order details"로 시작할 때 줄의 선택성은 100%(가상 d*1)라고 언급했다.이것은 이 내용을 바꾸지 않지만, 중요한 것은 검색 기획기가 고려할 수 있는 모든 연결 순서를 고려하고, 알림이 모든 순서와 일치하는지 확인하는 것입니다.각 주문에 대해 평균 3개의 주문 상세 정보를 제공하는 행(가상 o d*3)을 추가할 수도 있습니다.나는 또한 정확한 숫자를 사용하기로 결정할 수 있다. 예를 들어 행(위o#18)행(위d#2155)행(위d*2.5)을 사용하면 표에 변화가 생겨도 연결 방법의 결정에 정확한 균형을 유지할 수 있다.마지막으로, 나는 나의 가상 CTE로 시작하지 않는 연결 경로를 제시하지 않았다. 왜냐하면, 나는 검색 계획기가 항상 거기서부터 시작하기를 원하기 때문이다. (값이나 제한 구조 때문에, 그것은 단지 한 줄만 알고 있기 때문이다.)
    알림: 검색 기획사가 기수를 정확하게 예측할 수 없을 때, 알림은 일종의 변통 방법입니다. 통계 데이터가 표시할 수 없는 기수와 선택성을 이해하도록 도와주십시오.또한 CTE 추가는 다른 솔루션입니다.

    좋은 웹페이지 즐겨찾기