我正在试验 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 万行customers
。orders
由于一对一的关系,订单详细信息包含相同的金额。
更新:似乎该示例过于简化而无法重现该问题,因为我再次检查了,在这种情况下,两个执行平原是相同的。然而,在我的实际查询中有更多连接时,会出现问题:如果我将客户作为第一个连接,则执行速度会快 100 倍。我将添加我的真实查询,但由于匈牙利语以及它是由 XPO 和 Npgsql 生成的事实,使其可读性降低。
第一个查询比第二个查询慢得多(大约 100 倍),当我使用 EXPLAIN ANALYZE 输出计划时,我可以看到连接的顺序反映了它们在查询字符串中的位置。因此,首先将两个“巨型”表连接在一起,然后在过滤的客户表连接后(过滤器仅选择一行)。
第二个查询更快,因为连接从一个客户行开始,然后连接 20-30 个订单详细信息行。
不幸的是,在我的情况下,XPO 生成了第一个版本,所以我在性能方面受到了影响。
为什么 PostgreSQL 查询计划程序没有注意到客户的联接在 WHERE 子句中有条件?IMO 正确的优化是首先采用具有任何类型过滤器的连接,然后采用仅参与选择的连接。
任何形式的帮助或建议表示赞赏。