我的查询正在这样做:
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 =>可以利用索引的年龄?
答案 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)