我正在执行大量的SQL选择,如下所示。想象一下,我们有一个包含航班的数据库,每个航班当然可能有出境和入境机场,出发日期,出发地和目的地之间的停靠点数(长途航班),当然还有价格。
我现在想要选择一条特定路线,并选择停靠次数最少的路线,当然还有最优价路线。
CREATE TABLE flights(
id integer
outbound character varying,
inbound character varying,
date timestamp,
stops integer
price numeric
);
CREATE INDEX my_idx ON flights (outbound, inbound, date, stops, price);
select * from flights where outbound = 'SFO' and inbound = 'SYD' and date = '2015-10-10' and stops < 2 order by stops asc, price asc.
问题:使用explain-analyze
的费用非常高:
Sort (cost=9.78..9.79 rows=1 width=129) (actual time=0.055..0.055 rows=4 loops=1)
Sort Key: stops, price
Sort Method: quicksort Memory: 26kB
-> Index Scan using my_idx (cost=0.42..9.77 rows=1 width=129) (actual time=0.039..0.041 rows=4 loops=1)
Index Cond: ((date = '2015-10-10'::date) AND ((outbound)::text = 'SFO'::text) AND (stops < 2) AND ((inbound)::text = 'SYD'::text))
Total runtime: 0.079 ms
如果我只是不停地按价格排序,那么成本是可以的(0.42)。但以停靠方式排序会增加成本显着。
如何降低成本?
postgresql 9.3.2
答案 0 :(得分:5)
根据给定的数字判断,您的备用查询(“如果我只是按价格排序而不停止”)实际上是较慢,并且您误读了这些数字。 0.079 ms
与0.42
(?)。
这也是有道理的,因为你的第一个查询完全符合索引的排序顺序。
您已拥有完美索引。删除price
的建议没有根据。附加列会删除排序步骤的费用:time=0.055..0.055
,如您在计划中所见。
无论哪种方式,它根本不重要。只要您将检索到的行数减少到 small 数字(在索引的前导列上有谓词),其余的都是便宜的。
要获得更有趣的结果,请不要使用stops < 2
(只留下0和1站点)进行测试,尝试使用更大的数字来查看任何(可能很小的)差异。
实际上,由于几乎所有列都已在索引中,我也会尝试添加一个缺少的列id
- 如果你可以从中获取index-only scans(Postgres 9.2+,请阅读链接页面上的Postgres Wiki:
CREATE INDEX my_idx ON flights (outbound, inbound, date, stops, price, id);
SELECT id, outbound, inbound, date, stops, price
FROM ...
答案 1 :(得分:2)
这是您的查询:
select *
from flights
where outbound = 'SFO' and inbound = 'SYD' and date = '2015-10-10' and stops < 2
order by stops asc, price asc.
最佳指数为:flights(outbound, inbound, date, stops)
。这适用于where
子句。鉴于order by
,我不知道是否有办法消除where
,但除非当天有数千个航班,否则排序不应该是一个大问题。
答案 2 :(得分:0)
费用是任意数字。
此外,排序步骤的数字是进入和退出该步骤时计划中的总累积成本,而不是与该单个步骤相关的特定成本
您的查询可以快速排序。它只有四行,它以0.079毫秒完成整个查询。