【问题标题】:Need help optimizing this simple query需要帮助优化这个简单的查询
【发布时间】:2014-11-04 13:42:54
【问题描述】:

我的最终目标是使用索引优化我的查询,但我无法添加正确的索引。我尝试过的所有方法在解释图中的成本都相同,并且没有迹象表明它甚至使用了任何索引。

我有两张桌子:

  • event 有两个 date 列:start_dateend_date(可以为 null)。
  • fiscal_date 具有:
    • 两个datestart_dateend_date(不能为空)
    • fiscal_year 类型为 char(4) 的列
    • fiscal_quarter 类型为 char(1) 的列

还有另一个表address,它只是与event 中的外键一对一的关系。除了公钥之外,没有任何索引。

我有一个无法更改的查询,用于确定事件开始的财政季度和年份:

SELECT
    e.*, 
    (select 'Q' || fd.fiscal_quarter || ' FY' || fd.fiscal_year
        from fiscal_date fd
        where e.start_date between fd.start_date and fd.end_date
        limit 1) as fiscal_quarter_year,

    (select 'Q' || fd.fiscal_quarter
        from fiscal_date fd
        where e.start_date between fd.start_date and fd.end_date
        limit 1) as fiscal_quarter,

    (select 'FY' || fd.fiscal_year
        from fiscal_date fd
        where e.start_date between fd.start_date and fd.end_date
        limit 1) as fiscal_year,

    a.street1, a.street2, a.street3, a.city, a.state, a.country, a.postal_code

FROM event AS e
LEFT OUTER JOIN address a ON e.address_id=a.address_id;

这是查询的解释(注意左侧所有昂贵的 seq 扫描):

根据要求,这是explain analyze 的输出:

 Hash Left Join  (cost=115.78..2846.64 rows=1649 width=5087) (actual time=18.334..134.279 rows=1649 loops=1)
   Hash Cond: (e.address_id = a.address_id)
   ->  Seq Scan on event e  (cost=0.00..323.49 rows=1649 width=5031) (actual time=0.223..19.808 rows=1649 loops=1)
   ->  Hash  (cost=68.68..68.68 rows=3768 width=60) (actual time=17.797..17.797 rows=3768 loops=1)
         Buckets: 1024  Batches: 1  Memory Usage: 248kB
         ->  Seq Scan on address a  (cost=0.00..68.68 rows=3768 width=60) (actual time=0.004..9.071 rows=3768 loops=1)
   SubPlan 1
     ->  Limit  (cost=0.00..0.49 rows=1 width=28) (actual time=0.011..0.014 rows=1 loops=1649)
           ->  Seq Scan on fiscal_date fd  (cost=0.00..1.46 rows=3 width=28) (actual time=0.006..0.006 rows=1 loops=1649)
                 Filter: (($0 >= start_date) AND ($0 <= end_date))
   SubPlan 2
     ->  Limit  (cost=0.00..0.48 rows=1 width=8) (actual time=0.010..0.012 rows=1 loops=1649)
           ->  Seq Scan on fiscal_date fd  (cost=0.00..1.43 rows=3 width=8) (actual time=0.006..0.006 rows=1 loops=1649)
                 Filter: (($1 >= start_date) AND ($1 <= end_date))
   SubPlan 3
     ->  Limit  (cost=0.00..0.48 rows=1 width=20) (actual time=0.010..0.012 rows=1 loops=1649)
           ->  Seq Scan on fiscal_date fd  (cost=0.00..1.43 rows=3 width=20) (actual time=0.005..0.005 rows=1 loops=1649)
                 Filter: (($2 >= start_date) AND ($2 <= end_date))
 Total runtime: 138.008 ms

我尝试将索引添加到 event 以索引开始日期和结束日期(以及单独),将索引添加到 fiscal_date 的日期列,但似乎没有什么能减少此查询的成本计算.

我该如何优化这个查询,还是不可能?

【问题讨论】:

  • 请贴出explain analyze 的输出,从提供的信息很难得出很多结论。一般提示是尽可能在子查询上使用连接,它通常执行得更好。
  • 很酷的解释,这是什么原因?这是什么意思?有没有你遗漏的查询?您显示的查询从事件中选择所有行,因此索引无济于事。
  • 也许只有我一个人,但我发现explain analyze 的纯文本输出更多比图形显示更能提供信息(也更容易理解)
  • @amphetamachine 你的查询有问题——你使用limit 没有order by,所以PostgreSQL 可以返回它碰巧首先找到的任何匹配行。
  • @amphetamachine 同意这与优化不是特别相关。我只是指出问题所在。顺便说一句,我对人们无法更改查询、无法更新 PostgreSQL、无法安装任何东西、无法访问 Internet 并且想要一个神奇的修复,实际上并没有改变任何东西。如果你在这样的环境中,我很同情你。

标签: postgresql date indexing


【解决方案1】:

好的,所以您的问题不在于财政日期顺序扫描,行数太少以至于顺序扫描可能是正确的做法。您可能需要两个表上的 address._id 索引。 如果 adress_is 是地址表的主键,它已经被索引。

另外,为了确定,对所有表运行 Vacuum full 和 Vacuum 分析。

编辑: 考虑到行数太少(低于 10000 行不算什么),性能似乎真的很差。桌子真的很大还是硬件很古老?如果不是,您可能应该认真查看配置(工作内存等)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-05
    • 2012-10-14
    • 2019-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多