테이블 분석 - Amazon Redshift

테이블 분석

ANALYZE 작업은 쿼리 플래너가 최적의 계획을 선택하는 데 사용하는 통계 메타데이터를 업데이트합니다.

대부분의 경우 ANALYZE 명령을 명시적으로 실행할 필요가 없습니다. Amazon Redshift는 워크로드의 변경 사항을 모니터링하고 백그라운드에서 통계를 자동으로 업데이트합니다. 또한 COPY 명령은 빈 테이블로 데이터 로드 시 분석을 자동으로 수행합니다.

테이블 또는 전체 데이터베이스를 명시적으로 분석하려면 ANALYZE 명령을 실행합니다.

자동 분석

Amazon Redshift는 데이터베이스를 지속적으로 모니터링하고 백그라운드에서 분석 작업을 자동으로 수행합니다. 시스템 성능에 대한 영향을 최소화하기 위해 자동 분석은 워크로드가 적을 때 실행됩니다.

자동 분석은 기본적으로 활성화되어 있습니다. 자동 분석을 끄려면 클러스터의 파라미터 그룹을 수정하여 auto_analyze 파라미터를 false로 설정합니다.

처리 시간을 줄이고 전반적인 시스템 성능을 개선하기 위해 Amazon Redshift에서는 수정 범위가 작은 테이블에 대한 자동 분석은 건너뜁니다.

분석 작업은 통계가 최신 상태인 테이블은 건너뜁니다. ETL(추출, 변환, 로드) 워크플로우의 일부로 ANALYZE를 실행하면 자동 분석이 통계가 최신 상태인 테이블을 건너뜁니다. 마찬가지로, 자동 분석이 테이블의 통계를 업데이트한 경우에는 명시적 ANALYZE가 해당 테이블을 건너뜁니다.

새 테이블 데이터의 분석

기본적으로 COPY 명령은 데이터를 빈 테이블로 로드한 후 ANALYZE를 수행합니다. STATUPDATE를 ON으로 설정하면 테이블이 비어 있는지 여부에 상관없이 ANALYZE를 수행하도록 지정할 수 있습니다. STATUPDATE를 OFF로 지정하면 ANALYZE가 수행되지 않습니다. 테이블 소유자 또는 수퍼유저만이 ANALYZE 명령을 실행하거나 STATUPDATE가 ON으로 설정된 상태에서 COPY 명령을 실행할 수 있습니다.

Amazon Redshift는 다음 명령을 사용하여 생성하는 새 테이블을 분석합니다.

  • CREATE TABLE AS (CTAS)

  • CREATE TEMP TABLE AS

  • SELECT INTO

처음 데이터가 로드된 후 분석되지 않은 새 테이블에 대해 쿼리를 실행하면 Amazon Redshift에서는 경고 메시지를 반환합니다. 후속 업데이트 또는 로드 후 테이블을 쿼리하면 경고가 발생하지 않습니다. 분석되지 않은 테이블을 참조하는 쿼리에 대해 EXPLAIN 명령을 실행하면 동일한 경고 메시지가 반환됩니다.

비어 있지 않은 테이블에 데이터를 추가해 테이블의 크기가 크게 변경되면 항상 통계를 명시적으로 업데이트할 수 있습니다. ANALYZE 명령을 실행하거나 COPY 명령과 함께 STATUPDATE ON 옵션을 사용하여 업데이트할 수 있습니다. 마지막 ANALYZE 이후 삽입되거나 삭제된 행의 수에 대한 세부 정보를 보려면 PG_STATISTIC_INDICATOR 시스템 카탈로그 테이블을 쿼리합니다.

ANALYZE 명령의 범위는 다음 중 하나로 지정할 수 있습니다.

  • 전체 현재 데이터베이스

  • 단일 테이블

  • 단일 테이블의 하나 이상의 특정 열

  • 쿼리에서 조건자로 사용될 수 있는 열

ANALYZE 명령은 테이블에서 행의 샘플을 가져오고, 몇 가지 계산을 하며, 그 결과로 나온 열 통계를 저장합니다. 기본적으로 Amazon Redshift는 DISTKEY 열에 대해 샘플 패스를 실행하고, 테이블의 다른 모든 열에 대해 또 다른 샘플 패스를 실행합니다. 열의 하위 세트에 대한 통계를 생성하려면 쉼표로 구분된 열 목록을 지정할 수 있습니다. PREDICATE COLUMNS 절과 함께 ANALYZE를 실행해 조건자로 사용되지 않는 열은 건너뛸 수 있습니다.

ANALYZE 작업은 리소스를 많이 사용하므로 실제로 통계 업데이트가 필요한 테이블과 열에서만 실행하십시오. 정기적으로 또는 같은 일정으로 모든 테이블의 모든 열을 분석할 필요는 없습니다. 데이터가 대폭 변경되는 경우, 다음에서 자주 사용되는 열을 분석합니다.

  • 정렬 및 그룹화 작업

  • 조인

  • 쿼리 조건자

