Postgresql

Postgres jsonb 與復合類型的性能差異

  • July 20, 2020

在 jsonb 列和相同結構的複合類型列之間進行選擇涉及哪些注意事項?

例如,考慮 Postgres 文件中使用的列:

CREATE TYPE inventory_item AS (
name            text,
supplier_id     integer,
price           numeric
);

這種方法與反映這種結構的 jsonb 列之間的權衡是什麼?

例如,我懷疑複合類型不需要儲存每條記錄的鍵名,而 jsonb 類型需要這樣做。

TYPEinventory_item是在問題中定義的(與指南中相同*)因此我們只需要定義具有復合(ROW)類型的表tc和具有 JSONb 類型的tj 。*

插入時間

-- drop table tc; drop table tj;
CREATE TABLE tc (id serial, x inventory_item);
CREATE TABLE tj (id serial, x JSONb);

EXPLAIN ANALYSE 
 INSERT INTO tc(x) VALUES 
   (ROW('fuzzy dice', 42, 1.99)),
   (ROW('test pi', 3, 3.1415))
; -- Execution Time: try1 0.386 ms; try2 0.559 ms; try3 0.102 ms; ... 
EXPLAIN ANALYSE 
 INSERT INTO tj(x) VALUES 
   ('{"name":"fuzzy dice", "supplier_id":42, "price":1.99}'::jsonb),
   ('{"name":"test pi", "supplier_id":3, "price":3.1415}'::jsonb)
; -- Execution Time: try1 0.343; try2 0.355 ms; try3 0.112 ms; ...

當然,我們需要循環等複雜的東​​西來測試……但似乎“可比”的時間,沒有太大的區別。

選擇本地時間

僅檢索原始數據類型。需要好的基準,但讓我們想像一些簡單的東西,只檢查大的差異。

EXPLAIN ANALYSE   SELECT x, i FROM tc, generate_series(1,999999) g(i); 
EXPLAIN ANALYSE   SELECT x, i FROM tj, generate_series(1,999999) g(i); 

再次沒有區別。兩者都具有“執行時間:~460”。

爆炸時間

EXPLAIN ANALYSE
 SELECT i, id, (x).name, (x).supplier_id, (x).price
 FROM tc, generate_series(1,999999) g(i)
; -- Execution Time: ~490 ms 
EXPLAIN ANALYSE
 SELECT i, tj.id, t.* 
 FROM tj, generate_series(1,999999) g(i),
      LATERAL jsonb_populate_record(null::inventory_item, tj.x) t  
; -- Execution Time: ~650 ms

似乎將 JSONb-object 轉換為 SQL-row 非常快!似乎是二進制轉換:我們可以假設該函式jsonb_populate_record使用inventory_item內部定義將 JSONb 類型映射到 SQL。

比複合表更快

爆炸和計算一些東西

EXPLAIN ANALYSE
 SELECT i, (x).supplier_id+i, (x).price+0.01
 FROM tc, generate_series(1,999999) g(i)
; -- Execution Time: ~800 ms

EXPLAIN ANALYSE
 SELECT i,  t.supplier_id+i, t.price+0.01
 FROM tj, generate_series(1,999999) g(i),
      LATERAL jsonb_populate_record(null::inventory_item, tj.x) t  
; -- Execution Time: ~620 ms

計算時間可能約為 150 毫秒,因此預期時間相同……上面的範例中存在一些錯誤,需要更好的基準來檢查實際差異。


檢查從文本中投射的比較時間。

EXPLAIN ANALYSE -- (supposed to) cast from binary
 SELECT i, id, x->>'name' as name, 
        (x->'supplier_id')::int as supplier_id, (x->'price')::float as price
 FROM tj, generate_series(1,999999) g(i)
; -- Execution Time: ~1600 ms 

EXPLAIN ANALYSE -- cast from text
 SELECT i, id, x->>'name' as name, 
        (x->>'supplier_id')::int as supplier_id, (x->>'price')::float as price
 FROM tj, generate_series(1,999999) g(i)
; -- Execution Time: ~1600 ms 

時間長且相同。似乎(x->'supplier_id')::int它只是(x->>'supplier_id')::int or的一種糖語法(x->'supplier_id')::text::int

PS:這個答案也是另一個問題的補充,關於“Binary to binary cast with JSONb”。

引用自:https://dba.stackexchange.com/questions/227397