2015-05-19 10 views
5

tl; drPobieranie wielu wartości z dużego pola jsonb szybciej (PostgreSQL 9.4)

Korzystanie PSQL 9.4, czy jest jakiś sposób, aby pobrać wiele wartości z pola jsonb, takie jak w przypadku funkcji urojonej :

jsonb_extract_path(x, ARRAY['a_dictionary_key', 'a_second_dictionary_key', 'a_third_dictionary_key']) 

z nadzieją na przyspieszenie czasu inaczej prawie liniowy wymagane, aby wybrać wiele wartości (wartość = 1, 2 wartości 300ms = 450ms, 3 wartości = 600ms)

Tło

I mają następujące jsonb tabeli:

CREATE TABLE "public"."analysis" (
    "date" date NOT NULL, 
    "name" character varying (10) NOT NULL, 
    "country" character (3) NOT NULL, 
    "x" jsonb, 
    PRIMARY KEY(date,name) 
); 

z około 100 000 wierszy, z których każdy posiada rzędy słownika jsonb z ponad 90 przycisków i odpowiadających im wartości.Próbuję napisać zapytanie SQL, aby zaznaczyć kilka (< 10) + klawisz wartości w dość szybki sposób (< 500 ms)

indeks i odpytywania: 190ms

I rozpoczęte przez dodanie index:

CREATE INDEX ON analysis USING GIN (x); 

to sprawia odpytywanie na podstawie wartości w "x" słowniku szybko, jak to:

SELECT date, name, country FROM analysis where date > '2014-01-01' and date < '2014-05-01' and cast(x#>> '{a_dictionary_key}' as float) > 100; 

ten trwa ~ 190 ms (dopuszczalne dla nas)

Odzyskiwanie słownika wartości

Jednakże raz rozpocząć dodawanie kluczy do powrotu w SELECT części, czas realizacji wzrasta prawie liniowy:

1 Wartość: 300 ms

select jsonb_extract_path(x, 'a_dictionary_key') from analysis where date > '2014-01-01' and date < '2014-05-01' and cast(x#>> '{a_dictionary_key}' as float) > 100; 

przyjmuje 366ms (+ 175ms)

select x#>'{a_dictionary_key}' as gear_down_altitude from analysis where date > '2014-01-01' and date < '2014-05-01' and cast(x#>> '{a_dictionary_key}' as float) > 100 ; 

przyjmuje 300MS (+ 110ms)

3 wartości: 600ms

select jsonb_extract_path(x, 'a_dictionary_key'), jsonb_extract_path(x, 'a_second_dictionary_key'), jsonb_extract_path(x, 'a_third_dictionary_key') from analysis where date > '2014-01-01' and date < '2014-05-01' and cast(x#>> '{a_dictionary_key}' as float) > 100; 

przyjmuje do 600ms (+410, +100 i dla każdej z wybranych wartości)

select x#>'{a_dictionary_key}' as a_dictionary_key, x#>'{a_second_dictionary_key}' as a_second_dictionary_key, x#>'{a_third_dictionary_key}' as a_third_dictionary_key from analysis where date > '2014-01-01' and date < '2014-05-01' and cast(x#>> '{a_dictionary_key}' as float) > 100 ; 

przyjmuje do 600ms (+410 lub +100 dla każdej wybranej wartości)

Odzyskiwanie więcej wartości szybciej

Czy istnieje sposób, aby pobrać wiele wartości z pola jsonb, takie jak w przypadku funkcji urojonej:

jsonb_extract_path(x, ARRAY['a_dictionary_key', 'a_second_dictionary_key', 'a_third_dictionary_key']) 

które mogłyby przyspieszyć te wyszukiwań. Może zwracać je jako kolumny lub jako listę/tablicę lub nawet obiekt json.

Odzyskiwanie tablicę używając PL/Python

Tylko do cholery to zrobiłem funkcji niestandardowej przy użyciu PL/Python, ale to było znacznie wolniejsze (5s +), prawdopodobnie z powodu json.loads:

CREATE OR REPLACE FUNCTION retrieve_objects(data jsonb, k VARCHAR[]) 
RETURNS TEXT[] AS $$ 
    if not data: 
    return [] 

    import simplejson as json 
    j = json.loads(data) 

    l = [] 
    for i in k: 
    l.append(j[i]) 

    return l 

$$ LANGUAGE plpython2u; 

# Usage: 
# select retrieve_objects(x, ARRAY['a_dictionary_key', 'a_second_dictionary_key', 'a_third_dictionary_key']) from analysis where date > '2014-01-01' and date < '2014-05-01' 

Aktualizacja 2015-05-21

i ponownie wprowadzone do stołu za pomocą hstore z indeksem gin i wydajności jest niemal identyczna do korzystania jsonb, nie znaczy pomocne w moim przypadku.

Odpowiedz

0

Używasz urządzenia #> operator, które wygląda tak, jakby przeprowadzało wyszukiwanie ścieżki. Czy wypróbowałeś normalne sprawdzanie ->?Na przykład:

select json_column->'json_field1' 
,  json_column->'json_field2' 

Ciekawie byłoby zobaczyć, co się stanie, jeśli skorzystasz z tymczasowego stołu. Podobnie jak:

create temporary table tmp_doclist (doc jsonb) 
; 
insert tmp_doclist 
     (doc) 
select x 
from analysis 
where ... your conditions here ... 
; 
select doc->'col1' 
,  doc->'col2' 
,  doc->'col3' 
from tmp_doclist 
; 
+0

Dla 3 kolumn, użycie '->' trwa 560ms, vs 580ms z '#>'. Próbowałem z tabelą tymczasową, używając 'wybierz x do ....', a następnie wybierając z tej listy, która zajmuje 650ms –

+0

Czy czas dla tabeli tymczasowej zmienia się po dodaniu/usunięciu kolumn? Wydaje się, że 100ms jest dziwaczne w wyszukiwaniu słownika, można się tego spodziewać w ciągu nanosekund. – Andomar

+0

Utworzenie tabeli tymczasowej zajmuje 200ms, a następnie 150ms dla 1 wartości, 285ms dla 2 wartości i 460ms dla 3 wartości. Zastanawiam się, czy postgresql dekoduje json dla każdego wyszukiwania, ale tak nie powinno być (szczególnie nie dla jsonb) –

Powiązane problemy