Ich habe eine partitionierte Tabellenstruktur wie:
CREATE TABLE measurements (
sensor_id bigint,
tx timestamp,
measurement int
);
CREATE TABLE measurements_201201(
CHECK (tx >= '2012-01-01 00:00:00'::timestamp without time zone
AND tx < ('2012-01-01 00:00:00'::timestamp without time zone + '1 mon'::interval))
)INHERITS (measurements);
CREATE INDEX ON measurements_201201(sensor_id);
CREATE INDEX ON measurements_201201(tx);
CREATE INDEX ON measurements_201201(sensor_id, tx);
....
Und so weiter. Jede Tabelle hat ungefähr 20 Millionen Zeilen.
Wenn ich in der WHERE
Klausel nach einem Beispiel für Sensoren und einem Beispiel für Zeitstempel frage, zeigt der Abfrageplan die richtigen ausgewählten Tabellen und verwendeten Indizes an, z. B.:
SELECT *
FROM measurements
INNER JOIN sensors TABLESAMPLE BERNOULLI (0.01) USING (sensor_id)
WHERE tx BETWEEN '2015-01-04 05:00' AND '2015-01-04 06:00'
OR tx BETWEEN '2015-02-04 05:00' AND '2015-02-04 06:00'
OR tx BETWEEN '2014-03-05 05:00' AND '2014-04-07 06:00' ;
Wenn ich jedoch einen CTE verwende oder die Zeitstempelwerte in eine Tabelle einfüge (nicht angezeigt, auch nicht mit Indizes für die temporäre Tabelle).
WITH sensor_sample AS(
SELECT sensor_id, start_ts, end_ts
FROM sensors TABLESAMPLE BERNOULLI (0.01)
CROSS JOIN (VALUES (TIMESTAMP '2015-01-04 05:00', TIMESTAMP '2015-01-04 06:00'),
(TIMESTAMP '2015-02-04 05:00', TIMESTAMP '2015-02-04 06:00'),
(TIMESTAMP '2014-03-05 05:00', '2014-04-07 06:00') ) tstamps(start_ts, end_ts)
)
So etwas wie das Folgende
SET constraint_exclusion = on;
SELECT * FROM measurements
INNER JOIN sensor_sample USING (sensor_id)
WHERE tx BETWEEN start_ts AND end_ts
Führt für jede Tabelle einen Index-Scan durch. Dies ist immer noch relativ schnell, kann jedoch mit zunehmender Komplexität der Abfragen zu seq-Scans führen, die zum Abrufen von ~ 40 KB-Zeilen aus einer begrenzten Teilmenge partitionierter Tabellen (4-5 von 50) sehr langsam sind.
Ich bin besorgt darüber , dass so etwas wie dies das Problem ist.
Für nicht triviale Ausdrücke müssen Sie die mehr oder weniger wörtliche Bedingung in Abfragen wiederholen, damit der Postgres-Abfrageplaner versteht, dass er sich auf die CHECK-Einschränkung stützen kann. Auch wenn es überflüssig erscheint!
Wie kann ich die Partitionierung und die Abfragestruktur verbessern, um die Wahrscheinlichkeit zu verringern, dass für alle meine Daten Seq-Scans ausgeführt werden?
Antworten:
Der Constraint-basierte Ausschluss [CBE] wird in einem frühen Stadium der Abfrageplanung ausgeführt, unmittelbar nachdem die Abfrage analysiert, den tatsächlichen Beziehungen zugeordnet und neu geschrieben wurde. ( Interna , Planer / Optimierer-Phase)
Der Planer kann keinen Inhalt der Tabelle "sensor_sample" annehmen.
Wenn Sie also keine fest in der Abfrage codierten Werte haben, schließt der Planer "Partitionen" nicht aus.
Ich denke, was mit der CTE-Variante passiert ... der Planer ist eingeschränkt, weil Sie TABLESAMPLE verwenden und die gesamte Unterabfrage als flüchtig behandelt werden kann, selbst wenn Literale in der Unterabfrage statisch sind. ( das ist nur meine Vermutung, ich bin kein Experte für Planercode )
Positiv zu vermerken ist, dass der Index-Scan mit negativem Ergebnis unglaublich schnell ist. (höchstens einseitiger Scan!) Wenn Sie also nicht über 10000 Partitionen haben, würde ich mich nicht darum kümmern.
Um Ihre Frage direkt zu beantworten:
Sie können diese Datenstruktur nicht wesentlich verbessern.
In Bezug auf Index-Scans - sie sind billig;
Sequentielle Scans werden nach Möglichkeit vermieden, wie Sie anhand Ihrer eigenen Beispiele sehen.
quelle