我在 Ubuntu 12.04 上使用 PostgreSQL 9.1。
我需要在一个时间范围内选择记录:我的表time_limits有两个timestamp字段和一个integer属性。我的实际表中还有其他列与此查询无关。
create table (
start_date_time timestamp,
end_date_time timestamp,
id_phi integer,
primary key(start_date_time, end_date_time,id_phi);
Run Code Online (Sandbox Code Playgroud)
该表包含大约 200 万条记录。
像下面这样的查询花费了大量的时间:
select * from time_limits as t
where t.id_phi=0
and t.start_date_time <= timestamp'2010-08-08 00:00:00'
and t.end_date_time >= timestamp'2010-08-08 00:05:00';
Run Code Online (Sandbox Code Playgroud)
所以我尝试添加另一个索引 - PK的倒数:
create index idx_inversed on time_limits(id_phi, start_date_time, end_date_time);
Run Code Online (Sandbox Code Playgroud)
我的印象是性能有所提高:访问表中间记录的时间似乎更合理:介于 40 到 90 秒之间。
但是对于时间范围中间的值,它仍然是几十秒。在针对表格末尾时(按时间顺序),还有两次。
我explain analyze第一次尝试得到这个查询计划:
Bitmap Heap Scan on time_limits (cost=4730.38..22465.32 rows=62682 width=36) (actual time=44.446..44.446 rows=0 loops=1)
Recheck …Run Code Online (Sandbox Code Playgroud) 我们的系统写入了大量数据(一种大数据系统)。写入性能足以满足我们的需求,但读取性能真的太慢了。
我们所有表的主键(约束)结构都相似:
timestamp(Timestamp) ; index(smallint) ; key(integer).
Run Code Online (Sandbox Code Playgroud)
一个表可以有数百万行,甚至数十亿行,而一个读请求通常是针对特定时间段(时间戳/索引)和标记的。查询返回大约 20 万行是很常见的。目前,我们每秒可以读取大约 15k 行,但我们需要快 10 倍。这是可能的,如果是,如何?
注意: PostgreSQL 是和我们的软件一起打包的,所以不同客户端的硬件是不一样的。
它是一个用于测试的虚拟机。VM 的主机是具有 24.0 GB RAM 的 Windows Server 2008 R2 x64。
Server 2008 R2 x64
2.00 GB of memory
Intel Xeon W3520 @ 2.67GHz (2 cores)
Run Code Online (Sandbox Code Playgroud)
postgresql.conf 优化shared_buffers = 512MB (default: 32MB)
effective_cache_size = 1024MB (default: 128MB)
checkpoint_segment = 32 (default: 3)
checkpoint_completion_target = 0.9 (default: 0.5)
default_statistics_target = 1000 (default: 100)
work_mem = 100MB (default: 1MB)
maintainance_work_mem = 256MB …Run Code Online (Sandbox Code Playgroud) 从文档:
在 PostgreSQL 中,行的 UPDATE 或 DELETE不会立即删除该行的旧版本[...] 但最终,任何事务都不再对过时或删除的行版本感兴趣。然后必须回收它占用的空间以供新行重用,以避免磁盘空间需求的无限增长。这是通过运行 VACUUM来完成的。
当vacuum运行时,它是否通过重写整个块来有效地释放被删除行占用的空间,或者只有当新行小于为它们让路的已删除行时,才会在新行适合可用“孔”时发生块碎片?
由于频繁的新记录和更新记录导致索引和存储碎片,我面临性能下降和存储使用量增加的问题。
VACUUM 没有多大帮助。
不幸的是,CLUSTER 不是一个选项,因为它会导致停机并且 pg_repack 不适用于 AWS RDS。
我正在寻找 CLUSTER 的 hacky 替代品。在我的本地测试中似乎可以正常工作的一个是:
begin;
create temp table tmp_target as select * from target;
delete from target;
insert into target select * from tmp_target order by field1 asc, field2 desc;
drop table tmp_target;
commit;
Run Code Online (Sandbox Code Playgroud)
ctid看起来的顺序是正确的:
select ctid, field1, field2 from target order by ctid;
Run Code Online (Sandbox Code Playgroud)
问题是:这看起来好吗?是否会锁定target表以SELECT查找导致应用程序停机的查询?有没有办法列出事务中涉及的锁?
postgresql ×4
clustering ×1
explain ×1
index ×1
locking ×1
optimization ×1
performance ×1
vacuum ×1