큰 데이터베이스 쿼리 최적화 (max () 및 GROUP BY를 사용하여 2 천 5 백만 행 이상)


14

Postgres 9.3.5를 사용하고 있으며 데이터베이스에 큰 테이블이 있으며 현재 2,500 만 개가 넘는 행이 있으며 훨씬 더 빨리 커지는 경향이 있습니다. 다음과 같은 간단한 쿼리 를 사용하여 특정 행을 선택하려고합니다 ( 각 행 마다 unit_id최신 행만 있음 unit_timestamp).

SELECT unit_id, max(unit_timestamp) AS latest_timestamp FROM all_units GROUP BY unit_id;

인덱스가 없으면이 쿼리를 실행하는 데 약 35 초가 걸립니다. 인덱스를 정의하면 ( CREATE INDEX partial_idx ON all_units (unit_id, unit_timestamp DESC);) 쿼리 시간이 약 19 초로 단축됩니다.

더 적은 시간 (예 : 몇 초) 내에 쿼리를 실행할 수 있을지 궁금하다면 더 최적화하기 위해 어떤 단계를 수행해야합니까?

내 테이블 구조 덤프는 다음과 같습니다.

CREATE TABLE "all_units" (
"unit_id" int4 NOT NULL,
"unit_timestamp" timestamp(6) NOT NULL,
"lon" float4,
"lat" float4,
"speed" float4,
"status" varchar(255) COLLATE "default"
)
ALTER TABLE "all_units" ADD PRIMARY KEY ("unit_id", "unit_timestamp");

EXPLAIN (ANALYZE, BUFFERS)다음과 같습니다 :

QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------
HashAggregate  (cost=663998.38..664069.73 rows=7135 width=12) (actual time=84715.050..84732.021 rows=11094 loops=1)
  Buffers: shared hit=192 read=286819
  ->  Seq Scan on ais_sorted  (cost=0.00..538335.92 rows=25132492 width=12) (actual time=0.608..41264.196 rows=25132492 loops=1)
        Buffers: shared hit=192 read=286819
Total runtime: 84746.501 ms

서버의 psql 설정은 다음과 같습니다.

                name                 |  context   |  min_val  |   max_val    |                boot_val
