如何提高此 PostgreSQL 查询在索引扫描中的性能

Posted

技术标签:

【中文标题】如何提高此 PostgreSQL 查询在索引扫描中的性能【英文标题】:How to improve this PostgreSQL query's performance in index scan 【发布时间】:2014-12-10 23:28:21 【问题描述】:

在这个execution plan 中,以下查询花费了大量时间,3.780 秒,仅对 order_line 表(执行计划的第 11 行)执行索引扫描。

表的主键:

Customer PK - c_w_id, c_d_id, c_id
OOrder PK - o_w_id, o_d_id, o_id
Order_line PK - ol_w_id, ol_d_id, ol_o_id, ol_number
Nation PK - n_nationkey

查询:

select   c_id, c_last, sum(ol_amount) as revenue, c_city, c_phone, n_name
from     customer, oorder, order_line, nation
where    c_id = o_c_id
     and c_w_id = o_w_id
     and c_d_id = o_d_id
     and ol_w_id = o_w_id
     and ol_d_id = o_d_id
     and ol_o_id = o_id
     and o_entry_d >= '2007-01-02 00:00:00.000000'
     and o_entry_d <= ol_delivery_d
     and n_nationkey = ascii(substr(c_state,1,1))
group by c_id, c_last, c_city, c_phone, n_name
order by revenue desc

如何提高此查询的性能?你推荐什么物化视图?这是一个好的选择吗?

CREATE MATERIALIZED VIEW mview AS
select c_id, c_last, ol_amount, c_city, c_phone, o_entry_d, ol_delivery_d, c_state
from     customer, oorder, order_line
where    c_id = o_c_id
     and c_w_id = o_w_id
     and c_d_id = o_d_id
     and ol_w_id = o_w_id
     and ol_d_id = o_d_id
     and ol_o_id = o_id;

【问题讨论】:

你能做一个explain select ... 并发布输出吗? 您可以在发布的执行计划中看到这一点……在哪里说 TEXT。谢谢 很酷的 postgresql 查询解释网站 :) 我也有同样的看法,真的很好:) 【参考方案1】:
    切勿使用此类列名。 如果不是 1) 则永远不要在查询中写入没有表前缀的列名(无需在列名中添加前缀)。 最好在“join”子句中编写连接,而不是在“where”子句中,这样您就可以使用连接的层次结构进行操作。

最后,你跑了吗

analyse customer; 
analyse order_line; 
analyse oorder; 
analyse nation;

在 ascii(substr(c_state,1,1)) 上添加索引后? 如果没有 - 运行它。

您还可以在 select 子句中将 n_name 作为子查询:

select c_id, c_last, revenue, c_city, c_phone, (select x.n_name from nation x where x.n_nationkey = ascii(c_statecut)) as n_name 
  from (
select   c_id, c_last, sum(ol_amount) as revenue, c_city, c_phone, substr(c_state,1,1) as c_statecut
from     customer, oorder, order_line
where    c_id = o_c_id
     and c_w_id = o_w_id
     and c_d_id = o_d_id
     and ol_w_id = o_w_id
     and ol_d_id = o_d_id
     and ol_o_id = o_id
     and o_entry_d >= '2007-01-02 00:00:00.000000'
     and o_entry_d <= ol_delivery_d
group by c_id, c_last, c_city, c_phone, c_statecut
) finale
order by revenue desc

国家表是一个简单的查找表,但它会影响聚合的整体计划。

关于物化视图,单独使用 order_line 表的预聚合是获取总数的最快方法,但就查询中的“o_entry_d

select o_c_id, ol_w_id, ol_d_id, ol_o_id, sum(ol_amount)
  from order_line 
  join oorder
    on     ol_w_id = o_w_id
       and ol_d_id = o_d_id
       and ol_o_id = o_id
       and o_entry_d <= ol_delivery_d -- (very strange condition, which looks redundant... it could be better if you can remove it)
 where o_entry_d >= '2007-01-02 00:00:00.000000'
 group by o_c_id, ol_w_id, ol_d_id, ol_o_id

如果此查询大约需要 3 秒,则将其具体化。如果少于 3 秒,那么您可以即时加入它。

【讨论】:

我明白你的建议,但没有帮助。此外,现在花更多的时间。【参考方案2】:

您可以尝试使用ascii(substr(c_state,1,1)) 的表达式索引。您对客户进行顺序扫描。

【讨论】:

以上是关于如何提高此 PostgreSQL 查询在索引扫描中的性能的主要内容,如果未能解决你的问题,请参考以下文章

mysql提高查询速度

为啥即使使用仅索引扫描 PostgresQL 计数也如此缓慢

如何提高sql查询速度

在oracle里,一个sql多表查询,单独执行能利用索引提高速率,但外层套上分页时,会全表扫描,如何解决,求助高手

PostgreSQL——查询优化——生成路径3

PostgreSQL——查询优化——生成路径3