问题陈述:
我们有一个以 Postgresql db 作为后端的企业产品。其中一个表有 5 列,相应的数据类型为 (bigint time、bigint store_time、varchar category、varchar sub_catorgy、integer count)。总共有 1500 万条唯一记录。
客观的:
我们正在尝试在 1 或 2 秒的响应时间内获取/选择约 1400 万条记录以显示在 UI 中。
目前的观察与分析:
我们设计了如下所示的选择语句来获取 1400 万条记录
查询 — “从时间介于 1541156340000 和 1560509940000 之间的表中选择时间、类别、子类别、计数”
时间以纪元 (Epoch) 为单位维护。
表在时间、类别、子类别和计数列上有索引。存储未在任何地方使用的时间列。
在 pgadmin / 同一服务器框 postgres 命令行中运行上述查询时,耗时约 25 秒来检索约 1400 万条记录。
我们尝试了顺序扫描和索引扫描,修改了postgresql.conf
文件中的以下参数。两者都花费了相同的 25 秒(没有差异)
尝试 1:
enable_indexscan = on
enable_seqscan = on
尝试2:
enable_indexscan = on
enable_seqscan = off
在使用“EXPLAIN ANALYZE Select Time, category,sub_category,count from table where time between 1541156340000 and 1560509940000”命令分析查询计划时,我们可以看到,总执行时间约为 3-4 秒,而单独运行选择查询(Select Time, category,sub_category,count from table where time between 1541156340000 and 1560509940000)则耗时 25 秒。(不确定,原始选择查询执行时间和“EXPLAIN ANALYZE”执行时间之间的差异是什么。我们假设两者应该相同。- 请确认我们对此理解是否错误)
解释分析输出:
"Seq Scan on table (cost=0.00..393652.98 rows=13540999 width=52) (actual time=0.007..3346.241 rows=13545864 loops=1)"
" Filter: ((time >= '1541156340000'::bigint) AND (time <= '1560509940000'::bigint))"
"Planning time: 0.192 ms"
"Execution time: 3733.535 ms"
我们还尝试过在 postgresql 配置文件中更改以下参数,考虑到机器容量(24 核 - 超线程、128 GB RAM、4 TB 磁盘),但仍然没有成功。使用默认参数值也观察到了相同的性能数字。
笔记:
在 128 GB RAM 中,我们的应用程序 JVM 使用 24 GB RAM。应用程序和 Postgresql DB 都位于同一个 JVM 中。在查询执行期间,资源利用率仅正常。
参数调整:
shared_buffers = 6GB
effective_cache_size = 18GB
maintenance_work_mem = 1536MB
checkpoint_completion_target = 0.7
wal_buffers = 16MB
default_statistics_target = 100
random_page_cost = 1
autovacuum = on
seq_page_cost = 1.0
effective_io_concurrency = 200
work_mem = 62914kB
min_wal_size = 1GB
max_wal_size = 2GB
笔记:
查询执行仅耗时 25 秒。查询执行后,我们就能在 UI 中看到结果。因此考虑到这一点,查询结果与在 UI 中显示之间没有延迟。
预期结果
我们期望上述选择查询应在 1 或 2 秒内返回结果。
我们需要一些帮助来调整查询或参数以提高性能。