-------------------------------------+------------+-----------+--------------+-----------------------------------------
 allow_system_table_mods             | postmaster |           |              | off
 application_name                    | user       |           |              |
 archive_command                     | sighup     |           |              |
 archive_mode                        | postmaster |           |              | off
 archive_timeout                     | sighup     | 0         | 1073741823   | 0
 array_nulls                         | user       |           |              | on
 authentication_timeout              | sighup     | 1         | 600          | 60
 autovacuum                          | sighup     |           |              | on
 autovacuum_analyze_scale_factor     | sighup     | 0         | 100          | 0.1
 autovacuum_analyze_threshold        | sighup     | 0         | 2147483647   | 50
 autovacuum_freeze_max_age           | postmaster | 100000000 | 2000000000   | 200000000
 autovacuum_max_workers              | postmaster | 1         | 8388607      | 3
 autovacuum_multixact_freeze_max_age | postmaster | 10000000  | 2000000000   | 400000000
 autovacuum_naptime                  | sighup     | 1         | 2147483      | 60
 autovacuum_vacuum_cost_delay        | sighup     | -1        | 100          | 20
 autovacuum_vacuum_cost_limit        | sighup     | -1        | 10000        | -1
 autovacuum_vacuum_scale_factor      | sighup     | 0         | 100          | 0.2
 autovacuum_vacuum_threshold         | sighup     | 0         | 2147483647   | 50
 backslash_quote                     | user       |           |              | safe_encoding
 bgwriter_delay                      | sighup     | 10        | 10000        | 200
 bgwriter_lru_maxpages               | sighup     | 0         | 1000         | 100
 bgwriter_lru_multiplier             | sighup     | 0         | 10           | 2
 block_size                          | internal   | 8192      | 8192         | 8192
 bonjour                             | postmaster |           |              | off
 bonjour_name                        | postmaster |           |              |
 bytea_output                        | user       |           |              | hex
 check_function_bodies               | user       |           |              | on
 checkpoint_completion_target        | sighup     | 0         | 1            | 0.5
 checkpoint_segments                 | sighup     | 1         | 2147483647   | 3
 checkpoint_timeout                  | sighup     | 30        | 3600         | 300
 checkpoint_warning                  | sighup     | 0         | 2147483647   | 30
 client_encoding                     | user       |           |              | SQL_ASCII
 client_min_messages                 | user       |           |              | notice
 commit_delay                        | superuser  | 0         | 100000       | 0
 commit_siblings                     | user       | 0         | 1000         | 5
 config_file                         | postmaster |           |              |
 constraint_exclusion                | user       |           |              | partition
 cpu_index_tuple_cost                | user       | 0         | 1.79769e+308 | 0.005
 cpu_operator_cost                   | user       | 0         | 1.79769e+308 | 0.0025
 cpu_tuple_cost                      | user       | 0         | 1.79769e+308 | 0.01
 cursor_tuple_fraction               | user       | 0         | 1            | 0.1
 data_checksums                      | internal   |           |              | off
 data_directory                      | postmaster |           |              |
 DateStyle                           | user       |           |              | ISO, MDY
 db_user_namespace                   | sighup     |           |              | off
 deadlock_timeout                    | superuser  | 1         | 2147483647   | 1000
 debug_assertions                    | user       |           |              | off
 debug_pretty_print                  | user       |           |              | on
 debug_print_parse                   | user       |           |              | off
 debug_print_plan                    | user       |           |              | off
 debug_print_rewritten               | user       |           |              | off
 default_statistics_target           | user       | 1         | 10000        | 100
 default_tablespace                  | user       |           |              |
 default_text_search_config          | user       |           |              | pg_catalog.simple
 default_transaction_deferrable      | user       |           |              | off
 default_transaction_isolation       | user       |           |              | read committed
 default_transaction_read_only       | user       |           |              | off
 default_with_oids                   | user       |           |              | off
 dynamic_library_path                | superuser  |           |              | $libdir
 effective_cache_size                | user       | 1         | 2147483647   | 16384
 effective_io_concurrency            | user       | 0         | 1000         | 1
 enable_bitmapscan                   | user       |           |              | on
 enable_hashagg                      | user       |           |              | on
 enable_hashjoin                     | user       |           |              | on
 enable_indexonlyscan                | user       |           |              | on
 enable_indexscan                    | user       |           |              | on
 enable_material                     | user       |           |              | on
 enable_mergejoin                    | user       |           |              | on
 enable_nestloop                     | user       |           |              | on
 enable_seqscan                      | user       |           |              | on
 enable_sort                         | user       |           |              | on
 enable_tidscan                      | user       |           |              | on
 escape_string_warning               | user       |           |              | on
 event_source                        | postmaster |           |              | PostgreSQL
 exit_on_error                       | user       |           |              | off
 external_pid_file                   | postmaster |           |              |
 extra_float_digits                  | user       | -15       | 3            | 0
 from_collapse_limit                 | user       | 1         | 2147483647   | 8
 fsync                               | sighup     |           |              | on
 full_page_writes                    | sighup     |           |              | on
 geqo                                | user       |           |              | on
 geqo_effort                         | user       | 1         | 10           | 5
 geqo_generations                    | user       | 0         | 2147483647   | 0
 geqo_pool_size                      | user       | 0         | 2147483647   | 0
 geqo_seed                           | user       | 0         | 1            | 0
 geqo_selection_bias                 | user       | 1.5       | 2            | 2
 geqo_threshold                      | user       | 2         | 2147483647   | 12
 gin_fuzzy_search_limit              | user       | 0         | 2147483647   | 0
 hba_file                            | postmaster |           |              |
 hot_standby                         | postmaster |           |              | off
 hot_standby_feedback                | sighup     |           |              | off
 ident_file                          | postmaster |           |              |
 ignore_checksum_failure             | superuser  |           |              | off
 ignore_system_indexes               | backend    |           |              | off
 integer_datetimes                   | internal   |           |              | on
 IntervalStyle                       | user       |           |              | postgres
 join_collapse_limit                 | user       | 1         | 2147483647   | 8
 krb_caseins_users                   | sighup     |           |              | off
 krb_server_keyfile                  | sighup     |           |              | FILE:/etc/postgresql-common/krb5.keytab
 krb_srvname                         | sighup     |           |              | postgres
 lc_collate                          | internal   |           |              | C
 lc_ctype                            | internal   |           |              | C
 lc_messages                         | superuser  |           |              |
 lc_monetary                         | user       |           |              | C
 lc_numeric                          | user       |           |              | C
 lc_time                             | user       |           |              | C
 listen_addresses                    | postmaster |           |              | localhost
 lo_compat_privileges                | superuser  |           |              | off
 local_preload_libraries             | backend    |           |              |
 lock_timeout                        | user       | 0         | 2147483647   | 0
 log_autovacuum_min_duration         | sighup     | -1        | 2147483647   | -1
 log_checkpoints                     | sighup     |           |              | off
 log_connections                     | backend    |           |              | off
 log_destination                     | sighup     |           |              | stderr
 log_directory                       | sighup     |           |              | pg_log
 log_disconnections                  | backend    |           |              | off
 log_duration                        | superuser  |           |              | off
 log_error_verbosity                 | superuser  |           |              | default
 log_executor_stats                  | superuser  |           |              | off
 log_file_mode                       | sighup     | 0         | 511          | 384
 log_filename                        | sighup     |           |              | postgresql-%Y-%m-%d_%H%M%S.log
 log_hostname                        | sighup     |           |              | off
 log_line_prefix                     | sighup     |           |              |
 log_lock_waits                      | superuser  |           |              | off
 log_min_duration_statement          | superuser  | -1        | 2147483647   | -1
 log_min_error_statement             | superuser  |           |              | error
 log_min_messages                    | superuser  |           |              | warning
 log_parser_stats                    | superuser  |           |              | off
 log_planner_stats                   | superuser  |           |              | off
 log_rotation_age                    | sighup     | 0         | 35791394     | 1440
 log_rotation_size                   | sighup     | 0         | 2097151      | 10240
 log_statement                       | superuser  |           |              | none
 log_statement_stats                 | superuser  |           |              | off
 log_temp_files                      | superuser  | -1        | 2147483647   | -1
 log_timezone                        | sighup     |           |              | GMT
 log_truncate_on_rotation            | sighup     |           |              | off
 logging_collector                   | postmaster |           |              | off
 maintenance_work_mem                | user       | 1024      | 2147483647   | 16384
 max_connections                     | postmaster | 1         | 8388607      | 100
 max_files_per_process               | postmaster | 25        | 2147483647   | 1000
 max_function_args                   | internal   | 100       | 100          | 100
 max_identifier_length               | internal   | 63        | 63           | 63
 max_index_keys                      | internal   | 32        | 32           | 32
 max_locks_per_transaction           | postmaster | 10        | 2147483647   | 64
 max_pred_locks_per_transaction      | postmaster | 10        | 2147483647   | 64
 max_prepared_transactions           | postmaster | 0         | 8388607      | 0
 max_stack_depth                     | superuser  | 100       | 2147483647   | 100
 max_standby_archive_delay           | sighup     | -1        | 2147483647   | 30000
 max_standby_streaming_delay         | sighup     | -1        | 2147483647   | 30000
 max_wal_senders                     | postmaster | 0         | 8388607      | 0
 password_encryption                 | user       |           |              | on
 port                                | postmaster | 1         | 65535        | 5432
 post_auth_delay                     | backend    | 0         | 2147         | 0
 pre_auth_delay                      | sighup     | 0         | 60           | 0
 quote_all_identifiers               | user       |           |              | off
 random_page_cost                    | user       | 0         | 1.79769e+308 | 4
 restart_after_crash                 | sighup     |           |              | on
 search_path                         | user       |           |              | "$user",public
 segment_size                        | internal   | 131072    | 131072       | 131072
 seq_page_cost                       | user       | 0         | 1.79769e+308 | 1
 server_encoding                     | internal   |           |              | SQL_ASCII
 server_version                      | internal   |           |              | 9.3.5
 server_version_num                  | internal   | 90305     | 90305        | 90305
 session_replication_role            | superuser  |           |              | origin
 shared_buffers                      | postmaster | 16        | 1073741823   | 1024
 shared_preload_libraries            | postmaster |           |              |
 sql_inheritance                     | user       |           |              | on
 ssl                                 | postmaster |           |              | off
 ssl_ca_file                         | postmaster |           |              |
 ssl_cert_file                       | postmaster |           |              | server.crt
 ssl_ciphers                         | postmaster |           |              | DEFAULT:!LOW:!EXP:!MD5:@STRENGTH
 ssl_crl_file                        | postmaster |           |              |
 ssl_key_file                        | postmaster |           |              | server.key
 ssl_renegotiation_limit             | user       | 0         | 2147483647   | 524288
 standard_conforming_strings         | user       |           |              | on
 statement_timeout                   | user       | 0         | 2147483647   | 0
 stats_temp_directory                | sighup     |           |              | pg_stat_tmp
 superuser_reserved_connections      | postmaster | 0         | 8388607      | 3
 synchronize_seqscans                | user       |           |              | on
 synchronous_commit                  | user       |           |              | on
 synchronous_standby_names           | sighup     |           |              |
 syslog_facility                     | sighup     |           |              | local0
 syslog_ident                        | sighup     |           |              | postgres
 tcp_keepalives_count                | user       | 0         | 2147483647   | 0
 tcp_keepalives_idle                 | user       | 0         | 2147483647   | 0
 tcp_keepalives_interval             | user       | 0         | 2147483647   | 0
 temp_buffers                        | user       | 100       | 1073741823   | 1024
 temp_file_limit                     | superuser  | -1        | 2147483647   | -1
 temp_tablespaces                    | user       |           |              |
 TimeZone                            | user       |           |              | GMT
 timezone_abbreviations              | user       |           |              |
 trace_notify                        | user       |           |              | off
 trace_recovery_messages             | sighup     |           |              | log
 trace_sort                          | user       |           |              | off
 track_activities                    | superuser  |           |              | on
 track_activity_query_size           | postmaster | 100       | 102400       | 1024
 track_counts                        | superuser  |           |              | on
 track_functions                     | superuser  |           |              | none
 track_io_timing                     | superuser  |           |              | off
 transaction_deferrable              | user       |           |              | off
 transaction_isolation               | user       |           |              | default
 transaction_read_only               | user       |           |              | off
 transform_null_equals               | user       |           |              | off
 unix_socket_directories             | postmaster |           |              | /var/run/postgresql
 unix_socket_group                   | postmaster |           |              |
 unix_socket_permissions             | postmaster | 0         | 511          | 511
 update_process_title                | superuser  |           |              | on
 vacuum_cost_delay                   | user       | 0         | 100          | 0
 vacuum_cost_limit                   | user       | 1         | 10000        | 200
 vacuum_cost_page_dirty              | user       | 0         | 10000        | 20
 vacuum_cost_page_hit                | user       | 0         | 10000        | 1
 vacuum_cost_page_miss               | user       | 0         | 10000        | 10
 vacuum_defer_cleanup_age            | sighup     | 0         | 1000000      | 0
 vacuum_freeze_min_age               | user       | 0         | 1000000000   | 50000000
 vacuum_freeze_table_age             | user       | 0         | 2000000000   | 150000000
 vacuum_multixact_freeze_min_age     | user       | 0         | 1000000000   | 5000000
 vacuum_multixact_freeze_table_age   | user       | 0         | 2000000000   | 150000000
 wal_block_size                      | internal   | 8192      | 8192         | 8192
 wal_buffers                         | postmaster | -1        | 2147483647   | -1
 wal_keep_segments                   | sighup     | 0         | 2147483647   | 0
 wal_level                           | postmaster |           |              | minimal
 wal_receiver_status_interval        | sighup     | 0         | 2147483      | 10
 wal_receiver_timeout                | sighup     | 0         | 2147483647   | 60000
 wal_segment_size                    | internal   | 2048      | 2048         | 2048
 wal_sender_timeout                  | sighup     | 0         | 2147483647   | 60000
 wal_sync_method                     | sighup     |           |              | fdatasync
 wal_writer_delay                    | sighup     | 1         | 10000        | 200
 work_mem                            | user       | 64        | 2147483647   | 1024
 xmlbinary                           | user       |           |              | base64
 xmloption                           | user       |           |              | content
 zero_damaged_pages                  | superuser  |           |              | off

