2016-10-21 9 views
1

Ich leide an Leistungsproblemen beim Einfügen von Millionen Zeilen in eine PostgreSQL-Datenbank.Einfügen von Daten in Postgresql

Ich sende ein JSON-Objekt, das ein Array mit einer Million Zeilen hat.

Für jede Zeile erstelle ich einen Datensatz in der Datenbanktabelle. Ich habe das auch mit mehreren Einsätzen gleichzeitig versucht, aber das Problem bleibt bestehen.

Ich bin mir nicht sicher, wie ich damit umgehen soll, ich habe gelesen, dass der Befehl COPY am schnellsten ist.

Wie kann ich die Leistung verbessern?

Mein JSON-Objekt mit Protokoll als Array: Array Log hat eine Million Zeilen.

{"type":"monitoring","log":[ 
["2016-10-12T20:33:21","0.00","0.00","0.00","0.00","0.0","24.00","1.83","-0.00","1","1","-100.00"], 
["2016-10-12T20:33:23","0.00","0.00","0.00","0.00","0.0","24.00","1.52","-0.61","1","1","-100.00"]]} 

Mein aktueller Code (Ich baue eine dynamische Anweisung, so dass ich mehrere Zeilen auf einmal ausführen kann):

IF(NOT b_first_line) THEN 
      s_insert_query_values = right(s_insert_query_values, -1); --remove te leading comma 

      EXECUTE format('INSERT INTO log_rlda 
        (record_node_id, log_line, log_value, timestamp, record_log_id) 
      VALUES %s;', s_insert_query_values); 

      s_insert_query_values = ''; 
      i_num_lines_buffered = 0; 
     END IF; 
     END IF; 

s_insert_query_values ​​enthält:

Jeder Wert innerhalb der Array innerhalb von "log" muss in eine eigene Zeile (in colum: log_value) eingefügt werden. Dies ist, wie die INSERT aussieht (Verweis auf s_insert_query_values):

INSERT INTO log_rlda 
        (record_node_id, log_line, log_value, timestamp, record_log_id) 
      VALUES 
    (806, 1, 0.00, '2016-10-12 20:33:21', 386), 
    (807, 1, 0.00, '2016-10-12 20:33:21', 386), 
    (808, 1, 0.00, '2016-10-12 20:33:21', 386), 
    (809, 1, 0.00, '2016-10-12 20:33:21', 386), 
    (810, 1, 0.0, '2016-10-12 20:33:21', 386), 
    (811, 1, 24.00, '2016-10-12 20:33:21', 386), 
    (768, 1, 1.83, '2016-10-12 20:33:21', 386), 
    (769, 1, 0.00, '2016-10-12 20:33:21', 386), 
    (728, 1, 1, '2016-10-12 20:33:21', 386), 
    (771, 1, 1, '2016-10-12 20:33:21', 386), 
    (729, 1, -100.00, '2016-10-12 20:33:21', 386), 
    (806, 2, 0.00, '2016-10-12 20:33:23', 386), 
    (807, 2, 0.00, '2016-10-12 20:33:23', 386), 
    (808, 2, 0.00, '2016-10-12 20:33:23', 386), 
    (809, 2, 0.00, '2016-10-12 20:33:23', 386), 
    (810, 2, 0.0, '2016-10-12 20:33:23', 386), 
    (811, 2, 24.00, '2016-10-12 20:33:23', 386), 
    (768, 2, 1.52, '2016-10-12 20:33:23', 386), 
    (769, 2, -0.61, '2016-10-12 20:33:23', 386), 
    (728, 2, 1, '2016-10-12 20:33:23', 386), 
    (771, 2, 1, '2016-10-12 20:33:23', 386), 
    (729, 2, -100.00, '2016-10-12 20:33:23', 386) 

Solution (i_node_id_list enthält IDs i vor dieser Abfrage ausgewählt):

SELECT i_node_id_list[log_value_index] AS record_node_id, 
        e.log_line-1 AS log_line, 
        items.log_value::double precision as log_value, 
        to_timestamp((e.line->>0)::text, 'YYYY-MM-DD HH24:MI:SS') as "timestamp", 
        i_log_id as record_log_id 
       FROM (VALUES (log_data::json)) as data (doc), 
       json_array_elements(doc->'log') with ordinality as e(line, log_line), 
       json_array_elements_text(e.line)  with ordinality as items(log_value, log_value_index) 
       WHERE log_value_index > 1 --dont include timestamp value (shouldnt be written as log_value) 
       AND log_line > 1 

Antwort

1

Sie müssen zwei Ebenen der Entschachtelung.

select e.log_line, items.log_value, e.line -> 0 as timestamp 
from (
    values ('{"type":"monitoring","log":[ 
    ["2016-10-12T20:33:21","0.00","0.00","0.00","0.00","0.0","24.00","1.83","-0.00","1","1","-100.00"], 
    ["2016-10-12T20:33:23","0.00","0.00","0.00","0.00","0.0","24.00","1.52","-0.61","1","1","-100.00"]]}'::json) 
) as data (doc), 
    json_array_elements(doc->'log') with ordinality as e(line, log_line), 
    json_array_elements(e.line) with ordinality as items(log_value, log_value_index) 
