PostgreSQL에서 복합 인덱스의 열 순서 및 쿼리 순서


10

50K 행이있는 테이블이 있습니다. 실제로 PostGIS 테이블입니다.

쿼리에는 4 개의 파트가 있습니다 (1 개의 필수) (3 개의 옵션)

  1. 4lat, long (st_intersects를 사용함)이있는 교차 상자 (지리 사각형) [필수]
  2. 날짜 필드의 날짜 범위 (최소, 최대)
  3. 현재 IN (.....)을 사용하는 파일 형식 (최대 8 개의 텍스트 값 집합)이지만 필요한 경우 임시 테이블을 만들 수 있습니다. 나는 많은 사람들이 IN을 좋아하지 않는 것을 본다.
  4. 국가 (텍스트 값)

약 100 ~ 4,000 행이 반환 될 것으로 예상합니다.

테이블에 복합 인덱스를 만들면 어떤 열을 먼저 사용해야합니까? 미세 입자는 아마도 위치 일 것입니다 (데이터는 전 세계에 퍼져 있습니다). 나는 현재 그것을 GIST 지수로 가지고 있습니다.

다른 인덱스는 BTREE입니다.

내 직감은 세밀하게 사용하고 마지막으로 사용한다고 말합니다. 예를 들어 파일 형식은 약 12 ​​개뿐이므로 인덱스에 매우 큰 버킷이됩니다.

PostgreSQL 및 PostGIS 전문가 (시스템 내부를 아는 사람)는 무엇을 말합니까?


최신 정보:

이 질문을 선명하게하겠습니다.

  1. 나는 내가해야 할 일을하는 사람을 원하지 않는다. 나는 당신의 시간을 너무 존중합니다. 나중에 Explain 분석으로 이동하겠습니다.
  2. 내가 찾던 것은 몇 가지 지침과 팁 및 지침이었습니다.
  3. 나는이 훌륭한 작은 게시물을 읽었습니다 : https://devcenter.heroku.com/articles/postgresql-indexes#managing-and-maintaining-indexes 인덱스에 대한
  4. 내가 일반적으로하는 일은 4 개의 개별 색인 (geo-box, 국가 이름, file_type 및 날짜)을 작성하지만 복합 쿼리의 기능을 확인하려는 것입니다.

