2017-02-15 52 views
4

我剛剛發現了PostgreSQL的JSONB,並想知道如果我將它用於所有表的列,會出現什麼問題?對主鍵和外鍵以外的postgres列使用JSONB

也就是說我所有的表將有主鍵和外鍵列和類型JSONB的任何其他數據的field列。

除了佔用額外的空間,因爲JSONB的開銷,並失去打字「列」,那會我錯過?

回答

3

事實證明,你在這裏的東西。

使用關係數據庫的要點。

  • 定義良好的關係。
  • 一個明確的和詳細的模式。
  • 大型數據集的高性能。

玩家可以不斷的關係。但是你失去了架構和很多的性能。模式不僅僅是數據驗證。這意味着您不能在個別字段上使用觸發器或約束條件。

至於性能...你會注意到的JSONB性能最測試是對其他類似的數據類型。他們從不反對正常的SQL表。這是因爲,儘管JSONB效率驚人,但其效率幾乎不如常規SQL高。所以我們來測試一下,結果發現你在這裏做些什麼。

運用this JSONB performance presentation我創建了一個正確的SQL架構中的數據集...

create table customers (
    id text primary key 
); 

create table products (
    id text primary key, 
    title text, 
    sales_rank integer, 
    "group" text, 
    category text, 
    subcategory text, 
    similar_ids text[] 
); 

create table reviews (
    customer_id text references customers(id), 
    product_id text references products(id), 
    "date" timestamp, 
    rating integer, 
    votes integer, 
    helpful_votes integer 
); 

,另一種使用SQL的關係,但JSONB數據...

create table customers (
    id text primary key 
); 

create table products_jb (
    id text primary key, 
    fields jsonb 
); 

create table reviews_jb (
    customer_id text references customers(id), 
    product_id text references products_jb(id), 
    fields jsonb 
); 

和一個JSONB表。

create table reviews_jsonb (
    review jsonb 
); 

然後我imported the same data into both sets of tables using a little script。 589859評論,93319產品,98761客戶。

讓我們嘗試相同的查詢作爲JSONB性能的文章,得到的平均評價一個產品類別。首先,沒有索引。

傳統SQL:138毫秒

test=> select round(avg(r.rating), 2) 
from reviews r 
join products p on p.id = r.product_id 
where p.category = 'Home & Garden'; 
round 
------- 
    4.59 
(1 row) 

Time: 138.631 ms 

完全JSONB:380毫秒

test=> select round(avg((review#>>'{review,rating}')::numeric),2) 
test-> from reviews_jsonb 
test-> where review #>>'{product,category}' = 'Home & Garden'; 
round 
------- 
    4.59 
(1 row) 

Time: 380.697 ms 

混合JSONB:190毫秒

test=> select round(avg((r.fields#>>'{rating}')::numeric),2) 
from reviews_jb r 
join products_jb p on p.id = r.product_id 
where p.fields#>>'{category}' = 'Home & Garden'; 
round 
------- 
    4.59 
(1 row) 

Time: 192.333 ms 

那老老實實去比想象的要好。混合方法的速度是完整JSONB的兩倍,但比普通SQL慢50%。現在如何與索引?

傳統SQL:130毫秒(500毫秒的索引)

test=> create index products_category on products(category); 
CREATE INDEX 
Time: 491.969 ms 

test=> select round(avg(r.rating), 2) 
from reviews r 
join products p on p.id = r.product_id 
where p.category = 'Home & Garden'; 
round 
------- 
    4.59 
(1 row) 

Time: 128.212 ms 

全JSONB:360毫秒(+ 25000毫秒的索引)

test=> create index on reviews_jsonb using gin(review); 
CREATE INDEX 
Time: 25253.348 ms 
test=> select round(avg((review#>>'{review,rating}')::numeric),2) 
from reviews_jsonb 
where review #>>'{product,category}' = 'Home & Garden'; 
round 
------- 
    4.59 
(1 row) 

Time: 363.222 ms 

混合JSONB:185毫秒( +6900毫秒爲指標)

test=> create index on products_jb using gin(fields); 
CREATE INDEX 
Time: 3654.894 ms 
test=> create index on reviews_jb using gin(fields); 
CREATE INDEX 
Time: 3237.534 ms 
test=> select round(avg((r.fields#>>'{rating}')::numeric),2) 
from reviews_jb r 
join products_jb p on p.id = r.product_id 
where p.fields#>>'{category}' = 'Home & Garden'; 
round 
------- 
    4.59 
(1 row) 

Time: 183.679 ms 

原來,這是一個查詢索引不會有太大的幫助。

這就是我所看到的數據有點混雜,混合JSONB總是比完整SQL慢,但比完整JSONB更快。這似乎是一個很好的妥協。您可以使用傳統的外鍵和連接,但可以靈活地添加您喜歡的任何字段。

我建議採取混合方式更進一步:爲您所知的字段使用SQL列,並有一個JSONB列來提取任何其他字段以提高靈活性。

我鼓勵你在這裏玩弄測試數據,看看錶現如何。