我有一个timescaledb设置,在那里我定期转储数据(每10分钟左右一次)。使用docker-compose进行部署。
数据包括一个entity_id和一个度量以及其他一些东西,例如区域等。
典型的查询是get per day minimum for last 30 days for an entity_id
。
SELECT
time_bucket_gapfill('1 day', time, date_trunc('day', now() - interval '30 days'), date_trunc('day', now())) AS one_day,
country,
type_id,
min(measurement)
FROM hypertable
WHERE
entity_id='XYZ' AND
country='US' AND
time > time_bucket('1 day', now() - interval '30 days') AND
time < time_bucket('1 day', now())
GROUP BY one_day, country, type_id
每个块的大小约为4.5GB
chunk_table | table_size | index_size | total_size
---------------------------------------|-------------------------|------------
_timescaledb_internal._hyper_1_1_chunk | 696 MB | 1675 MB | 2370 MB
_timescaledb_internal._hyper_1_2_chunk | 1318 MB | 3223 MB | 4540 MB
_timescaledb_internal._hyper_1_3_chunk | 1318 MB | 3222 MB | 4539 MB
_timescaledb_internal._hyper_1_4_chunk | 1318 MB | 3223 MB | 4540 MB
数据库当前大约有24个块(24天的数据)。
我一直在使用wrk
做一些基准测试和负载测试,发现大量查询需要几秒钟才能完成。
我看到的问题是timescaledb的ram使用率保持在大约50MB。在运行上述查询的负载测试过程中达到了约100MB,而CPU使用率和磁盘IO则大幅增加。
我期望RAM中大约有一块数据(最近的一块)。 即使这个假设是错误的,当发出30天的查询时,ram的使用也不会增加。
我想了解这是预期的行为还是设置存在问题。
我尝试为docker容器设置内存保留和内存限制,但没有效果。
答案 0 :(得分:0)
PostgreSQL的内存消耗主要与以下方面有关:
shared_buffers:整个PostgreSQL实例的恒定内存量,在所有会话之间共享。 work_mem可用于会话中的排序/哈希操作的内存量。每个会话可以多次使用。
如果您有足够的内存可用于DB Server,则增加shared_buffers
是有意义的,因此会在内存中保留更多数据。传统观点认为,可用RAM的25%是一个很好的起点。在使用docker-compose时,您可能会与其他进程共享该服务器,因此您可能需要对其进行调整以考虑到这一点。
您可以/还应该增加work_mem
,以便更多的哈希/排序操作使用内存而不是磁盘。 work_mem
是可以在会话中设置的变量,因此您可以尝试一些操作,例如,比较以下内容:
feike=# EXPLAIN (ANALYZE ON, BUFFERS ON) SELECT * FROM pg_class ORDER BY relfilenode;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------
Sort (cost=230.82..234.95 rows=1652 width=782) (actual time=3.149..3.477 rows=1680 loops=1)
Sort Key: relfilenode
Sort Method: quicksort Memory: 1246kB
Buffers: shared hit=126
-> Seq Scan on pg_class (cost=0.00..142.52 rows=1652 width=782) (actual time=0.015..0.627 rows=1680 loops=1)
Buffers: shared hit=126
Planning Time: 0.193 ms
Execution Time: 3.908 ms
(8 rows)
feike=# set work_mem to '64kB';
SET
feike=# EXPLAIN (ANALYZE ON, BUFFERS ON) SELECT * FROM pg_class ORDER BY relfilenode;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------
Sort (cost=1371.82..1375.95 rows=1652 width=782) (actual time=6.675..8.102 rows=1680 loops=1)
Sort Key: relfilenode
Sort Method: external merge Disk: 832kB
Buffers: shared hit=126, temp read=239 written=268
-> Seq Scan on pg_class (cost=0.00..142.52 rows=1652 width=782) (actual time=0.015..0.654 rows=1680 loops=1)
Buffers: shared hit=126
Planning Time: 0.192 ms
Execution Time: 8.993 ms
(8 rows)
计划的主要区别在于:
Sort Method: external merge Disk: 832kB
Sort Method: quicksort Memory: 1246kB
找出work_mem
是否有用的最好方法是执行以下操作:
EXPLAIN (ANALYZE ON, BUFFERS ON)
SELECT
time_bucket_gapfill('1 day', time, date_trunc('day', now() - interval '30 days'), date_trunc('day', now())) AS one_day,
country,
type_id,
min(measurement)
FROM hypertable
WHERE
entity_id='XYZ' AND
country='US' AND
time > time_bucket('1 day', now() - interval '30 days') AND
time < time_bucket('1 day', now())
GROUP BY one_day, country, type_id
并查找任何磁盘操作。
这行看起来像这样:
Buffers: shared hit=96 read=44152
告知您shared_buffers
,它找到所需内容的次数(hit
)以及它必须多久从磁盘中获取内容(read
)。
答案太长了一点,但要点是您需要根据工作负载调整PostgreSQL实例的大小。 PostgreSQL的默认设置(非常)保守,这使得它几乎可以在任何地方运行。但是,您似乎想认真使用数据库,因此需要进行一些调整。
一些工具可以帮助您做到这一点: