【发布时间】:2016-04-06 08:44:43
【问题描述】:
我有一个主/从表的情况。对于主表中的每个条目,我在详细表中都有几十个。
假设这些是我的表:
+-----------------------
| Master
+-----------------------
| master_key integer,
| insert_date timestamp
+-----------------------
+-----------------------
| Detail
+-----------------------
| detail_key integer,
| master_key integer
| quantity numeric
| amount numeric
+-----------------------
我最常用的查询是这样的
SELECT extract(year from insert_date) AS Insert_Year, extract(month from insert_date) AS Insert_Month, sum(quantity) AS Quantity, sum(amount) AS Amount
FROM Master, Detail
WHERE (amount not null) and (insert_date <= '2016-12-31') and (insert_date >= '2015-01-01') and (Detail.master_key=Master.master_key)
GROUP BY Insert_Year, Insert_Month
ORDER BY Insert_Year ASC, Insert_Month ASC;
这个查询变得很慢,因为两个表中都有很多年的大量数据。
当然,我在两个表上都有索引,EXPLAIN ANALYZE 告诉我索引扫描的模式超过了 80% 的空洞执行时间。
"Sort (cost=44013.52..44013.53 rows=1 width=19) (actual time=17073.129..17073.129 rows=16 loops=1)"
" Sort Key: (date_part('year'::text, master.insert_date)), (date_part('month'::text, master.insert_date))"
" Sort Method: quicksort Memory: 26kB"
" -> HashAggregate (cost=44013.49..44013.51 rows=1 width=19) (actual time=17073.046..17073.053 rows=16 loops=1)"
" Group Key: date_part('year'::text, master.insert_date), date_part('month'::text, master.insert_date)"
" -> Nested Loop (cost=0.43..43860.32 rows=15317 width=19) (actual time=0.056..15951.178 rows=843647 loops=1)"
" -> Seq Scan on master (cost=0.00..18881.38 rows=3127 width=12) (actual time=0.027..636.202 rows=182338 loops=1)"
" Filter: ((date(insert_date) >= '2015-01-01'::date) AND (date(insert_date) <= '2016-12-31'::date))"
" Rows Removed by Filter: 443031"
" -> Index Scan using idx_detail_master_key on detail (cost=0.43..7.89 rows=7 width=15) (actual time=0.055..0.077 rows=5 loops=182338)"
" Index Cond: (master_key = master.master_key)"
" Filter: (amount IS NOT NULL)"
" Rows Removed by Filter: 2"
"Planning time: 105.317 ms"
"Execution time: 17073.396 ms"
所以我的想法是通过部分定义索引来减小索引大小。在大多数情况下,仅查询最近 2 年的数据。
所以我尝试了类似的方法:
CREATE INDEX idx_detail_table_master_keys
ON detail (master_key)
WHERE master_key in (SELECT master_key FROM master WHERE (extract( year from insert_date) = 2016) or (extract( year from insert_date) = 2015))
当然,这不是最终版本,它应该只是一个概念证明,但它失败了。 PGAdmin 告诉我不允许在创建索引时使用子选择。
所以我的问题是:是否可以根据其他表的数据创建部分索引?
当然,我会感谢任何加速这样的星座的提示。
问候
【问题讨论】:
-
Edit 您的问题,并为您的查询添加
explain (analyze, verbose)的输出。不相关,但是:您应该真正开始使用显式JOIN运算符,而不是where子句中旧的、过时的隐式连接。 -
@a_horse_with_no_name:我必须简化明细表和查询以使其适合 EXPLAIN 结果。但它完成了;)。这个问题的想法不仅是为了改进我当前的查询,而且是为了学习如何总体上加速类似的构造。这就是为什么我尽量简化它。
-
@Mike 不如为
date(insert_date)创建索引,例如CREATE INDEX idx_detail_table_master_insert ON Master USING btree (date(insert_date))
标签: postgresql join indexing