过滤器在子查询中时PostgreSQL不使用索引

pbgvytdp  于 2023-08-04  发布在  PostgreSQL
关注(0)|答案(3)|浏览(122)

我试图理解为什么PostgreSQL不使用索引时,条件之一是在子查询。
我有(股票行情,日期)的索引

EXPLAIN ANALYZE SELECT OPEN 
FROM
    daily_prices dp 
WHERE
    dp.ticker = ( SELECT ticker FROM tickers_profile WHERE short_name = '1TECH' ) 
    AND DATE <= '2022-07-05'

个字符
如果子查询是内联的(作为参数)

EXPLAIN ANALYZE SELECT OPEN 
FROM
    daily_prices dp 
WHERE
    dp.ticker = '03041'
    AND DATE <= '2022-07-05'
Bitmap Heap Scan on daily_prices dp  (cost=30.42..3646.10 rows=975 width=5) (actual time=0.506..0.758 rows=285 loops=1)
  Recheck Cond: (((ticker)::text = '03041'::text) AND (date <= '2022-07-05'::date))
  Heap Blocks: exact=16
  ->  Bitmap Index Scan on daily_prices_pkey  (cost=0.00..30.18 rows=975 width=0) (actual time=0.490..0.490 rows=285 loops=1)
        Index Cond: (((ticker)::text = '03041'::text) AND (date <= '2022-07-05'::date))
Planning Time: 0.077 ms
Execution Time: 0.793 ms

的字符串
我试过:

  1. CTE(带报表),性能相同
    1.连接语句,性能相同
    编辑:使用函数工作
CREATE 
    OR REPLACE FUNCTION get_ticker_from_short_name ( _short_name VARCHAR ) RETURNS TEXT AS $BODY$ SELECT
    ticker 
FROM
    tickers_profile 
WHERE
    short_name = _short_name$BODY$ LANGUAGE SQL VOLATILE COST 100
EXPLAIN ANALYZE SELECT OPEN 
FROM
    daily_prices dp 
WHERE
    dp.ticker = ( SELECT get_ticker_from_short_name ( '1TECH' ) ) 
    AND DATE <= '2022-07-05'
Bitmap Heap Scan on daily_prices dp  (cost=36.61..3969.86 rows=1065 width=5) (actual time=0.369..0.565 rows=285 loops=1)
  Recheck Cond: (((ticker)::text = $0) AND (date <= '2022-07-05'::date))
  Heap Blocks: exact=16
  InitPlan 1 (returns $0)
    ->  ProjectSet  (cost=0.00..5.27 rows=1000 width=32) (actual time=0.314..0.314 rows=1 loops=1)
          ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual time=0.000..0.001 rows=1 loops=1)
  ->  Bitmap Index Scan on daily_prices_pkey  (cost=0.00..31.08 rows=1065 width=0) (actual time=0.362..0.362 rows=285 loops=1)
        Index Cond: (((ticker)::text = $0) AND (date <= '2022-07-05'::date))
Planning Time: 0.088 ms
Execution Time: 0.604 ms
x6492ojm

x6492ojm1#

PostgreSQL可以在那里使用索引,但它不喜欢这样,可能是因为daily_prices.ticker的一些值经常出现,这会使索引扫描成为一个糟糕的选择。优化器不知道子查询将返回哪个值。也许可以将作业拆分为两个查询,这样优化器就知道何时计划第二个查询。
如果您知道没有一个频繁值可以返回,您可以添加一个WHERE条件,如AND dp.ticker NOT IN ('frequent value 1', 'frequent value 2')

xoefb8l8

xoefb8l82#

使用函数对我的情况很有效

CREATE 
    OR REPLACE FUNCTION get_ticker_from_short_name ( _short_name VARCHAR ) RETURNS TEXT AS $BODY$ SELECT
    ticker 
FROM
    tickers_profile 
WHERE
    short_name = _short_name$BODY$ LANGUAGE SQL VOLATILE COST 100
EXPLAIN ANALYZE SELECT OPEN 
FROM
    daily_prices dp 
WHERE
    dp.ticker = ( SELECT get_ticker_from_short_name ( '1TECH' ) ) 
    AND DATE <= '2022-07-05'
Bitmap Heap Scan on daily_prices dp  (cost=36.61..3969.86 rows=1065 width=5) (actual time=0.369..0.565 rows=285 loops=1)
  Recheck Cond: (((ticker)::text = $0) AND (date <= '2022-07-05'::date))
  Heap Blocks: exact=16
  InitPlan 1 (returns $0)
    ->  ProjectSet  (cost=0.00..5.27 rows=1000 width=32) (actual time=0.314..0.314 rows=1 loops=1)
          ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual time=0.000..0.001 rows=1 loops=1)
  ->  Bitmap Index Scan on daily_prices_pkey  (cost=0.00..31.08 rows=1065 width=0) (actual time=0.362..0.362 rows=285 loops=1)
        Index Cond: (((ticker)::text = $0) AND (date <= '2022-07-05'::date))
Planning Time: 0.088 ms
Execution Time: 0.604 ms
8aqjt8rx

8aqjt8rx3#

我也遇到过类似的问题。
我从WHERE dp.ticker =改为WHERE dp.ticker IN修复了它。
固定查询:

EXPLAIN ANALYZE SELECT OPEN 
FROM
    daily_prices dp 
WHERE
    dp.ticker IN ( SELECT ticker FROM tickers_profile WHERE short_name = '1TECH' ) 
    AND DATE <= '2022-07-05'

字符串

相关问题