Amazon Redshift는 처리 시간을 줄이고 전체 시스템 성능을 높이기 위해 analyze_threshold_percent 파라미터에서 결정하는 대로 변경되는 행 비율이 낮은 테이블은 ANALYZE를 건너뜁니다. 기본적으로 분석 임계값은 10퍼센트로 설정됩니다. SET 명령을 실행하면 현재 세션의 분석 임계값을 변경할 수 있습니다.

빈번히 분석할 필요성이 낮은 열은 큰 VARCHAR 열 등 실제로 결코 쿼리되지 않는 사실과 측정값 및 관련 속성을 나타내는 열입니다. 예를 들어 TICKIT 데이터베이스의 LISTING 테이블을 고려해 보십시오.

select "column", type, encoding, distkey, sortkey from pg_table_def where tablename = 'listing'; column | type | encoding | distkey | sortkey ---------------+--------------------+----------+---------+--------- listid | integer | none | t | 1 sellerid | integer | none | f | 0 eventid | integer | mostly16 | f | 0 dateid | smallint | none | f | 0 numtickets | smallint | mostly8 | f | 0 priceperticket | numeric(8,2) | bytedict | f | 0 totalprice | numeric(8,2) | mostly32 | f | 0 listtime | timestamp with... | none | f | 0

이 테이블이 많은 수의 새 레코드와 함께 매일 로드된다면 쿼리에서 조인 키로 자주 사용되는 LISTID 테이블을 정기적으로 분석해야 합니다. TOTALPRICE와 LISTTIME이 쿼리에서 자주 사용되는 제약이라면 평일에는 항상 이 열들과 분산 키를 분석할 수 있습니다.

analyze listing(listid, totalprice, listtime);

애플리케이션에서 판매자와 이벤트가 훨씬 정적이고 날짜 ID가 2년 또는 3년만을 포함하는 고정된 날짜 집합을 가리킨다고 가정해 보겠습니다. 이 경우, 이러한 열의 고유한 값은 크게 변하지 않습니다. 하지만 각 고유 값의 인스턴스 수는 꾸준히 증가합니다.

그 밖에도 NUMTICKETS 및 PRICEPERTICKET 지표에 대한 쿼리 주기가 TOTALPRICE 열에 비해 드문 경우를 생각해보겠습니다. 이러한 경우에는 주말마다 한 번 전체 테이블에서 ANALYZE 명령을 실행해 매일 분석되지 않는 5개 열의 통계를 업데이트할 수 있습니다.

조건자 열

열 목록을 지정하는 대신 편하게 조건자로 사용될 수 있는 열만 분석하는 방법도 있습니다. 쿼리를 실행할 때 join, filter condition 또는 group by 절에서 사용되는 열은 모두 시스템 카탈로그에서 조건자 열로 표시됩니다. PREDICATE COLUMNS 절을 사용하여 ANALYZE를 실행하면 분석 작업에 다음 기준을 만족하는 열만 포함됩니다.

  • 조건자 열로 표시되는 열

  • 분산 키인 열

  • 정렬 키에 포함되는 열

테이블에서 조건자로 표시되는 열이 하나도 없으면 PREDICATE COLUMNS로 지정되더라도 ANALYZE에 모든 열이 포함됩니다. 조건자 열로 표시되는 열이 없는 이유는 테이블에 대한 쿼리를 아직 실행하지 않았기 때문일 수 있습니다.

워크로드의 쿼리 패턴이 비교적 안정적일 때는 PREDICATE COLUMNS를 사용할 수 있습니다. 다른 열이 조건자로 사용되는 경우가 빈번하여 쿼리 패턴이 가변적일 때 PREDICATE COLUMNS를 사용하면 일시적으로 시간이 경과된(stale) 통계가 나타날 수 있습니다. 시간이 경과된 통계는 최적화되지 못한 쿼리 런타임 계획으로 이어져 런타임이 길어지게 됩니다. 하지만 다음에 PREDICATE COLUMNS를 사용하여 ANALYZE를 실행할 때는 새로운 조건자 열이 포함됩니다.

조건자 열에 대한 세부 정보를 보려면 다음 SQL을 사용하여 PREDICATE_COLUMNS라는 이름으로 뷰를 생성하십시오.

