使用Postgres 9.5,如何查询具有JSONB列的表,加入两个JSON字段,关键是利用GIN索引来最大化性能?
我在一个系统上进行原型设计,该系统可以在单一平台上为不同的客户提供不同的模式/数据模型。实体 - 属性 - 值(EAV)是一种常见的模式,我热衷于预测Postgres如何处理使用其JSONB数据类型存储的实体的查询。
我有一个表存储不同类型的实体,例如客户,销售交易。
CREATE TABLE entity_jsonb (
id uuid PRIMARY KEY,
type text,
created_at timestamp without time zone,
properties jsonb,
org_id integer
);
CREATE INDEX entity_jsonb_created_at_idx ON entity_jsonb USING btree (created_at);
CREATE INDEX entity_jsonb_org_id_idx ON entity_jsonb USING btree (org_id);
CREATE INDEX entity_jsonb_type_idx ON entity_jsonb USING btree (type);
CREATE INDEX entity_jsonb_properties_idx ON entity_jsonb USING gin (properties);
我在此表中有一个客户记录类型'客户'和属性:
{"uuid": "8f8896c7-f41c-49f7-ad6e-4613f7b51a23", "email": "crashfound@somema1l.org", "lastname": "McCarthy", "createdAt": "May 27, 2015 12:06:45 PM", "firstname": "Nathan"}
我在此表中有一个销售交易记录,类型为' sales_transaction'和属性:
{"uuid": "54243d48-e69f-4bb6-ab33-6defb8a0f626", "amount": 99817, "status": 0, "paymentType": 1, "currencyCode": "USD", "customerUuid": "8f8896c7-f41c-49f7-ad6e-4613f7b51a23", "transactionId": "471170"}
如何利用GIN索引(运营商:@>,?,?&,?|)来有效地查询交易,但是与客户联系以从两者返回数据。填充过去7天的交易清单,显示客户名称和交易金额?
我已经尝试过此查询来查找交易对象的子集(金额= 99817)和相关的客户详细信息:
SELECT t.properties AS transaction, c.properties AS customer
FROM entity_jsonb t
JOIN entity_jsonb c ON (c.properties->>'uuid' = t.properties->>'customerUuid' AND c.type = 'customer')
WHERE t.type = 'sales_transaction' AND t.properties @> '{"amount" : 99817}';
它有效,但它没有使用GIN索引,即没有像我想的那样快。我尝试了这种方法(使用GIN @>包含运算符),但它没有包含客户详细信息。我做错了什么?
SELECT t.properties AS transaction, c.properties AS customer FROM entity_jsonb t LEFT JOIN entity_jsonb c ON (c.properties @> json_build_array(json_build_object('uuid', t.properties->'customerUuid'))::jsonb AND c.type = 'customer') WHERE t.type = 'sales_transaction' AND t.properties @> '{"amount" : 99817}';
据我所知,与传统的关系设计相比,这不是一个最佳解决方案,但我有兴趣了解查询是如何有效地将实体数据纯粹存储为JSON。
答案 0 :(得分:3)
我的询问并不遥远。我不需要json_build_array
。对于100k客户的数据集,查询现在运行速度比没有使用GIN索引的版本快10倍:
SELECT t.properties AS transaction, c.properties AS customer
FROM entity_jsonb t
JOIN entity_jsonb c ON (c.properties @> json_build_object('uuid', t.properties->'customerUuid')::jsonb AND c.type = 'customer')
WHERE t.type = 'sales_transaction' AND t.properties @> '{"amount" : 99817}';