【发布时间】:2016-04-17 11:19:34
【问题描述】:
我目前正在从事一个项目,该项目从现场的无线调制解调器网络收集大量数据。我们有一个如下所示的“读数”表:
CREATE TABLE public.readings (
id INTEGER PRIMARY KEY NOT NULL DEFAULT nextval('readings_id_seq'::regclass),
created TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT now(),
timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL,
modem_serial CHARACTER VARYING(255) NOT NULL,
channel1 INTEGER NOT NULL,
channel2 INTEGER NOT NULL,
signal_strength INTEGER,
battery INTEGER,
excluded BOOLEAN NOT NULL DEFAULT false
);
CREATE UNIQUE INDEX _timestamp_modemserial_uc ON readings USING BTREE (timestamp, modem_serial);
CREATE INDEX ix_readings_timestamp ON readings USING BTREE (timestamp);
CREATE INDEX ix_readings_modem_serial ON readings USING BTREE (modem_serial);
对于系统的完整性,我们永远不会有来自同一调制解调器的两个读数具有相同的时间戳,因此是唯一索引。
我们目前的挑战是找到一种插入读数的高效方法。当我们引入历史数据时,我们经常需要插入数百万行,当添加到现有的超过 1 亿个读数的基础上时,这可能会有点慢。
我们当前的方法是将 10,000 个读数批量导入到一个临时读数表中,该表本质上是读数的未索引副本。然后我们运行以下 SQL 将其合并到主表中并删除重复项:
INSERT INTO readings (created, timestamp, modem_serial, channel1, channel2, signal_strength, battery)
SELECT DISTINCT ON (timestamp, modem_serial) created, timestamp, modem_serial, channel1, channel2, signal_strength, battery
FROM temporary_readings
WHERE NOT EXISTS(
SELECT * FROM readings
WHERE timestamp=temporary_readings.timestamp
AND modem_serial=temporary_readings.modem_serial
)
ORDER BY timestamp, modem_serial ASC;
这很好用,但插入每 10,000 行块需要大约 20 秒。我的问题是双重的:
- 这是解决问题的最佳方法吗?我对具有这些性能要求的项目比较陌生,所以我很想知道是否有更好的解决方案。
- 我可以采取哪些步骤来加快插入过程?
提前致谢!
【问题讨论】:
-
您能否详细描述一下您的用例 - 您需要实时对读数进行重复数据删除,还是要为分析构建一个仓库?
-
temporary_readings表是否有任何结构或约束(例如 PK 或 UNIQUE 约束)?
标签: sql performance postgresql sql-insert