2017-11-20 1 views
1

Für die Entwicklung einer Flugeinzelhandels-Engine speichern wir Bestellungen als JSON-Dokumente in einer PostgreSQL-Datenbank.Wie verschachtelte JSON-Abfragen in PostgreSQL beschleunigen?

ist die Reihenfolge Tabelle wie folgt definiert:

CREATE TABLE IF NOT EXISTS orders (
    id   SERIAL PRIMARY KEY, 
    order_data JSONB NOT NULL 
); 

Eine vereinfachte Version eines Dokuments typische Reihenfolge wie folgt aussieht:

{ 
    "orderID":"ORD000001", 
    "invalid":false, 
    "creationDate":"2017-11-19T15:49:53.897", 
    "orderItems":[ 
     { 
     "orderItemID":"ITEM000001", 
     "flight":{ 
      "id":"FL000001", 
      "segments":[ 
       { 
        "origin":"FRA", 
        "destination":"LHR", 
        "departure":"2018-05-12T14:00:00", 
        "arrival":"2018-05-12T14:40:00", 
        "marketingCarrier":"LH", 
        "marketingFlightNumber":"LH908" 
       } 
      ] 
     }, 
     "passenger":{ 
      "lastName":"Test", 
      "firstName":"Thomas", 
      "passengerTypeCode":"ADT" 
     } 
     }, 
     { 
     "orderItemID":"ITEM000002", 
     "flight":{ 
      "id":"FL000002", 
      "segments":[ 
       { 
        "origin":"LHR", 
        "destination":"FRA", 
        "departure":"2018-05-17T11:30:00", 
        "arrival":"2018-05-17T14:05:00", 
        "marketingCarrier":"LH", 
        "marketingFlightNumber":"LH905" 
       } 
      ] 
     }, 
     "passenger":{ 
      "lastName":"Test", 
      "firstName":"Thomas", 
      "passengerTypeCode":"ADT" 
     } 
     } 
    ] 
} 

Die Anzahl der Einträge in dieser Tabelle eher größer (bis wachsen kann zu über 100 Millionen).

Das Erstellen eines GIN-Indexes für "orderID" funktioniert einwandfrei und beschleunigt erwartungsgemäß die Abfragen für Aufträge mit einer bestimmten ID erheblich.

Aber wir benötigen auch eine schnelle Ausführungszeit für viel komplexere Anfragen wie die Suche nach Aufträgen mit einem bestimmten Flugsegment.

Dank this Thread konnte ich eine Anfrage wie

für unsere Anforderungen
SELECT * 
FROM orders, 
    jsonb_array_elements(order_data->'orderItems') orderItems, 
    jsonb_array_elements(orderItems->'flight'->'segments') segments 
WHERE order_data->>'invalid'='false' 
    AND segments->>'origin'='LHR' 
    AND ((segments->>'marketingCarrier'='LH' AND segments->>'marketingFlightNumber'='LH905') OR (segments->>'operatingCarrier'='LH' AND segments->>'operatingFlightNumber'='LH905')) 
    AND segments->>'departure' BETWEEN '2018-05-17T10:00:00' AND '2018-05-17T18:00:00' 

Dies funktioniert gut, ist aber zu langsam schreiben.

Was ist der beste Weg, um eine solche Abfrage zu beschleunigen?

eine materialisierte Ansicht erstellen wie

CREATE MATERIALIZED VIEW order_segments AS 
SELECT id, order_data->>'orderID' AS orderID, segments->>'origin' AS origin, segments->>'marketingCarrier' AS marketingCarrier, segments->>'marketingFlightNumber' AS marketingFlightNumber, segments->>'operatingCarrier' AS operatingCarrier, segments->>'operatingFlightNumber' AS operatingFlightNumber, segments->>'departure' AS departure 
FROM orders, 
    jsonb_array_elements(order_data -> 'orderItems') orderItems, 
    jsonb_array_elements(orderItems -> 'flight'->'segments') segments 
WHERE order_data->>'invalid'='false'; 

Werke, hat aber den Nachteil, nicht automatisch aktualisiert werden.

Also, wie würde ich Indizes in der Bestellungstabelle definieren, um schnelle Ausführungszeiten zu erreichen? Oder gibt es eine ganz andere Lösung?

+0

Ich weiß nicht, wie Ihre Abfragen im Allgemeinen aussehen, aber haben Sie darüber nachgedacht, auch andere Spalten zu indizieren? Wie MarketingCarrier und/oder Herkunft? –

+0

Danke für Ihren Vorschlag! Ja, ich habe darüber nachgedacht, aber leider habe ich nie herausgefunden, wie man richtige Indizes für verschachtelte Arrays innerhalb von Arrays einstellt. –

Antwort

0

schließlich eine Antwort auf meine eigene Frage gefunden:

einen Index

CREATE INDEX ix_order_items ON orders USING gin (((order_data->'orderItems')) jsonb_path_ops) 

und mit Hilfe der Anfrage

SELECT DISTINCT id, order_data 
FROM orders, 
    jsonb_array_elements(order_data -> 'orderItems') orderItems, 
    jsonb_array_elements(orderItems -> 'flight'->'segments') segments 
WHERE id IN 
(SELECT id 
    FROM orders 
    WHERE order_data->'orderItems'@>'[{"flight": {"segments": [{"origin":"LHR"}]}}]' 
    AND (
     order_data->'orderItems'@>'[{"flight": {"segments": [{"marketingCarrier":"LH","marketingFlightNumber":"LH905"}]}}]' 
     OR 
     order_data->'orderItems'@>'[{"flight": {"segments": [{"operatingCarrier":"LH","operatingFlightNumber":"LH905"}]}}]' 
    ) 
) 
AND [email protected]>'{"invalid": false}' 
AND segments->>'departure' BETWEEN '2018-05-17T10:00:00' AND '2018-05-17T18:00:00' 

beschleunigt Einstellen der Anforderung von einigen Sekunden bis wenigen Millisekunden.

Verwandte Themen