WHERE 절이 도움이되므로 실제로 모든 unit_id가 필요합니까?
Mihai

불행히도 나는 그들 모두를 필요로하고, 더 악화시키기 위해, 지금 당장 11000 + 단위로 "단지"를 얻지 만, 앞으로 5-10 배 더 많이있을 것이라고 믿습니다.
정오표

시도 SELECT DISTINCT ON (unit_id),unit_timestamp FROM t ORDER BY unit_timestamp DESCunit_timestamp에 별도의 인덱스가 도움이 될 것이다.
Mihai

구체화보기는 옵션입니까?
user1363989

흠, 구체화 된 견해에 대해서는 전혀 몰랐습니다. 나는 하나를 만들고 그것이 유용한 지 알아볼 것입니다!
정오표

답변:


13

질문

쿼리는 전체 테이블 (또는 전체 인덱스)을 스캔해야합니다. 모든 행 다른 개별 단위 있습니다. 프로세스를 실질적으로 단축하는 유일한 방법 은 모든 사용 가능한 단위 가 포함 된 별도의 테이블 일 것입니다 all_units.
25M 항목에 ~ 11k 단위 (주석에 추가)가 있으므로이 점이 도움이됩니다.

값의 빈도에 따라 결과를 훨씬 빠르게 얻을 수있는 몇 가지 쿼리 기술이 있습니다.

  • 재귀 CTE
  • JOIN LATERAL
  • 상관 된 하위 쿼리

