将 JSONB 用于除主键和外键之外的 postgres 列
Use JSONB for postgres columns other than primary and foreign keys
我刚刚发现了 PostgreSQL 的 JSONB,想知道如果我将它用于所有表的列会出现什么问题?
也就是说,我所有的表都将主键和外键作为列,并且 field
类型为 JSONB 的列用于任何其他数据。
除了因为 JSONB 的开销占用额外的 space 和在 "columns" 上输掉输入之外,我还会错过什么?
原来你在这里有所作为。
使用关系型数据库的要点
- 定义明确的关系。
- 定义明确且详细的架构。
- 大型数据集的高性能。
你要保持关系。但是你失去了模式和很多性能。架构不仅仅是数据验证。这意味着您不能在单个字段上使用触发器或约束。
至于性能...您会注意到大多数 JSONB 性能测试都是针对其他类似数据类型的。他们从不反对正常的 SQL table。这是因为,虽然 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 table。
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 的两倍,但比正常方法慢 50% SQL。现在索引怎么样?
传统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 列来选择任何其他字段以实现灵活性。
我鼓励您在此处试用测试数据,看看性能如何。
我刚刚发现了 PostgreSQL 的 JSONB,想知道如果我将它用于所有表的列会出现什么问题?
也就是说,我所有的表都将主键和外键作为列,并且 field
类型为 JSONB 的列用于任何其他数据。
除了因为 JSONB 的开销占用额外的 space 和在 "columns" 上输掉输入之外,我还会错过什么?
原来你在这里有所作为。
使用关系型数据库的要点
- 定义明确的关系。
- 定义明确且详细的架构。
- 大型数据集的高性能。
你要保持关系。但是你失去了模式和很多性能。架构不仅仅是数据验证。这意味着您不能在单个字段上使用触发器或约束。
至于性能...您会注意到大多数 JSONB 性能测试都是针对其他类似数据类型的。他们从不反对正常的 SQL table。这是因为,虽然 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 table。
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 的两倍,但比正常方法慢 50% SQL。现在索引怎么样?
传统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 列来选择任何其他字段以实现灵活性。
我鼓励您在此处试用测试数据,看看性能如何。