Postgresql Postgres:如何有效地对以下随机事件id(小时、配置id、传感器id)进行备份

Postgresql Postgres:如何有效地对以下随机事件id(小时、配置id、传感器id)进行备份,postgresql,Postgresql,我有一个大表“测量”,有4列: measurement-service=> \d measurement Table "public.measurement" Column | Type | Collation | Nullable | Default -----------------------+------------------------

我有一个大表“测量”,有4列:

measurement-service=> \d measurement
                                Table "public.measurement"
        Column         |            Type             | Collation | Nullable | Default 
-----------------------+-----------------------------+-----------+----------+---------
 hour                  | timestamp without time zone |           | not null | 
 config_id             | bigint                      |           | not null | 
 sensor_id             | bigint                      |           | not null | 
 event_id              | uuid                        |           | not null | 
Partition key: RANGE (hour)
Indexes:
    "hour_config_id_sensor_id_event_id_key" UNIQUE CONSTRAINT, btree (hour, config_id, sensor_id, event_id)
Number of partitions: 137 (Use \d+ to list them.)
分区名称示例:“measurement_y2019m12d04”

然后我通过复制将许多事件作为CSV插入到一个临时表中,然后使用ON CONFLICT DO NOTHING将表直接复制到分区中

例如:

CREATE TEMPORARY TABLE 'tmp_measurement_y2019m12d04T02_12345' (
  hour timestamp without timezone,
  config_id bigint,
  sensor_id bigint,
  event_id uuid
) ON COMMIT DROP;
[...]
COPY tmp_measurement_y2019m12d04T02_12345 FROM STDIN DELIMITER ',' CSV HEADER;
INSERT INTO measurement_y2019m12d04 (SELECT * FROM tmp_measurement_y2019m12d04T02_12345) ON CONFLICT DO NOTHING;
我想我可以通过只发送同一小时的CSV数据来帮助postgres。同样在这一小时内,我删除了CSV中的所有重复项。因此,CSV只包含唯一的行


但我发送了不同时间的许多批次。没有秩序。它可以是今天、昨天、最后一周的时间。等等

到目前为止,我的方法还不错,但我想我已经达到了极限。插入速度变得非常慢。当CPU空闲时,我有25%的i/o等待。子系统是一个具有多TB的RAID,使用非SSD的磁盘

maintenance_work_mem = 32GB
max_wal_size = 1GB
fsync = off
max_worker_processes = 256
wal_buffers = -1
shared_buffers = 64GB
temp_buffers = 4GB
effective_io_concurrency = 1000
effective_cache_size = 128GB
每天每个分区的大小约为20gb,包含的行数不超过500万行。通过维护每个分区的唯一索引,我只需再次复制数据

另一方面,查找速度很快

我认为限制是在维护btree时使用了相当随机的UUID(小时、配置id、传感器id)。我不断地修改它,把它写出来,然后重新阅读

我想知道,是否还有其他办法。基本上,我需要(小时、配置id、传感器id、事件id)的唯一性,然后每个(小时、配置id、传感器id)快速查找

我正在考虑删除唯一索引,并且只有一个索引超过(小时、配置id、传感器id)。然后在读者端提供唯一性。但它可能会减慢读取速度,因为当我通过(小时、配置id、传感器id)查找时,事件id无法再通过索引传递。它必须访问实际行才能获取事件id

或者我通过散列索引提供唯一性

欢迎任何其他想法


谢谢。

执行插入操作时,应指定与要插入的表的索引相匹配的顺序:

INSERT INTO measurement_y2019m12d04 
    SELECT * FROM tmp_measurement_y2019m12d04T02_12345 
        order by hour, config_id, sensor_id, event_id
仅当这不能给予足够的改进时,我会考虑你列出的其他选项。

哈希索引不提供唯一性。您可以使用排除约束来模拟它,但我认为它们效率较低。排除约束不支持不执行任何操作,但不支持执行更新。因此,只要您的用例不演变为想要进行更新,您在这方面就做得很好,但我仍然怀疑它是否真的能解决问题。如果您的瓶颈是更新索引的IO,那么哈希只会使情况变得更糟,因为它被设计成将您的数据分散在所有地方,而不是将其集中在一个小的可缓存区域


您还提到了并行处理。对于插入temp表,这可能很好。但我不会同时插入…选择。如果IO是你的瓶颈,那可能只会让事情变得更糟。当然,如果依建议订购后IO不再是瓶颈,则忽略此部分。

“但我针对不同的时间发送了许多批次。没有订单。可能是今天、昨天、上周等的时间。”但您只显示一个临时表。您是否对不同日期的原始数据进行多次传递?还是同时填充多个临时表?作为索引中的最后一列,uuid的随机性不太重要。对于任何给定负载中的相同组合(小时、配置id、传感器id),有多少不同的事件id?是的,我同时填充多个临时表。它可以是每小时数百或数千个不同的id(小时、配置id、传感器id)。为什么你认为这个活动可能不是很重要?它仍然需要被排序到索引中。一旦它在前面三个字段上排序,应该将最后一个字段上的“工作集”的大小减小到一定程度,即使没有排序,它也会被很好地缓存。除非前三个字段的每个组合在任何给定负载中仍然可以有数百万个uuid。您需要唯一的约束吗?如果您在客户端的小时内进行重复数据消除,并且小时是唯一索引的一部分,因此根据定义,具有不同小时的内容不能重复,那么重复是如何产生的?您的一小时内重复数据消除是否纯粹是一种“尽力而为”的做法,而且不能保证有效?