SO에 대한이 관련 답변의 세부 사항 :

기본 키의 암시 적 인덱스 만 필요한 (unit_id, unit_timestamp)경우이 쿼리는 암시 적을 사용하여 트릭을 수행해야합니다 JOIN LATERAL.

SELECT u.unit_id, a.max_ts
FROM unit u
  , (SELECT unit_timestamp AS max_ts
     FROM   all_units
     WHERE  unit_id = u.unit_id
     ORDER  BY unit_timestamp DESC
     LIMIT  1
     ) a;

all_units원래 검색어와 같이에 입력하지 않은 단위는 제외 합니다.
또는 관련성이 낮은 하위 쿼리 (아마도 더 빠름) :

SELECT u.unit_id
    , (SELECT unit_timestamp
       FROM   all_units
       WHERE  unit_id = u.unit_id
       ORDER  BY unit_timestamp DESC
       LIMIT  1) AS max_ts
FROM unit u;

에 항목이없는 단위를 포함합니다 all_units.

효율성은 단위당 항목 수에 따라 다릅니다 . 항목이 많을수록 이러한 쿼리 중 하나에 대한 가능성이 높아집니다.

유사한 테이블 (500 "단위", 큰 테이블의 1M 행)을 사용 하는 빠른 로컬 테스트 에서 상관 된 하위 쿼리가있는 쿼리는 ~ 500x 빠릅니다. 당신의 원본보다. 큰 테이블의 PK 인덱스에 대한 인덱스 전용 스캔과 원래 쿼리의 순차적 스캔.