where log_value_index > 1; 

Der erste Aufruf von json_array_elements() extrahiert alle Array-Elemente aus dem log Attribute. Die with ordinality ermöglicht es uns, jede Zeile in diesem Array zu identifizieren. Der zweite Aufruf ruft dann jedes Element von den Zeilen ab, wobei wiederum die with ordinality es uns ermöglicht, die Position in dem Array herauszufinden.

Die obige Abfrage gibt diese:

log_line | log_value | timestamp    
---------+-----------+---------------------- 
     1 | "0.00" | "2016-10-12T20:33:21" 
     1 | "0.00" | "2016-10-12T20:33:21" 
     1 | "0.00" | "2016-10-12T20:33:21" 
     1 | "0.00" | "2016-10-12T20:33:21" 
     1 | "0.0"  | "2016-10-12T20:33:21" 
     1 | "24.00" | "2016-10-12T20:33:21" 
     1 | "1.83" | "2016-10-12T20:33:21" 
     1 | "-0.00" | "2016-10-12T20:33:21" 
     1 | "1"  | "2016-10-12T20:33:21" 
     1 | "1"  | "2016-10-12T20:33:21" 
     1 | "-100.00" | "2016-10-12T20:33:21" 
     2 | "0.00" | "2016-10-12T20:33:23" 
     2 | "0.00" | "2016-10-12T20:33:23" 
     2 | "0.00" | "2016-10-12T20:33:23" 
     2 | "0.00" | "2016-10-12T20:33:23" 
     2 | "0.0"  | "2016-10-12T20:33:23" 
     2 | "24.00" | "2016-10-12T20:33:23" 
     2 | "1.52" | "2016-10-12T20:33:23" 
     2 | "-0.61" | "2016-10-12T20:33:23" 
     2 | "1"  | "2016-10-12T20:33:23" 
     2 | "1"  | "2016-10-12T20:33:23" 
     2 | "-100.00" | "2016-10-12T20:33:23" 

Das Ergebnis der obigen Aussage kann dann direkt verwendet werden, um die Daten einzufügen, ohne darüber Looping. Das sollte viel schneller sein, als eine Menge einzelner Inserts.

Ich bin mir jedoch nicht sicher, wie Sie das korrekte record_node_id oder record_log_id in das obige Ergebnis integrieren können.

+0

Vielen Dank für die schnelle Antwort Die Daten werden auf eine andere Art und Weise gelöscht. Für jeden Wert im "line array", außer dem ersten Wert, wird eine Zeile in log_rlda eingefügt. Erklärung der Spalten in log_rlda: record_node_id Bezieht sich auf einen Record-Knoten, der die Bedeutung des Werts beschreibt. log_line die Zeilennummer in den Protokolldaten log_value jeder Wert Zeitstempel der erste Wert in der „line array“ record_log_id zu dem Satz von Daten I answerd die erste Frage, was „s_insert_query_values“ enthält, bezieht. – Vern

+0

@Vern: siehe meine Bearbeitung –

+0

, um das Problem der Integration der richtigen record_node_id zu lösen, habe ich die folgende Anweisung bearbeitet, um die richtige ID aus einem Array von IDs zu wählen, die ich zuvor gesammelt habe. Ich benutze den log_value_index, um es zu durchlaufen. Es funktioniert ziemlich gut und ich habe bis jetzt einen signifikanten Leistungsschub erreicht. Ich habe dem Thema die Lösung hinzugefügt – Vern

Verwandte Themen