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添加索引。
答案 0 :(得分:3)
最佳查询取决于缺少的信息 在典型的设置中,这应该快得多:
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
并直接从discounted_vehicles
加入vehicle_options
。
此外,如果每个不同选项有许多符合条件的行,EXISTS
通常会更快。
理想情况下,您有多列索引:
discounted_vehicles(discount_id, vehicle_id)
vehicle_options(vehicle_id, option_id)
按此顺序索引列。您可能在vehicle_options
上有一个PK约束,提供第二个索引,但列顺序应匹配。相关:
根据实际数据分布,可能会有更快的查询样式。相关:
更改加入订单通常是徒劳。 Postgres重新加载以任何预期最快的方式加入。 (例外情况适用。)相关:
答案 1 :(得分:0)
1 - 更改连接顺序,从最小表连接到最大表。
幕后花絮PostgreSQL根据SQL优化器设计的解释计划重新排列表的顺序。你写的顺序没有意义。
2 - 向discounted_vehicles.discount_id添加索引。
这取决于discount_id
列的选择性。你认为它会过滤95%的行只留下5%吗?如果它留下5%或更少,索引将有所帮助。否则全表扫描会更快。
此外,如果还没有,我会添加索引:
vehicle_options (vehicle_id)
但也许它已经由外键创建了。
答案 2 :(得分:0)
尝试使用groupby而不是distinct
SELECT
"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
GROUP BY
"options.id";
答案 3 :(得分:0)
尽管如此,您需要先创建必要的索引,然后尝试在查询
下运行SELECT "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
GROUP BY options"."id", "options"."foo_option_id",
"options"."description"