CREATE VIEW predicate_columns AS WITH predicate_column_info as ( SELECT ns.nspname AS schema_name, c.relname AS table_name, a.attnum as col_num, a.attname as col_name, CASE WHEN 10002 = s.stakind1 THEN array_to_string(stavalues1, '||') WHEN 10002 = s.stakind2 THEN array_to_string(stavalues2, '||') WHEN 10002 = s.stakind3 THEN array_to_string(stavalues3, '||') WHEN 10002 = s.stakind4 THEN array_to_string(stavalues4, '||') ELSE NULL::varchar END AS pred_ts FROM pg_statistic s JOIN pg_class c ON c.oid = s.starelid JOIN pg_namespace ns ON c.relnamespace = ns.oid JOIN pg_attribute a ON c.oid = a.attrelid AND a.attnum = s.staattnum) SELECT schema_name, table_name, col_num, col_name, pred_ts NOT LIKE '2000-01-01%' AS is_predicate, CASE WHEN pred_ts NOT LIKE '2000-01-01%' THEN (split_part(pred_ts, '||',1))::timestamp ELSE NULL::timestamp END as first_predicate_use, CASE WHEN pred_ts NOT LIKE '%||2000-01-01%' THEN (split_part(pred_ts, '||',2))::timestamp ELSE NULL::timestamp END as last_analyze FROM predicate_column_info;

LISING 테이블에 대해 다음 쿼리를 실행한다고 가정하겠습니다. 단, LISTID, LISTTIME 및 EVENTID는 join, filter 및 group by 절에 사용됩니다.

select s.buyerid,l.eventid, sum(l.totalprice) from listing l join sales s on l.listid = s.listid where l.listtime > '2008-12-01' group by l.eventid, s.buyerid;

다음 예와 같이 PREDICATE_COLUMNS 뷰에 대한 쿼리를 실행하면 LISTID, EVENTID 및 LISTTIME이 조건자 열로 표시되어 있는 것을 볼 수 있습니다.

select * from predicate_columns where table_name = 'listing';
schema_name | table_name | col_num | col_name       | is_predicate | first_predicate_use | last_analyze       
------------+------------+---------+----------------+--------------+---------------------+--------------------
public      | listing    |       1 | listid         | true         | 2017-05-05 19:27:59 | 2017-05-03 18:27:41
public      | listing    |       2 | sellerid       | false        |                     | 2017-05-03 18:27:41
public      | listing    |       3 | eventid        | true         | 2017-05-16 20:54:32 | 2017-05-03 18:27:41
public      | listing    |       4 | dateid         | false        |                     | 2017-05-03 18:27:41
public      | listing    |       5 | numtickets     | false        |                     | 2017-05-03 18:27:41
public      | listing    |       6 | priceperticket | false        |                     | 2017-05-03 18:27:41
public      | listing    |       7 | totalprice     | false        |                     | 2017-05-03 18:27:41
public      | listing    |       8 | listtime       | true         | 2017-05-16 20:54:32 | 2017-05-03 18:27:41

통계를 최신 상태로 유지하면 쿼리 플래너가 최적의 계획을 선택할 수 있으므로 쿼리 성능이 향상됩니다. Amazon Redshift는 백그라운드에서 통계를 자동으로 새로 고치며 사용자가 ANALYZE 명령을 명시적으로 실행할 수도 있습니다. ANALYZE를 명시적으로 실행하도록 선택한 경우 다음을 수행합니다.

  • 쿼리를 실행하기 전에 ANALYZE 명령을 실행합니다.

  • 정기적인 로드 또는 업데이트 사이클이 끝날 때마다 일상적으로 데이터베이스에 대해 ANALYZE 명령을 실행합니다.

  • 새로 생성한 모든 테이블과 상당한 변경이 있는 모든 기존 테이블이나 열에 대해 ANALYZE 명령을 실행합니다.

  • 쿼리에서의 사용 및 변경 경향에 따라 테이블과 열의 형식마다 일정을 달리하여 ANALYZE 작업을 실행하는 것을 고려해 보십시오.

  • ANALYZE를 실행할 때 시간과 클러스터 리소스를 절약하려면 PREDICATE COLUMNS 절을 사용하십시오.

프로비저닝된 클러스터 또는 서버리스 네임스페이스에 스냅샷을 복원하거나 일시 중지된 프로비저닝된 클러스터를 다시 시작한 후에는 ANALYZE 명령을 명시적으로 실행할 필요가 없습니다. 이러한 경우 Amazon Redshift는 시스템 테이블 정보를 보존하므로 수동 ANALYZE 명령이 필요하지 않습니다. Amazon Redshift는 필요에 따라 자동 분석 작업을 계속 실행합니다.

분석 작업은 통계가 최신 상태인 테이블은 건너뜁니다. ETL(추출, 변환, 로드) 워크플로우의 일부로 ANALYZE를 실행하면 자동 분석이 통계가 최신 상태인 테이블을 건너뜁니다. 마찬가지로, 자동 분석이 테이블의 통계를 업데이트한 경우에는 명시적 ANALYZE가 해당 테이블을 건너뜁니다.