Ich arbeite derzeit an einem Projekt, das eine sehr große Menge an Daten aus einem Netzwerk von drahtlosen Modems im Feld sammelt. Wir haben eine Tabelle ‚Lesungen‘, der wie folgt aussieht:Effiziente Einfügungen mit doppelten Prüfungen für große Tabellen in Postgres
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);
Es ist wichtig für die Integrität des Systems, das wir nie zwei Lesungen aus dem gleichen Modem mit dem gleichen Zeitstempel haben, daher den eindeutigen Index.
Unsere Herausforderung besteht im Moment darin, eine performante Methode zum Einfügen von Messwerten zu finden. Wir müssen oft Millionen von Zeilen einfügen, wenn wir historische Daten einbringen, und wenn wir sie zu einer bestehenden Basis von 100 Millionen plus Lesungen hinzufügen, kann dies etwas langsam werden.
Unser aktueller Ansatz besteht darin, Chargen von 10.000 Messwerten in eine temporäre Tabelle zu importieren, bei der es sich im Wesentlichen um eine nicht indizierte Kopie der Messwerte handelt. Wir führen dann die folgende SQL es in der Haupttabelle zu verschmelzen und Duplikate entfernen:
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;
Das funktioniert gut, aber dauert ~ 20 Sekunden pro 10.000 Zeilenblock einzufügen. Meine Frage ist zweifach:
- Ist dies der beste Weg, um das Problem anzugehen? Ich bin relativ neu in Projekten mit diesen Leistungsanforderungen, daher bin ich gespannt, ob es bessere Lösungen gibt.
- Welche Schritte kann ich ergreifen, um den Einfügeprozess zu beschleunigen?
Vielen Dank im Voraus!
Können Sie mehr über Ihren Anwendungsfall beschreiben - müssen Sie die Messwerte in Echtzeit deduplizieren oder erstellen Sie ein Warehouse für Analysen? – wrschneider
Hat die 'temporary_reads'-Tabelle eine Struktur oder Einschränkungen (wie eine PK- oder UNIQUE-Einschränkung)? – wildplasser