테이블 때문에 tends to get even larger rapidly하는 구체화 된 뷰는 아마 옵션이 아닙니다.

이 또한 DISTINCT ON또 다른 가능한 쿼리 기술로, 그러나 거의 그렇게 빨리 원래 쿼리보다 더 될 것없는 것 없는 대답 당신이 찾고 있습니다. 자세한 내용은 여기 :

인덱스

당신의 partial_idx:

CREATE INDEX partial_idx ON all_units (unit_id, unit_timestamp DESC);

실제로는 부분 인덱스 가 아니며 중복입니다. Postgres는 실질적으로 동일한 속도로 인덱스를 뒤로 스캔 할 수 있으며 PK는 잘 작동합니다. 이 추가 색인을 삭제 하십시오.

테이블 레이아웃

테이블 정의를위한 몇 가지 사항.

CREATE TABLE all_units (
unit_timestamp timestamp,
unit_id int4,
lon     float4,
lat     float4,
speed   float4,
status  varchar(255),   -- might be improved.
PRIMARY KEY (unit_id, unit_timestamp)
);
  • timestamp(6)별로 의미가 없지만 timestamp, 최대 6 개의 소수 자릿수를 이미 저장하고있는 것과 정확히 동일 합니다.

  • 첫 두 열의 위치를 ​​전환하여 4 바이트의 패딩을 저장했습니다.이 크기는 25M 행의 경우 ~ 100MB입니다 (정확한 결과는에 따라 다름 status). 작은 테이블은 일반적으로 모든 것이 빠릅니다.

  • 경우 status무료 텍스트,하지만 표준화 노트의 어떤 종류의, 당신은 훨씬 저렴 무언가로 대체 할 수있다. Postgres 에 대한 추가 정보varchar(255) .

