TL; DR
我有一个问题表,查询非常慢。我在上面运行pg_repack来重建表,但是它仍然很慢。不幸的是,pg_repack没有重建表。我必须通过pg_dump转储并重新加载表。
分析显示很多死行。
# analyse verbose payslip;
INFO: analyzing "public.payslip"
INFO: "payslip": scanned 30000 of 458337 pages, containing 8732 live rows and 400621 dead rows; 8732 rows in sample, 133407 estimated total rows
ANALYZE
自动真空无法正常工作。本文确定了潜在的问题...
https://www.cybertec-postgresql.com/en/reasons-why-vacuum-wont-remove-dead-rows/
原始线程
我有一张有14万行的表,每周增加约500行。
几周前,我调查了表上的查询,发现所有查询都很慢。例如,select count()花费了6秒。我使用pg_repack重建了表,并假定那是表的结尾。我注意到表格今天又变慢了,选择计数()为3秒。
数据库中有138个表,只有另一个表(具有130万行)花费了超过一秒钟的时间来进行选择计数(*)。
我想知道是否存在损坏,这是否是Postgres中的错误或是否存在调整问题。
信息
这是今天通过psql的计数
# select count(*) from payslip;
count
--------
140327
(1 row)
Time: 3255.772 ms (00:03.256)
这是查询计划
# explain select count(*) from payslip;
QUERY PLAN
------------------------------------------------------------------------------------------
Aggregate (cost=142820.48..142820.49 rows=1 width=8)
-> Bitmap Heap Scan on payslip (cost=22543.92..142479.77 rows=136285 width=0)
-> Bitmap Index Scan on payslip_idx3 (cost=0.00..22509.84 rows=136285 width=0)
(3 rows)
这是数据模型(被截断)。
Table "public.payslip"
Column | Type | Collation | Nullable | Default
--------------------------+------------------------+-----------+----------+----------------------------------------------
taxregno | character varying(20) | | not null |
worksid | character varying(8) | | not null |
cutoffdate | character(10) | | not null |
productionid | integer | | not null |
...
Ignore 50 columns
Indexes:
"payslip_pkey" PRIMARY KEY, btree (taxregno, worksid, cutoffdate, productionid)
"payslip_k1" UNIQUE, btree (taxregno, worksid, cutoffdate, productionid)
"payslip_idx3" btree (worksid)
"payslip_idx4" btree (ppsnumber)
Postgres版本当前为11。此数据库库从Postgres 8迁移到当前版本已有10多年的历史。我只是按照各种Ubuntu升级中的说明进行操作。
$ psql -V
psql (PostgreSQL) 11.3 (Ubuntu 11.3-1.pgdg14.04+1)
服务器在具有SSD存储的Linode linux机器上运行。我设置了postgresql.conf页面成本以反映SSD。
#seq_page_cost = 1.0 # measured on an arbitrary scale
random_page_cost = 1.0 # same scale as above
今天
不幸的是,这是生产服务器,我需要在短期内解决性能问题。因此,我现在再次运行pg_repack。
在pg_repack之后
# select count(*) from payslip;
count
--------
140327
(1 row)
Time: 26.216 ms
# explain select count(*) from payslip;
QUERY PLAN
----------------------------------------------------------------------
Aggregate (cost=10974.09..10974.10 rows=1 width=8)
-> Seq Scan on payslip (cost=0.00..10623.27 rows=140327 width=0)
(2 rows)
按照下面的a_horse_with_no_name的要求,这里是进一步的信息。如上所述,这是在重建表后进行的。
# explain (analyze, buffers, timing) select count(*) from payslip;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------
Aggregate (cost=12850.75..12850.76 rows=1 width=8) (actual time=42.070..42.071 rows=1 loops=1)
Buffers: shared hit=11022
-> Seq Scan on payslip (cost=0.00..12485.00 rows=146300 width=0) (actual time=0.010..31.669 rows=140327 loops=1)
Buffers: shared hit=11022
Planning Time: 0.102 ms
Execution Time: 42.115 ms
(6 rows)
一周后更新。
这是一个安静的一周。该表增加了250行。 select count(*)从.04秒减至.7秒。该查询从较快的顺序扫描更改为较慢的位图索引扫描。
select count(*) from payslip;
140572
Time: 643.144 ms
这是细节。
explain (analyze, buffers, timing) select count(*) from payslip;
Aggregate (cost=108251.57..108251.58 rows=1 width=8) (actual time=718.015..718.016 rows=1 loops=1)
Buffers: shared hit=169407
-> Bitmap Heap Scan on payslip (cost=8522.42..107900.14 rows=140572 width=0) (actual time=229.612..707.319 rows=140572 loops=1)
Heap Blocks: exact=76839 lossy=84802
Buffers: shared hit=169407
-> Bitmap Index Scan on payslip_idx3 (cost=0.00..8487.28 rows=140572 width=0) (actual time=205.228..205.228 rows=2212168 loops=1)
Buffers: shared hit=7757
Planning Time: 0.115 ms
Execution Time: 718.069 ms
两周后更新
距我重建桌子已经两周了。本周表增加了340行。选择计数(*)时间从0.6秒减少到2秒。
select count(*) from payslip;
count
--------
140914
(1 row)
Time: 2077.577 ms (00:02.078)
查询计划没有变化,执行速度慢得多。
explain (analyze, buffers, timing) select count(*) from payslip;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=138089.00..138089.01 rows=1 width=8) (actual time=2068.305..2068.305 rows=1 loops=1)
Buffers: shared hit=8 read=324086 written=1
-> Bitmap Heap Scan on payslip (cost=17071.92..137736.72 rows=140914 width=0) (actual time=270.512..2056.755 rows=140914 loops=1)
Heap Blocks: exact=8198 lossy=301091
Buffers: shared hit=8 read=324086 written=1
-> Bitmap Index Scan on payslip_idx3 (cost=0.00..17036.69 rows=140914 width=0) (actual time=268.801..268.801 rows=4223367 loops=1)
Buffers: shared read=14794
Planning Time: 0.164 ms
Execution Time: 2068.623 ms
(9 rows)
Time: 2069.567 ms (00:02.070)
所选索引(idx3)是重复索引,在140k记录中具有22k唯一值。位图索引扫描表明,本周(插入400次之后)扫描了400万行,上周对同一查询扫描了200万行,这与性能下降相符。
来自索引维护查询的信息(由richyen建议)
relname | rows_in_bytes | num_rows | number_of_indexes | unique | single_column | multi_column
---------+---------------+----------+-------------------+--------+---------------+--------------
payslip | 138 kB | 140914 | 4 | Y | 2 | 2
schemaname | tablename | indexname | num_rows | table_size | index_size | unique | number_of_scans | tuples_read | tuples_fetched
------------+-----------+--------------+----------+------------+------------+--------+-----------------+-------------+----------------
public | payslip | payslip_k1 | 140914 | 2420 MB | 244 MB | Y | 39720 | 3292501603 | 14295183
public | payslip | payslip_idx4 | 140914 | 2420 MB | 156 MB | N | 43013 | 9529447977 | 34943724
public | payslip | payslip_idx3 | 140914 | 2420 MB | 116 MB | N | 42812 | 3067603558 | 72358879
public | payslip | payslip_pkey | 140914 | 2420 MB | 244 MB | Y | 3540 | 203676311 | 4213496
(4 rows)
size | idx1 | idx2 | idx3 | idx4
---------+------------------------------+---------------------------------+----------------------+------
488 MB | payslip_pkey | payslip_k1 | |
在这个阶段,我重新设计了表索引。我将主键设为序列中的整数值,并在所有索引中都包含序列号以使其唯一。
自从重建索引以来,选择计数(*)回到了顺序扫描。我将不得不等待表增长一点,以查看查询是否使数百万行读取。
explain (analyze, buffers, timing) select count(*) from payslip;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=312850.42..312850.43 rows=1 width=8) (actual time=1348.241..1348.242 rows=1 loops=1)
Buffers: shared hit=199941 read=111148
-> Seq Scan on payslip (cost=0.00..312498.14 rows=140914 width=0) (actual time=209.227..1336.035 rows=140914 loops=1)
Buffers: shared hit=199941 read=111148
Planning Time: 0.069 ms
Execution Time: 1348.289 ms
(6 rows)
现在索引信息
schemaname | tablename | indexname | num_rows | table_size | index_size | unique | number_of_scans | tuples_read | tuples_fetched
------------+-----------+--------------+----------+------------+------------+--------+-----------------+-------------+----------------
public | payslip | payslip_pkey | 140914 | 2430 MB | 91 MB | Y | 0 | 0 | 0
public | payslip | payslip_idx2 | 140914 | 2430 MB | 202 MB | Y | 0 | 0 | 0
public | payslip | payslip_idx4 | 140914 | 2430 MB | 128 MB | Y | 0 | 0 | 0
public | payslip | payslip_idx3 | 140914 | 2430 MB | 128 MB | N | 0 | 0 | 0
(4 rows)
问题已解决
我终于找到了解决方案。我的问题是我假设pg_repack按照建议的名称重建了表。没有。桌子完全零散了。
由于某种原因,我不知道为什么使用分散的表,PostgreSQL决定执行顺序扫描而不是索引扫描。
这是我应该看的。
# analyse verbose payslip;
INFO: analyzing "public.payslip"
INFO: "payslip": scanned 30000 of 458337 pages, containing 8732 live rows and 400621 dead rows; 8732 rows in sample, 133407 estimated total rows
ANALYZE
使用pg_dump并重新加载表可以很快解决问题。
我进一步研究了这个问题,并找到了这篇很棒的文章。
https://www.cybertec-postgresql.com/en/reasons-why-vacuum-wont-remove-dead-rows/
数据库中有两个准备不好的事务,导致自动真空无法正常工作。
-#FROM pg_prepared_xacts
-#ORDER BY age(transaction)DESC;
gid |准备业主|数据库| xmin
-------------------------------------- + ----------- -------------------- + ------- + ---------- + ---------
_sa_4f7780bb6653ccb70ddaf2143ac7a232 | 2019-08-12 13:00:11.738766 + 01 |凯文|凯文| 1141263
_sa_0db277aebcb444884763fe6245d702fe | 2019-09-19 14:00:11.977378 + 01 |凯文|凯文| 2830229
(2行)
感谢大家的帮助。
答案 0 :(得分:1)
从上周到本周的变化表明,Future runmodel() async {
manager.registerLocalModelSource(FirebaseLocalModelSource(
modelName: 'mobilenet_v10',
assetFilePath: 'assets/mobilenet_v2.tflite'));
var imageBytes = (await rootBundle.load('assets/download.jpg')).buffer;
img.Image image = img.decodeJpg(imageBytes.asUint8List());
image = img.copyResize(image, height: 224, width: 224);
var results = await interpreter.run();
print(results);}
的许多数据不再在缓存中(请参阅{{1}中payslip
和hit
的变化}}部分。
还要注意,您的read
越来越多Buffers:
,这意味着您可能将Heap Blocks
设置得过低。
这周您可能应该将lossy
至少增加到work_mem
(因为最新的统计数据表明正在访问约309,000个页面块)。但是,随着表的增长,您可能需要增加它的数量。{work_mem
可以基于每个会话进行设置,因此您需要根据表的基于模式的预测进行设置大小(我不喜欢这个主意,但也不建议将25MB
设置为任意高,因为全局设置可能会导致内存过度分配)
我对work_mem
的内部内容不是很清楚,但是我想知道您是否看到重新打包后的性能提高,因为东西被存储在内存中,并随着时间的流逝而被冲刷掉。
披露:我为EnterpriseDB (EDB)工作