示例查询显示PostgreSQL中的基数估计错误

时间:2014-07-28 18:53:44

标签: sql postgresql

我正在使用PostgreSQL9.3开发一个项目。我使用下面的查询来说明选择性估计错误如何导致使用PostgreSQL8.3在TPC-H工作负载上查询执行时间多倍增加。

select 
    n_name, 
    sum(l_extendedprice * (1 - l_discount)) as revenue 
from 
    customer, 
    orders, 
    lineitem, 
    supplier, 
    nation,
    region 
where 
    c_custkey = o_custkey 
    and l_orderkey = o_orderkey 
    and l_suppkey = s_suppkey   
    and c_nationkey = s_nationkey 
    and s_nationkey = n_nationkey 
    and n_regionkey = r_regionkey 
    and (r_name='ASIA' or r_name='AFRICA') 
    and o_orderdate >= date '1994-01-01' 
    and o_orderdate < date '1994-01-01' + interval '1 year' 
    and l_shipdate <= l_receiptdate 
    and l_commitdate <= l_shipdate + integer '90' 
    and l_extendedprice <= 20000 
    and c_name like '%r#00%' 
    and c_acctbal <=2400 
group by 
    n_name 
order by    
    revenue desc

问题是PostgreSQL8.3正在选择一个涉及大量NestedLoop连接的计划,因为对lineitem和客户的选择性估计是大错误的。我认为这主要是由于LIKE模式匹配。但最佳计划应该是使用Hash Joins。

最近我为我的项目升级到PostgreSQL9.3并观察到上述查询不再给出错误的计划。我花了一些时间试图在TPC-H 1GB数据上找到一个大基数估计错误的查询,直到现在都没有成功。是否有任何PostgreSQL极客知道TPC-H基准测试的现成查询或任何查询以显示PostgreSQL9.3中的基数估计错误

1 个答案:

答案 0 :(得分:1)

这是回答comment by @Twelfth以及问题本身。

Three quotes from this chapter in the manual:
"Controlling the Planner with Explicit JOIN Clauses"

  

明确的内部联接语法(INNER JOINCROSS JOIN或简单的JOIN)   在语义上与列出FROM中的输入关系相同,所以它   不限制连接顺序。

...

  

强制规划人员遵循显式列出的连接顺序   JOIN s,将join_collapse_limit运行时参数设置为1.(其他   可能的值将在下面讨论。)

...

  

以这种方式约束计划者的搜索是一种有用的技术   既可以减少计划时间,也可以指导计划者   良好的查询计划

大胆强调我的。相反,您可以滥用相同的方法将查询计划程序指向错误的查询计划,以用于测试目的。阅读整个手册页。它应该是有用的。

此外,您可以逐个disabling alternative methods强制嵌套循环(仅在您的会话中最好)。像:

SET enable_hashjoin = off;

等。
关于检查和设置参数:

强制实际估计错误

一种显而易见的方法是禁用autovacuum并在表中添加/删除行。然后查询计划程序正在处理过时的统计信息。请注意,其他一些命令也会更新统计信息。

统计信息存储在目录表pg_classpg_statistics中。

SELECT * FROM pg_class WHERE oid = 'mytable'::regclass;
SELECT * FROM pg_statistic WHERE starelid = 'mytable'::regclass;

这引出了另一种选择。您可以在这两个表中伪造条目。需要超级用户权限 作为一个新手,你不会打击我,但是对一般公众的警告:如果你在目录表中破坏了某些东西,你的数据库(集群)可能会瘫痪。你被警告了。