在一个标准化的 struct 上,它是微不足道的,但直到你找到时间和预算来改变它,你可以使用jsonb
JSONPath表达式与@@
predicate check operator:demo
select * from products
where attributes
@@ ' exists($.countries[*]
?( @=="US"
||@=="MX" ))
&& exists($.startDate?
(@>"2024-02-12T07:00:00.000Z"))'
;
id |
attributes |
1 |
{"type": ["RETAIL"], "status": ["ACTIVE"], "endDate": ["2024-02-20T21:00:00.000Z"], "currency": ["USD"], "countries": ["US", "IT", "ES"], "startDate": ["2024-02-13T08:00:00.000Z"], "categories": ["ELECTRONICS"]} |
如果你把它和GIN index配对:
create index on products using gin(attributes jsonb_path_ops);
由于索引扫描,您将看到@@
个速度显著提高:
|
Bitmap Heap Scan on public.products (cost=116.51..2432.07 rows=13325 width=396) (actual time=4.505..56.491 rows=9513 loops=1) |
Output: id, attributes |
Recheck Cond: (products.attributes @@ '(exists ($."countries"[*]?(@ == "US" || @ == "MX")) && exists ($."startDate"?(@ > "2024-02-12T07:00:00.000Z")))'::jsonpath) |
Rows Removed by Index Recheck: 28518 |
Heap Blocks: exact=2149 |
-> Bitmap Index Scan on products_attributes_idx (cost=0.00..113.18 rows=13325 width=0) (actual time=4.238..4.239 rows=38031 loops=1) |
Index Cond: (products.attributes @@ '(exists ($."countries"[*]?(@ == "US" || @ == "MX")) && exists ($."startDate"?(@ > "2024-02-12T07:00:00.000Z")))'::jsonpath) |
Planning Time: 0.374 ms |
Execution Time: 56.930 ms |
这是一个对40K随机样本的测试,类似于你的.同样显而易见的是,索引并不支持整个JSONPath,因此需要重新判断:
对于这些操作符[@@
,@?
],GIN索引从jsonpath
模式中提取形式为110的子句,并基于这些子句中提到的键和值进行索引搜索.访问器链可以包括111、112和113个访问器.jsonb_ops
操作符类也支持114和115访问器,但jsonb_path_ops
操作符类不支持.
日期比较使用>
的部分不合格,这就是为什么需要重新判断.在你不需要>
的地方,你应该更快.
如果您正在处理非统一的时间戳格式,您可能需要在其中添加一个.datetime()
方法.