【问题标题】:patial Index basing on data of second table基于第二张表数据的部分索引
【发布时间】: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


【解决方案1】:

不可能基于另一个表的数据创建部分索引,因为像 postgresql 这样的关系数据库具有三种连接方式:嵌套循环、哈希连接和排序合并。所有这些方法都分别加载连接的表。由于数据库优化器决定将使用哪些方法以及连接将在哪个方向执行,因此创建一个覆盖另一个表的数据的表索引是没有意义的。这就是您不能定义此类索引的原因。可以在此处找到有关此主题的更详细说明:http://use-the-index-luke.com/sql/join(以及在线书籍的以下部分)

更多优化见加百利信使的评论

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-27
    • 1970-01-01
    • 1970-01-01
    • 2017-12-20
    • 1970-01-01
    • 2022-01-04
    • 2012-08-15
    • 1970-01-01
    相关资源
    最近更新 更多