PostgreSQL 在写入密集型数据库上的性能随着时间的推移而下降

Bor*_*oro 5 postgresql performance database-tuning postgresql-9.1

我观察到一个奇怪的情况,随着时间的推移,查询(下面解释的查询组合)的性能会下降,这意味着在测试开始时(几分钟)查询的时间是 2 毫秒,然后第二天它变成了 15 毫秒然后是 30 毫秒后的一天。

通过查询,我在这里指的是以下任一者的组合:

  • 在表 2 中插入一行,从表 2 中选择一行,在表 3 中选择一行,更新表 3 中的一行,提交
  • 在表 1 中插入一行,在表 3 中选择一行,在表 3 中更新一行,提交

我想知道可能是什么原因,或者我应该考虑设置配置文件中的哪些设置以及如何设置?我在设置了数据库但未添加主键的 Ubuntu 机器上观察到了这个问题。另一方面,在我开发的 Win 上没有观察到(它在 7 天内平均每个查询 3ms 持续运行)。

我注意到在新数据库(在 Ubuntu 上)中,任何表上都没有主键,这与我开发的数据库相反。缺少主键是否会对此类查询产生负面影响?

我想我会同时问这个问题,因为我正在将我的整个数据库从我的开发机器移到测试机器上。

开发时我使用 PostgreSQL 8.4(CPU:Intel i7 740QM,RAM:6GB),测试时使用 PostgreSQL 9.1(CPU:Intel i3-2100,RAM:3.8GB)。


更新: autovacuum相关参数:

#autovacuum = on        
#log_autovacuum_min_duration = -1   
#autovacuum_max_workers = 3     
#autovacuum_naptime = 1min      
#autovacuum_vacuum_threshold = 50   
#autovacuum_analyze_threshold = 50  
#autovacuum_vacuum_scale_factor = 0.2   
#autovacuum_analyze_scale_factor = 0.1  
#autovacuum_freeze_max_age = 200000000  
#autovacuum_vacuum_cost_delay = 20ms    
#autovacuum_vacuum_cost_limit = -1  
Run Code Online (Sandbox Code Playgroud)

UPDATE2: 看来问题也出现在开发机器上,但我记得它之前运行良好。尽管如此,我还是做了一些更多的测试,并在查询上运行了 EXPLAIN ANALYZE,这是我花费最多时间的,它是一个更新(我也看到选择在表上需要一段时间)如下所示:

EXPLAIN ANALYZE UPDATE ais_track SET latest_dynamic = '2012-09-10 22:22:22.222' WHERE mmsi = 123456789 AND ais_system = 1;
Run Code Online (Sandbox Code Playgroud)

以下结果在 Win 上,因为在 Ubuntu 上恢复仍在进行中,我一开始得到了这个:

Index Scan using pk_track on ais_track  (cost=0.00..4.46 rows=1 width=36) (actual time=1.090..2.460 rows=1 loops=1)
  Index Cond: ((mmsi = 123456789) AND (ais_system = 1))
Total runtime: 8.681 ms
Run Code Online (Sandbox Code Playgroud)

然后在第二次重复和进一步重复相同的更新查询几次我得到这种形式的东西:

Index Scan using pk_track on ais_track  (cost=0.00..4.46 rows=1 width=36) (actual time=0.699..1.797 rows=1 loops=1)
  Index Cond: ((mmsi = 123456789) AND (ais_system = 1))
Total runtime: 1.850 ms
Run Code Online (Sandbox Code Playgroud)

经过一百次左右的重复后,它超过了 2 毫秒。

选择的解释分析:

EXPLAIN ANALYZE SELECT * FROM ais_track WHERE mmsi = 123456789 AND ais_system = 1
Run Code Online (Sandbox Code Playgroud)

第一次运行:

Index Scan using pk_track on ais_track  (cost=0.00..4.46 rows=1 width=38) (actual time=1.283..2.522 rows=1 loops=1)
  Index Cond: ((mmsi = 123456789) AND (ais_system = 1))
Total runtime: 2.560 ms
Run Code Online (Sandbox Code Playgroud)

经过一百次左右的运行:

Index Scan using pk_track on ais_track  (cost=0.00..4.46 rows=1 width=38) (actual time=0.027..1.357 rows=1 loops=1)
  Index Cond: ((mmsi = 123456789) AND (ais_system = 1))
Total runtime: 1.382 ms
Run Code Online (Sandbox Code Playgroud)

查询中使用的表:

CREATE TABLE ais_track
(
  ais_system integer NOT NULL,
  mmsi integer NOT NULL,
  ext_id integer,
  latest_dynamic timestamp without time zone,
  latest_static timestamp without time zone,
  "name" character varying,
  CONSTRAINT pk_track PRIMARY KEY (mmsi, ais_system)
)
Run Code Online (Sandbox Code Playgroud)

和两个索引:

CREATE INDEX ais_track_mmsi
  ON ais_track
  USING btree
  (mmsi);

CREATE INDEX ais_track_sys
  ON ais_track
  USING btree
  (ais_system);
Run Code Online (Sandbox Code Playgroud)

注意:表格大小为 11000,不会改变。

Col*_*art 5

所有(?)RDBMS 中的主键和唯一键都使用索引来快速确定新插入的值是否确实是唯一的。

这样做的副作用是通过主键和唯一键的查询通常是“快速的”。

现在,如果您尚未在表上定义主键或唯一键,

  1. 你没有关系表,但你有垃圾(好吧,这是一个有争议的意见,但关系模型需要所有表上的键)。
  2. 随着更多数据插入到该表中,对该表的查询(在没有任何其他索引的情况下)将变得更慢。

所以是的,没有主键会导致这个!


Bor*_*oro 3

感谢@Frank Heikens、@dezso 和@Colin 't Hart 的建议和参与,给你们+1。

问题出在我使用MyBatis 的方式上。我使用了一种“特殊”:) 单例模式,它能够在需要时生成新实例,并且为一些常规内容提供一个共享连接。尽管对于我的问题中提到的操作,我使用的是新的连接实例。

显然,使用共享连接并不是一个好主意,正如我的经验所表明的那样,MyBatis 手册也建议在工作完成后提醒关闭连接(会话)。无论如何,问题是我在开始时使用共享连接从数据库加载静态表,然后在完成单一选择后,未使用连接。尽管当我在 ais_track 表上进行查询(即选择和更新)时,操作次数正在增加。我仍然想知道为什么不关闭共享连接会使在不同连接上执行的查询在每次执行时减慢 - 任何建议将不胜感激。

使用普通 JDBC 时我无法重现此问题。所以我认为它一定与MyBatis有关,或者更确切地说我没有使用它?

我的解决方案是摆脱共享资源,一旦我做了一些操作并且我不再使用连接,我就会关闭它。 我还注意到,如果我在使用共享连接进行选择后强制提交,即使它仍然保持打开状态,也不会出现问题。

顺便说一句:请评论是否以及最重要的是,使用单例或换句话说与数据库建立挂起连接是不好的原因(如果事实上我所说的是真的)。