查询以查找其出生日期与索引

时间:2019-05-12 03:42:27

标签: postgresql

我的查询正在这样做:

where 
      ST_DWithin(
        "profile".location :: geography, ? :: geography, 
        ?
      ) 
      and EXTRACT (
        YEAR 
        FROM 
          age(profile.birth_date)
      ) BETWEEN ? :: integer 
      AND ? :: integer

我看到的地方:

Never Used Indexes  public  profile profile_birth_date_idx  0   0   16 kB   56 kB

这很有意义,因为btree索引仅位于birth_date上,但是它是在计算年龄,因此不使用。

是否有一个很好的查询birth_date =>可以利用索引的年龄?

1 个答案:

答案 0 :(得分:0)

如果禁用顺序扫描,则可能会使用您的索引:

SET enable_seqscan TO off;

关闭顺序扫描后在查询上运行EXPLAIN是查看索引本身是否正常的好方法。

我创建了一个类似的查询,实际上,它获取了索引:

db=# explain analyze select * from foo where date_part('year', age(birth_date)) = 5;
                                                                     QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------
 Gather  (cost=1000.42..4801.93 rows=500 width=8) (actual time=23.161..24.732 rows=365 loops=1)
   Workers Planned: 2
   Workers Launched: 2
   ->  Parallel Index Only Scan using foo_birth_date_idx on foo  (cost=0.42..3751.93 rows=208 width=8) (actual time=19.467..19.667 rows=122 loops=3)
         Filter: (date_part('year'::text, age((CURRENT_DATE)::timestamp with time zone, birth_date)) = '5'::double precision)
         Rows Removed by Filter: 33212
         Heap Fetches: 41207
 Planning time: 0.114 ms
 Execution time: 24.798 ms
(9 rows)

您可能希望更改查询,以便直接与birth_date比较,而不是它的派生值。以下应等效:

db=# explain analyze select * from foo where birth_date >= now() - make_interval(years := 5) and birth_date < now() - make_interval(years := 4);
                                                            QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------
 Index Only Scan using foo_birth_date_idx on foo  (cost=0.43..20.71 rows=364 width=8) (actual time=0.021..0.142 rows=365 loops=1)
   Index Cond: ((birth_date >= (now() - '5 years'::interval)) AND (birth_date < (now() - '4 years'::interval)))
   Heap Fetches: 365
 Planning time: 0.198 ms
 Execution time: 0.215 ms
(5 rows)

即使将enable_seqscan设置为on(默认设置),它仍然会拾取该索引。还要注意它有多快(因子100)。

因此,对于您的查询,将条件更改为以下内容,它应该获取索引。

WHERE
      ST_DWithin(
        "profile".location :: geography, ? :: geography,
        ?
      )
      AND birth_date >= now() - make_interval(years := ?::integer)
      AND birth_date < now() - make_interval(years := ?::integer)