Postgresql - 使用enable_nestloop = false查询运行速度更快。为什么规划师没有做正确的事情?

时间:2011-10-25 05:41:24

标签: postgresql

当我使用默认的enable_nestloop = true和enable_nestloop = false(~10秒)运行它时,我的查询运行速度慢得多(约5分钟)。

解释两种情况的分析结果:

机器A nestloop = true - http://explain.depesz.com/s/nkj0(约5分钟) 机器A nestloop = false - http://explain.depesz.com/s/wBM(~10秒)

在另一台稍微慢一点的机器上,复制数据库并保留默认的enable_nestloop = true需要大约20秒。

机器B nestloop = true - (~20secs)

对于上述所有情况,我确保在运行查询之前进行了ANALYZE。没有其他查询并行运行。

两台机器都在运行Postgres 8.4。机器A运行Ubuntu 10.04 32位,而机器B运行Ubuntu 8.04 32位。

此处提供了实际查询。它是一个包含许多连接的报告查询,因为数据库主要用于事务处理。

  1. 如果不采用物化视图的方式,我可以做些什么来让规划师通过设置enable_nestloop = false做我所做的事情?

  2. 从我所做的研究来看,计划者选择看似不理想的查询的原因似乎是因为估计行与实际行之间存在巨大差异。我怎样才能让这个数字更接近?

  3. 如果我要重写查询,我应该更改什么?

  4. 为什么规划师似乎正在为机器B做正确的事情。我应该在两台机器上进行比较?

4 个答案:

答案 0 :(得分:2)

如果查询计划程序选择次优的查询计划,则可能会使用不完整或误导性的信息。

有关服务器调整的信息,请参阅此PostgreSQL Wiki page。特别要注意 random_page_cost default_statistics_target 的章节。
另请阅读Statistics Used by the PlannerPlanner Cost Constants手册中的相应章节。

更具体地说,增加以下列的statistics target可能有所帮助:

ALTER TABLE postgres.products ALTER COLUMN id SET STATISTICS 1000;
ALTER TABLE postgres.sales_orders ALTER COLUMN retailer_id SET STATISTICS 1000;
ALTER TABLE postgres.sales_orders ALTER COLUMN company_id SET STATISTICS 1000;

ALTER TABLE goods_return_notes ALTER COLUMN retailer_id SET STATISTICS 1000;
ALTER TABLE goods_return_notes ALTER COLUMN company_id SET STATISTICS 1000;

ALTER TABLE retailer_category_leaf_nodes ALTER COLUMN tree_left SET STATISTICS 1000;
ALTER TABLE channels ALTER COLUMN principal_id SET STATISTICS 1000;

这些涉及导致

的过滤器
  

估计行数与实际行之间存在巨大差异。

更多。检查刨床与估算偏差很大的每一列。默认值仅为100.仅对带有>>的表有意义1000行。试验设置。之后在表格上运行ANALYZE以使更改生效。

postgres(sales_orders.retailer_id) WHERE retailer_id IS NOT NULL上创建部分索引也可能会有所帮助(取决于常见的NULL值)。


可能对您有帮助的另一件事是升级到最新版本9.1。这方面已经取得了一些重大进展。

答案 1 :(得分:2)

原来重写查询是最好的解决方法。查询的编写方式使其严重依赖左连接并具有许多连接。通过使用我对查询所加入的表中数据的连接性质的了解,我将其展平并减少了左连接。我想经验法则是,如果规划人员提出了真正糟糕的估计,那么可能有更好的方法来编写查询。

答案 2 :(得分:2)

这可能是有用的阅读: PostgreSQL tutorial about explicit JOINs

查询计划程序尝试分析JOIN顺序以找到JOINing的最佳顺序。

我看到你的查询至少有15个JOIN。可能的JOIN订单数量增加为factorial(n!)。因此,如果有15个JOIN,查询计划程序尝试找到最佳JOIN顺序是不合理的 - 它必须查看15! = 1307674368000不同的计划。

因此它使用基因查询优化器。见Query Planning: Genetic Query Optimizer parameters。参数“geqo_threshold”确定查询计划程序必须提供多少JOIN才能使用基因查询优化程序。

这样,PostgreSQL规划器只查看可能变体的一小部分,并尝试找到最好的变体(随机)。因此,每次运行ANALYZE时,都可能会提出更好的计划。

我认为通常情况下,如果你有这么多表加入JOIN,你最好不要像你那样做:将查询重写为最佳JOIN顺序。

答案 3 :(得分:0)

在具有相同PostgreSQL的两台服务器上,相同数据和相同查询的不同计划通常只有一个原因。这是不同的配置 - 主要是work_mem的值。散列连接通常更快,但需要大量可用内存。