由于我是一名年轻的开发人员,并且不太熟练使用数据库(PostgreSQL 9.3),因此我在一个项目中遇到了一些问题,我确实需要帮助。
我的项目是关于从设备(最多1000台或更多设备)收集数据的,其中每台设备每秒发送一个数据块,每小时大约发送300万行。
目前,我有一张大表,用于存储每个设备的传入数据:
CREATE TABLE data_block(
id bigserial
timestamp timestamp
mac bigint
)
由于数据块可以(或不能)包含多种数据类型,因此还有其他表引用该data_block
表。
CREATE TABLE dataA(
data_block_id bigserial
data
CONSTRAINT fkey FOREIGN KEY (data_block_id) REFERENCES data_block(id);
);
CREATE TABLE dataB(...);
CREATE TABLE dataC(...);
CREATE INDEX index_dataA_block_id ON dataA (data_block_id DESC);
...
一个data_block中可能有3x dataA,1x dataB但没有dataC。
数据将保留几周,因此该表中将有约50亿行。目前,表中有约6亿行,而我的查询要花很长时间。因此,我决定在timestamp
和上建立索引mac
,因为我的select语句总是随时间查询,通常也随时间+ mac查询。
CREATE INDEX index_ts_mac ON data_block (timestamp DESC, mac);
...但是我的查询仍然需要很长时间。例如,我查询了一天和一台Mac的数据:
SELECT * FROM data_block
WHERE timestamp>'2014-09-15'
AND timestamp<'2014-09-17'
AND mac=123456789
Index Scan using index_ts_mac on data_block (cost=0.57..957307.24 rows=315409 width=32) (actual time=39.849..334534.972 rows=285857 loops=1)
Index Cond: ((timestamp > '2014-09-14 00:00:00'::timestamp without time zone) AND (timestamp < '2014-09-16 00:00:00'::timestamp without time zone) AND (mac = 123456789))
Total runtime: 334642.078 ms
在查询运行之前,我做了充分的准备工作。有没有一种优雅的方法可以解决大表查询少于10秒的问题?
我读到了有关分区的信息,但这不适用于dataA,dataB,dataC对data_block_id的引用,对吗?如果可以正常工作,我应该随着时间的推移还是通过Mac进行分区?
我将索引更改为另一个方向。首先是MAC,然后是时间戳,它获得了很多性能。
CREATE INDEX index_mac_ts ON data_block (mac, timestamp DESC);
但是查询仍然需要30秒以上。特别是当我对LEFT JOIN
数据表进行处理时。以下是EXPLAIN ANALYZE
带有新索引的查询:
EXPLAIN ANALYZE SELECT * FROM data_block WHERE mac = 123456789 AND timestamp < '2014-10-05 00:00:00' AND timestamp > '2014-10-04 00:00:00'
Bitmap Heap Scan on data_block (cost=1514.57..89137.07 rows=58667 width=28) (actual time=2420.842..32353.678 rows=51342 loops=1)
Recheck Cond: ((mac = 123456789) AND (timestamp < '2014-10-05 00:00:00'::timestamp without time zone) AND (timestamp > '2014-10-04 00:00:00'::timestamp without time zone))
-> Bitmap Index Scan on index_mac_ts (cost=0.00..1499.90 rows=58667 width=0) (actual time=2399.291..2399.291 rows=51342 loops=1)
Index Cond: ((mac = 123456789) AND (timestamp < '2014-10-05 00:00:00'::timestamp without time zone) AND (timestamp > '2014-10-04 00:00:00'::timestamp without time zone))
Total runtime: 32360.620 ms
不幸的是,我的硬件受到严格限制。我正在使用Intel i3-2100 @ 3.10Ghz,4GB RAM。我当前的设置如下:
default_statistics_target = 100
maintenance_work_mem = 512MB
constraint_exclusion = on
checkpoint_completion_target = 0.9
effective_cache_size = 4GB
work_mem = 512MB
wal_buffers = 16MB
checkpoint_segments = 32
shared_buffers = 2GB
max_connections = 20
random_page_cost = 2