PostgreSQL使用jsonb字段快速搜索

时间:2020-10-16 03:06:55

标签: postgresql jsonb

我有一个带有jsonb字段的表。实际上,一维数组存储在此处-一些ID的列表,如下所示:

[254622, 301359, 309207, 334299, 351963, 355482, 350938]

此字段也有一个索引:

CREATE INDEX users_log_actions_idx ON public.users_list_orders 
USING gin (users_log_actions);

在我的查询中,我通过该字段(简化版本,没有WHERE的条件)进行搜索:

SELECT *
FROM
    users_list_orders
WHERE
    users_list_orders.user_id != '239118'
AND 
    NOT ( users_log_actions @> '239118' )

问题是:我的应用程序每秒执行数百个类似的查询(当然,使用不同的用户ID),有时此查询非常快(大约0.2秒),有时非常慢(> 15秒)。我发现瓶颈是按jsonb字段(users_log_actions)进行搜索,所以我很感激任何有关如何加快此速度的建议。

更新:

对此查询进行解释(分析,缓冲区,格式化文本):

Limit  (cost=1.36..53.32 rows=1 width=313) (actual time=0.470..0.473 rows=1 loops=1)
  Buffers: shared hit=25
  InitPlan 2 (returns $1)
    ->  Result  (cost=0.50..0.51 rows=1 width=4) (actual time=0.100..0.101 rows=1 loops=1)
          Buffers: shared hit=5
          InitPlan 1 (returns $0)
            ->  Limit  (cost=0.42..0.50 rows=1 width=4) (actual time=0.097..0.098 rows=1 loops=1)
                  Buffers: shared hit=5
                  ->  Index Only Scan Backward using users_list_orders_pkey on users_list_orders users_list_orders_1  (cost=0.42..39525.78 rows=503412 width=4) (actual time=0.096..0.097 rows=1 loops=1)
                        Index Cond: (id IS NOT NULL)
                        Heap Fetches: 1
                        Buffers: shared hit=5
  ->  Nested Loop  (cost=0.84..102524.47 rows=1973 width=313) (actual time=0.469..0.470 rows=1 loops=1)
        Buffers: shared hit=25
        ->  Index Scan using public_users_list_orders_order_category_id2_idx on users_list_orders  (cost=0.42..75900.87 rows=15889 width=312) (actual time=0.426..0.426 rows=1 loops=1)
              Index Cond: (order_category_id = '18'::smallint)
              Filter: ((user_id <> 239118) AND (order_reported <= '50'::smallint) AND (NOT (users_log_actions @> '239118'::jsonb)) AND (NOT (users_log_hidden @> '239118'::jsonb)) AND (order_active = 1) AND ((order_daily_limit = 0) OR (order_daily_counter < order_daily_limit)) AND ((order_overall_limit = 0) OR (order_overall_counter < order_overall_limit)) AND ((id)::double precision >= round((random() * ($1)::double precision))))
              Rows Removed by Filter: 4
              Buffers: shared hit=21
        ->  Index Scan using users_main_pkey on users_main  (cost=0.42..1.67 rows=1 width=9) (actual time=0.041..0.041 rows=1 loops=1)
              Index Cond: (id = users_list_orders.user_id)
              Filter: ((user_balance_usd > 0.05) AND (users_list_orders.order_price_usd < user_balance_usd))
              Buffers: shared hit=4
Planning time: 2.209 ms
Execution time: 0.559 ms

0 个答案:

没有答案