서버 구성

서버를 구성해야합니다. 대부분의 설정은 보수적 인 기본값 인 것 같습니다. 수백만 행이있는 설치의 경우 1MB shared_buffers이상 또는 최저 수준으로work_mem 보입니다 . 그리고 RAM이 많은 모든 최신 시스템에 적합합니다. 매뉴얼과 Postgres Wiki로 시작하십시오 :random_pare_cost = 4


완성도를 DISTINCT ON높이기 위해이 문제에 대한 쿼리 기술 목록에 mthod를 추가해야합니다 (물론 OP가 코드가 표시하는대로 2 개의 열이 아니라 주장한대로 모든 행을 표시하려는 경우)
ypercubeᵀᴹ

@ ypercube : 완전성을 위해, 네. 그러나 더 빠를 일은 거의 없습니다. OP가 찾고있는 답변이 아닙니다.
Erwin Brandstetter

재귀 적 CTE가 더 빨라질 방법을 정교하게 설명해 주시겠습니까 (또는 심지어 처음에 문제를 해결하는 방법- "최대"문제에 대한 재귀 적 CTE에 대해서는 생각해 본 적이 없습니다)
a_horse_with_no_name

1
@Mihai : 아니요, 비트 맵 인덱스 스캔 만 있습니다 (즉, "즉시"비트 맵 인덱스를 생성 함)
a_horse_with_no_name 1

3
@ErwinBrandstetter 좋아! 우선이 정교한 답변에 대해 대단히 감사드립니다. 매우 도움이되었습니다. 얼마나 많은지를 설명 할 수 없습니다! :) 둘째, 귀하의 질문 (두 번째 질문)은 굉장합니다! 쿼리 시간은 이제 약 0.2 초입니다 !!! :) 나는 첫 번째 쿼리를 가지고 놀려고했지만 내부 쿼리 invalid reference to FROM-clause entry for table "u"의이 WHERE절에서 얻은 오류를 해결하지 못했습니다 . 미안하지만 데이터베이스 자체는별로 좋지 않으므로 두 번째 쿼리가 이미 많은 도움을 주었으므로 머리를 압박하지 않았습니다.
정오표
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.