postgresql - 查询以查找从他们的 birth_date 开始的年龄范围与索引之间的所有用户

标签 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 => age 查询可以利用索引?

最佳答案

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

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)

关于postgresql - 查询以查找从他们的 birth_date 开始的年龄范围与索引之间的所有用户,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56096037/

相关文章:

java - Jooq 按日/月/年比较时间戳

python - SQL/ python : Transform data from csv and into table with different schema with condition

sql - 包含大量更新和 PostgreSQL 的流

sql - 带有 OFFSET 的 PostgreSQL LIMIT 无法超过 100000

postgresql - 如何在 slick 3.2.0 中将 Map[String, String] 映射到 (String, String)

postgresql - Postgres 根据查询结果从表中选择

ruby-on-rails - Rails 通过迁移删除表行

ruby-on-rails - postgres中的uuid ossp是什么

sql - 如何在 postgresql 中查找具有特定列的表

sql - 两次加入同一个表以计算不同的列