Postgresql
Postgres jsonb 與復合類型的性能差異
在 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”。