首页 > 解决方案 > 如何优化结合了 INNER JOIN、DISTINCT 和 WHERE 的 SQL 查询?

问题描述

SELECT DISTINCT options.id, options.foo_option_id, options.description
FROM vehicles 
INNER JOIN vehicle_options     ON vehicle_options.vehicle_id = vehicles.id 
INNER JOIN options             ON options.id = vehicle_options.option_id 
INNER JOIN discounted_vehicles ON vehicles.id = discounted_vehicles.vehicle_id 
WHERE discounted_vehicles.discount_id = 4;

上面的查询返回 2067 行,它在 1.7 秒内在本地运行。我想知道它是否尽可能快,或者我是否可以以某种方式进一步调整它,因为这个数据集会随着时间的推移快速增长。

我在没有改变速度的情况下尝试过的事情:

1 - 更改连接顺序,从最小的表连接到最大的表。

2 - 向 discounted_vehicles.discount_id 添加索引。

标签: sqlpostgresqlpostgresql-performance

解决方案


最佳查询取决于缺失的信息。
在典型设置中,这应该会更快:

SELECT id, foo_option_id, description
FROM   options o
WHERE  EXISTS (
   SELECT
   FROM   discounted_vehicles d
   JOIN   vehicle_options vo USING (vehicle_id)
   WHERE  d.discount_id = 4
   AND    vo.option_id = o.id
   );

假设参照完整性,由 FK 约束强制执行,我们可以从查询中省略表vehicle并直接连接 from discounted_vehiclesto vehicle_options

此外,EXISTS如果每个不同选项有许多符合条件的行,通常会更快。

理想情况下,您将在以下位置拥有多列索引:

discounted_vehicles(discount_id, vehicle_id)
vehicle_options(vehicle_id, option_id)

按此顺序索引列。您可能对vehicle_options提供第二个索引有 PK 约束,但列顺序应该匹配。有关的:

根据实际数据分布,可能会有更快的查询样式。有关的:

更改连接顺序通常是徒劳的。Postgres 重新排序以任何它期望最快的方式加入。(有例外情况。)相关:


推荐阅读