0

我正在试验 PostgreSQL (v9.3)。我有一个相当大的数据库,并且经常需要使用 8-10 个连接表(作为大型数据网格的来源)执行查询。我使用 Devexpress XPO 作为 PostgreSQL 之上的 ORM,所以很遗憾我无法控制连接的生成方式。

下面的例子是一个相当简化的例子,实际情况更复杂,但就我的检查而言,主要问题也可以在这方面看到。

考虑(语义上)相同查询的以下变体:

SELECT o.*, c.*, od.* 
FROM orders o 
LEFT JOIN orderdetails od ON o.details = od.oid
LEFT JOIN customers c ON o.customer = c.oid
WHERE c.code = 32435 and o.date > '2012-01-01';

SELECT o.*, c.*, od.* 
FROM orders o 
LEFT JOIN customers c ON o.customer = c.oid
LEFT JOIN orderdetails od ON o.details = od.oid
WHERE c.code = 32435 and o.date > '2012-01-01';

orders表包含大约 100 万行,大约 3 万行customersorders由于一对一的关系,订单详细信息包含相同的金额。

更新:似乎该示例过于简化而无法重现该问题,因为我再次检查了,在这种情况下,两个执行平原是相同的。然而,在我的实际查询中有更多连接时,会出现问题:如果我将客户作为第一个连接,则执行速度会快 100 倍。我将添加我的真实查询,但由于匈牙利语以及它是由 XPO 和 Npgsql 生成的事实,使其可读性降低。

第一个查询比第二个查询慢得多(大约 100 倍),当我使用 EXPLAIN ANALYZE 输出计划时,我可以看到连接的顺序反映了它们在查询字符串中的位置。因此,首先将两个“巨型”表连接在一起,然后在过滤的客户表连接后(过滤器仅选择一行)。

第二个查询更快,因为连接从一个客户行开始,然后连接 20-30 个订单详细信息行。

不幸的是,在我的情况下,XPO 生成了第一个版本,所以我在性能方面受到了影响。

为什么 PostgreSQL 查询计划程序没有注意到客户的联接在 WHERE 子句中有条件?IMO 正确的优化是首先采用具有任何类型过滤器的连接,然后采用仅参与选择的连接。

任何形式的帮助或建议表示赞赏。

4

1 回答 1

1

仅当您的查询的连接未折叠时,连接订单才重要。这是由查询计划程序在内部完成的,但您可以使用join_collapse_limit运行时选项来操作该过程。

但是请注意,默认情况下,查询计划器不会每次都找到最佳连接顺序:

以这种方式约束规划器的搜索对于减少规划时间和将规划器引导到一个好的查询计划都是一种有用的技术。如果计划者默认选择了一个错误的连接顺序,你可以通过 JOIN 语法强制它选择一个更好的顺序——假设你知道一个更好的顺序,也就是说。建议进行实验。

为了获得最佳性能,我建议使用某种本机查询(如果可用)。但是,如果您确保这不会导致其他问题,那么提高它join_collapse_limit 可能是一个足够好的解决方案。

还值得一提的是,筹集资金join_collapse_limit很可能会增加计划时间。

于 2014-12-04T12:05:32.230 回答