声明比平时慢250倍

时间:2017-05-24 15:26:01

标签: postgresql postgresql-9.6

我正在运行一系列非常长的语句,移动了大量数据。有问题的陈述看起来像是这样的:

CREATE TABLE a (...);
WITH cte_1 AS (...),
cte_2 AS (...)
INSERT INTO a (...)
SELECT ....

这将创建表并用大约60,000个大行填充它。通常需要大约1秒来执行此声明。 “通常”意味着完全相同的环境(所有表和数据都是由脚本创建的 - 没有手动交互,因此相同环境的所有实例在数据和数据结构方面都是相同的)但是在不同的机器上,只需要1秒执行此操作。

但是在我拥有的新机器上,此声明突然需要4.5分钟才能完成。在此期间,Postgresql占用CPU核心的100%。在此期间,如果我使用DBeaver打开一个新连接,并运行完全相同的查询,只需一次更改(创建表b,然后从完全相同的数据源插入),在第一个查询运行期间,它需要0.8秒才能完成。

所以它绝对不是脚本,而是关于Postgresql或其配置的内部工作方式。这就是为什么我要分享它,而不是代码。

哦,这个查询:

SELECT 
  pid, datname, usename,
  application_name, query, state, 
  to_char(current_timestamp - query_start, 'HH24:MI:SS') AS running_for
FROM pg_stat_activity;

输出2个DBeaver进程(SHOW search_path空闲,以及上面的查询)和慢查询:

  

9736 my_db my_user psql active 00:02:42

在数百种语句中,在各种模式中,具有各种复杂性,这是唯一受影响的语句。唯一被修改使它变慢的是新操作系统(Ubuntu 17.04),可能是这个新的配置,因为旧的配置因为我的mac死了而丢失了。

data_directory = '/var/lib/postgresql/9.6/main'
hba_file = '/etc/postgresql/9.6/main/pg_hba.conf'
ident_file = '/etc/postgresql/9.6/main/pg_ident.conf'
external_pid_file = '/var/run/postgresql/9.6-main.pid'

listen_addresses = '*'
port = 5432
max_connections = 40

unix_socket_directories = '/var/run/postgresql'

shared_buffers = 4GB
temp_buffers = 2GB
work_mem = 512MB
maintenance_work_mem = 2GB
dynamic_shared_memory_type = posix

wal_level = minimal
fsync = off
synchronous_commit = off
full_page_writes = off
wal_buffers = 16MB

max_wal_size = 4GB
checkpoint_completion_target = 0.9

seq_page_cost = 1.0
random_page_cost = 1.5
effective_cache_size = 12GB

default_statistics_target = 500

logging_collector = on
log_directory = 'pg_log'
log_filename = 'query.log'
log_min_duration_statement = 0

debug_print_parse = off
debug_print_rewritten = off
debug_print_plan = off
debug_pretty_print = on
log_checkpoints = off
log_connections = off
log_disconnections = off

session_preload_libraries = 'auto_explain'
auto_explain.log_min_duration = '2s'

auto_explain.log_nested_statements = true
auto_explain.log_verbose = true

autovacuum = on
autovacuum_max_workers = 1

datestyle = 'iso, mdy'
timezone = 'UTC'


lc_messages = 'C'
lc_monetary = 'C'
lc_numeric = 'C'
lc_time = 'C'

default_text_search_config = 'pg_catalog.english'

max_locks_per_transaction = 2048

shared_preload_libraries = 'cstore_fdw'

根据请求,这是我的另一个配置的旧备份,我手动调整了一个项目(shared_buffers),其余的几乎默认。

更新 跳过旧配置 我用旧的替换了配置,但仍然遇到了同样的问题,除了现在一切都慢了。

值得注意的更新 当我添加

时,查询再次变得闪电般快速
ANALYZE source_table1;
ANALYZE source_table2;
ANALYZE source_table3;

在运行查询之前查询的最大表。我以前没必要这样做,而且工作得非常好。

1 个答案:

答案 0 :(得分:1)

这是一个可以解释您所看到的行为的场景。这假设source_table {1,2,3}在计算查询之前是直接重建的(因为当它是ETL的一部分时会发生):

在:

  • 创建查询的源表
  • autovacuum有时间在桌面上进行分析,而其他一些过程完成
  • postgres在查询中选择正确的计划

如果现在数据或ETL发生了一些变化,这导致postgres在查询之前没有时间进行autovacuum,那么统计信息就会关闭,查询执行时间也会爆炸。