gpt4 book ai didi

sql - Postgres : huge table with (delayed) read and write access

转载 作者:行者123 更新时间:2023-11-29 12:33:24 24 4
gpt4 key购买 nike

我有一个巨大的表(目前大约有 300 万行,预计会增加 1000 倍)每秒有很多插入。该表永远不会更新。

现在我必须对该表运行查询,这非常慢(正如预期的那样)。这些查询不必 100% 准确,如果结果是一天前的(但不是更早的)也没关系。

目前在两个单个整数列上有两个索引,我必须再添加两个索引(整数和时间戳列)以加快查询速度。

到目前为止我的想法:

  1. 将两个缺失的索引添加到表中
  2. 巨大的表上根本没有索引并将内容(作为日常任务)复制到第二个表(只是重要的行),然后在第二个表上创建索引并在该表上运行查询?
  3. 对巨大的表进行分区
  4. 主/从设置(写入主设备并从从设备读取)。

就性能而言,哪个选项最好?你有什么其他的建议?

编辑:

这是表格(我已经标记了外键并稍微美化了查询):

CREATE TABLE client_log
(
id serial NOT NULL,
logid integer NOT NULL,
client_id integer NOT NULL, (FOREIGN KEY)
client_version varchar(16),
sessionid varchar(100) NOT NULL,
created timestamptz NOT NULL,
filename varchar(256),
funcname varchar(256),
linenum integer,
comment text,
domain varchar(128),
code integer,
latitude float8,
longitude float8,
created_on_server timestamptz NOT NULL,
message_id integer, (FOREIGN KEY)
app_id integer NOT NULL, (FOREIGN KEY)
result integer
);

CREATE INDEX client_log_code_idx ON client_log USING btree (code);
CREATE INDEX client_log_created_idx ON client_log USING btree (created);
CREATE INDEX clients_clientlog_app_id ON client_log USING btree (app_id);
CREATE INDEX clients_clientlog_client_id ON client_log USING btree (client_id);
CREATE UNIQUE INDEX clients_clientlog_logid_client_id_key ON client_log USING btree (logid, client_id);
CREATE INDEX clients_clientlog_message_id ON client_log USING btree (message_id);

还有一个示例查询:

SELECT 
client_log.comment,
COUNT(client_log.comment) AS count
FROM
client_log
WHERE
client_log.app_id = 33 AND
client_log.code = 3 AND
client_log.client_id IN (SELECT client.id FROM client WHERE
client.app_id = 33 AND
client."replaced_id" IS NULL)
GROUP BY client_log.comment ORDER BY count DESC;

client_log_code_idx 是上述查询所需的索引。还有其他查询需要 client_log_created_idx 索引。

和查询计划:

Sort  (cost=2844.72..2844.75 rows=11 width=242) (actual time=4684.113..4684.180 rows=70 loops=1)
Sort Key: (count(client_log.comment))
Sort Method: quicksort Memory: 32kB
-> HashAggregate (cost=2844.42..2844.53 rows=11 width=242) (actual time=4683.830..4683.907 rows=70 loops=1)
-> Hash Semi Join (cost=1358.52..2844.32 rows=20 width=242) (actual time=303.515..4681.211 rows=1202 loops=1)
Hash Cond: (client_log.client_id = client.id)
-> Bitmap Heap Scan on client_log (cost=1108.02..2592.57 rows=387 width=246) (actual time=113.599..4607.568 rows=6962 loops=1)
Recheck Cond: ((app_id = 33) AND (code = 3))
-> BitmapAnd (cost=1108.02..1108.02 rows=387 width=0) (actual time=104.955..104.955 rows=0 loops=1)
-> Bitmap Index Scan on clients_clientlog_app_id (cost=0.00..469.96 rows=25271 width=0) (actual time=58.315..58.315 rows=40662 loops=1)
Index Cond: (app_id = 33)
-> Bitmap Index Scan on client_log_code_idx (cost=0.00..637.61 rows=34291 width=0) (actual time=45.093..45.093 rows=36310 loops=1)
Index Cond: (code = 3)
-> Hash (cost=248.06..248.06 rows=196 width=4) (actual time=61.069..61.069 rows=105 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 4kB
-> Bitmap Heap Scan on client (cost=10.95..248.06 rows=196 width=4) (actual time=27.843..60.867 rows=105 loops=1)
Recheck Cond: (app_id = 33)
Filter: (replaced_id IS NULL)
Rows Removed by Filter: 271
-> Bitmap Index Scan on clients_client_app_id (cost=0.00..10.90 rows=349 width=0) (actual time=15.144..15.144 rows=380 loops=1)
Index Cond: (app_id = 33)
Total runtime: 4684.843 ms

最佳答案

一般来说,在不断将与时间相关的数据插入数据库的系统中,我建议使用 partitioning根据时间。

这不仅是因为它可以缩短查询时间,还因为否则会使数据管理变得困难。无论您的硬件有多大,它的容量都会受到限制,因此您最终将不得不开始删除早于某个日期的行。您删除行的速率必须等于它们进入的速率。

如果您只有一个大表,并且使用 DELETE 删除旧行,您将留下大量需要清除的死元组。 autovacuum 将持续运行,耗尽宝贵的磁盘 IO。

另一方面,如果您根据时间进行分区,那么删除过期数据就像删除相关子表一样容易。

在索引方面 - 索引不是继承的,因此您可以在加载分区之前节省创建索引的时间。在您的用例中,您的分区大小可能为 1 天。这意味着索引不需要在插入数据时不断更新。根据需要使用额外的索引来执行查询会更加实用。

您的示例查询不会过滤“创建”时间字段,但您说其他查询会过滤。如果您按时间分区,并且小心构建查询的方式,约束排除将会启动,它只会包括与查询相关的特定分区。

关于sql - Postgres : huge table with (delayed) read and write access,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25542010/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com