이러한 가정 중 하나라도 틀렸다면 알려주십시오. (저는 복합 지수에 대한 아이디어가 매우 익숙합니다)

  1. 순서가 중요합니다. 첫 번째 색인으로 행을 가장 많이 줄이십시오 (제 경우에는 간단한 다각형 또는 다중 다각형 인 위치 (지리)가 가장 좋습니다).
  2. 때때로 쿼리는 인덱스를 건너 뜁니다. 그러나 키 (# 1, # 2, # 3, # 4)로 복합 쿼리를 생성하면 사용자가 # 1, # 3을 요구하는 것을 생성하더라도 플래너는 여전히 단일 복합 쿼리를 사용합니다. 유지됩니다.
  3. 일반적으로 3 개의 BTREE 쿼리와 1 개의 GIST (지리 유형)를 작성합니다. PostGIS는 여러 인덱스 유형에서 복합 작성을 지원하지 않습니다. 따라서 복합 인덱스 GIST를 사용해야합니다. 그러나 그렇게해도 문제가되지는 않습니다.
  4. 추가 복합 또는 단일 값 인덱스를 만들면 플래너는 가장 지능적인 인덱스를 선택할 수있을만큼 똑똑합니다 .....
  5. 국가 이름은 약 250 개의 다른 값을 가질 수 있으며 분명히 위치 (geobox)와 강력하게 연결되어 있지만 행 크기를 줄이기 위해 다음으로 가장 좋은 색인이 file_type 인 경우 다음을 사용해야합니다. 사용자가 종종 쿼리 세트에서 국가 또는 날짜를 사용한다고는 생각하지 않습니다.
  6. 4 개의 키로 복합 인덱스를 생성하는 것에 대해 걱정할 필요가 없습니다. 인덱스 데이터의 크기가 크게 증가합니다. 즉, 단일 키 인덱스가 성능 향상의 90 %가 될 경우 3 개의 항목을 더 추가하여 복합적으로 만들 수 있습니다. 반대로 두 인덱스를 모두 만들어야합니다. 단일 지리 인덱스 및 복합 인덱스를 사용하여 플래너가 어느 것이 가장 적합한 지 알아 내면 인덱스 테이블의 크기를 고려하게됩니다.

다시 말하지만, 나는 누군가에게 내 솔루션을 디자인하도록 요구하지 않고 다른 사람들의 작업에 대해서는 신경 쓰지 않습니다. 그러나 PostGreSQL 설명서에서 구현에 대해 알려주지 않는 것들이 필요합니다.

[아직 설명 할 EXPLAIN 결과가없는 이유는 24M 행 테이블에서이 25K 행 테이블을 작성해야하기 때문입니다. 생각보다 시간이 많이 걸립니다. 물건을 1,000 개의 항목 그룹으로 클러스터링하고 사용자가 25K 행 테이블에 대해 쿼리 할 수있게합니다. 그러나 다음 질문은 해당 쿼리의 결과를 사용하여 MASTER 25M 행 테이블로 이동하여 항목을 꺼내는 것입니다. 바로 여기에서 복합 인덱스의 성능이 실제로 높아질 것입니다].


아래 샘플 쿼리 :


SELECT
    public.product_list_meta_mv.cntry_name       AS country,
    public.product_list_meta_mv.product_producer AS producer,
    public.product_list_meta_mv.product_name     AS prod_name,
    public.product_list_meta_mv.product_type     AS ptype,
    public.product_list_meta_mv.product_size     AS size,
    ST_AsGeoJSON(public.product_list_meta_mv.the_geom, 10, 2)          AS outline
FROM
    public.product_list_meta_mv 
WHERE
    public.product_list_meta_mv.cntry_name = 'Poland' 
AND
    ST_Intersects(public.product_list_meta_mv.the_geom,
    st_geogfromtext('SRID=4326;POLYGON((21.23107910156250 51.41601562500000,
                                        18.64379882812500 51.41601562500000,
                                        18.64379882812500 48.69415283203130,
                                        21.23107910156250 48.69415283203130,
                                        21.23107910156250 51.41601562500000))')) 
AND (date >= '1/2/1900 5:00:00 AM' 
 AND date <= '2/26/2014 10:26:44 PM')
AND (public.product_list_meta_mv.product_type in
    ('CIB10','DTED0','DTED1','DTED2','CIB01','CIB05')) ;

분석 결과를 설명하십시오 (나는 복합 색인을 넣지 않았으며 필요한 속도를 알지 못하는 속도에서).

"Bitmap Heap Scan on catalog_full cat  (cost=4.33..37.49 rows=1 width=7428) (actual time=1.147..38.051 rows=35 loops=1)"
"  Recheck Cond: ('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography && outline)"
"  Filter: (((type)::text = ANY ('{CADRG,CIB10,DTED1,DTED2}'::text[])) AND (_st_distance('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography, outline, 0::double precision, false) < 1e-005::double precision))"
"  Rows Removed by Filter: 61"
"  ->  Bitmap Index Scan on catalog_full_outline_idx  (cost=0.00..4.33 rows=8 width=0) (actual time=0.401..0.401 rows=96 loops=1)"
"        Index Cond: ('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography && outline)"
"Total runtime: 38.109 ms"

EXPLAIN ANALYZE SELECT pid,product_name,type,country,date,size,cocom,description,egpl_date,ST_AsGeoJSON(outline, 10, 2) AS outline 
FROM portal.catalog_full AS cat 
WHERE ST_Intersects(st_geogfromtext('SRID=4326;POLYGON((21.2200927734375 51.38031005859375, 18.65478515625 51.38031005859375, 18.65478515625 48.7298583984375, 21.2200927734375 48.7298583984375, 21.2200927734375 51.38031005859375))'), cat.outline) 
AND (cat.type in ('CADRG','CIB10','DTED1','DTED2'))

2
실제 검색어를 입력하십시오.
ypercubeᵀᴹ

"3 옵션"은 2,3,4 옵션의 활성화 여부에 따라 쿼리에 8 가지 변형이있을 수 있음을 의미합니까?
ypercubeᵀᴹ

WHERE에는 4 개의 AND 구성 요소가 있습니다. st_intersects가 필요하면 다른 것이있을 수도 있고 그렇지 않을 수도 있습니다. 그러나 나는 그들이 모두 존재하는 경우를 다루고 싶습니다.

2
질문을 dba.se로 마이그레이션하기로 투표했습니다. 이는 여러 범위 조건을 가진 복잡한 쿼리입니다.
ypercubeᵀᴹ

1
EXPLAIN ANALYZE검색어를 표시 합니다.
Craig Ringer

답변:


4

내 작업의 일환으로 상당히 큰 PostgreSQL 데이터베이스 (디스크에서 약 120GB, 수백만 행 테이블)를 유지 관리하고 쿼리 속도를 높이는 방법에 대한 몇 가지 트릭을 수집했습니다. 먼저 가정에 대한 몇 가지 의견 :

  1. 예, 순서는 중요하지만 실제로 다른 첫 번째 순서이며 나머지는 두 번째 클래스 인덱스입니다.
  2. 항상 두 가지를 모두 사용할지 확실하지 않습니다. 제 생각에 쿼리 플래너는 # 1을 사용하고 나머지는 영리한 것으로 생각합니다.
  3. GIST에 대한 경험이 없습니다.
  4. 예, 모든 색인을 먼저 추가하고 가장 많이 사용되는 항목과 최상의 성능을 제공하는 항목을 확인하십시오.
  5. 나는 당신이 두 가지를 모두 시도하고 가장 잘 작동하는 것을 측정한다고 제안합니다. 국가와 시간이 다른 하위 쿼리를 사용하여 SQL을 다시 작성하고 교차 쿼리와 함께 시도하십시오. IN 목록이 수천 개의 요소가 아닌 한 IN 절의 성능 문제를 발견하지 못했습니다. 내 생각에 사용 가능한 입력 기준에 따라 특별히 조정 된 몇 가지 쿼리가 최상의 결과를 제공 할 것입니다.
  6. 나는 4 방향 인덱스를 만드는 것에 반대 할 것을 제안한다. 하나를 만들어보고 크기를 확인하면 실제로 커질 수 있습니다. 내 경험상, 4 개의 1 키 인덱스는 단일 4 웨이 인덱스만큼 빠르다. 일부 특정 쿼리에서 잘 작동하는 트릭은 부분 인덱스입니다. 예를 들면 다음과 같습니다.

    INDEX ON table_x (key1, key2, key3) where some_x_column = 'XXXX';

추가하거나 제거 할 인덱스를 찾는 데 도움이되는 쿼리를 사용하여 .psqlrc 파일에 별칭을 만들었습니다. GitHub에서 자유롭게 살펴보십시오. .psql

: seq_scans 및 : bigtables를 많이 사용한 다음 \ d table_name을 사용하여 테이블에 대한 세부 정보를 얻습니다. 일부 변경을 수행 한 후 통계를 재설정하는 것을 잊지 마십시오. pg_stat_reset ();


1
이것들은 훌륭한 팁입니다. 나는 당신의 충고를 취한 다음 우리가 유지하는 훨씬 더 큰 테이블 (43 백만 행)에서 실험을하기 위해 이것을 사용했습니다. 결과는 다음과 같습니다 : dba.stackexchange.com/questions/61084/…
Dr.YSG

1

가장 도움이 될만한 것은 product_type을 두 번째 열로 요지 색인에 추가하는 것입니다. 그러나 일반적인 / 문제점 쿼리에 대해 각 AND 조건 (일치로)과 일치하는 행 수를 모르는 경우에만 추측 할 수 있습니다.

내가 이것에 접근 할 때, 내가하는 첫 번째 일은 WHERE 절에 EXPLAIN ANALYZE에서 하나의 조건 만 차례로 갖는 간단한 양식으로 쿼리를 실행하는 것입니다. 각 행의 예상 행과 실제 행을 모두보십시오.


위의 내 업데이트를 참조하십시오.하지만 좋은 리드를주고 있다고 생각합니다. 행 출력을 가장 빠르게 줄이는 인덱스를 정렬하는 것에 대해 생각하십시오. 맞습니까?
Dr.YSG
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.