【问题标题】:How to reduce the costs of an sql select with order by?如何通过 order by 降低 sql select 的成本?
【发布时间】:2014-12-18 20:15:53
【问题描述】:

我正在执行大量的 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

【问题讨论】:

  • 您的 Postgres 版本至关重要(并且应该始终在问题中)。
  • postgresql 9.3.2 以上更新
  • Err... 估计成本实际上很小。 0.42..9.77 -> 9.78..9.79。那里的成本很高的是定位行。你确定你应该担心排序行的成本吗? :-)
  • 您真的需要 all 列 (SELECT *) 还是可以减少该列?
  • 我不知道,但我认为分拣成本相当高,也许我可以以某种方式降低它们。

标签: sql database postgresql


【解决方案1】:

从给定的数字来看,您的备用查询(“如果我只是按价格排序而不停止”)实际上 较慢,并且您误读了数字。 0.079 ms0.42 (?)。

这也是有道理的,因为您的第一个查询与索引的排序顺序完美匹配。

你已经有了完美的索引。删除price 的建议是没有根据的。附加列删除了排序步骤的成本:time=0.055..0.055,正如您在计划中看到的那样。

无论哪种方式,这都不重要。一旦您将检索到的行数减少到 数(在索引的前导列上使用谓词),其余的都是便宜的。

要获得更有趣的结果,请不要使用 stops &lt; 2 进行测试(仅留下 0 和 1 个停靠点),尝试使用更大的数字来查看任何(可能很小的)差异。

实际上,由于几乎所有列都在索引中,我会尝试添加一个缺失的列id,如果你能从中得到index-only scans(Postgres 9.2+,请阅读 Postgres Wiki 在链接页面):

CREATE INDEX my_idx ON flights (outbound, inbound, date, stops, price, <b>id</b>);
SELECT id, outbound, inbound, date, stops, price
FROM ...

【讨论】:

    【解决方案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 子句。考虑到where,我不知道是否有办法消除order by,但除非当天有数千个航班,否则排序应该没什么大不了的。

    【讨论】:

    • 也许我什至不需要在这里停止索引?没有索引停止的差异是0.006ms。你认为在这种情况下,索引为 3 而不是 4 列更有好处?
    • @membersound 。 . . stops 的影响可能很小,具体取决于不止一站的例程数量。但我会包含它,因为索引中的附加列并不是很多开销。
    【解决方案3】:

    成本是任意数字。

    此外,排序步骤的数字是进入和退出该步骤时计划中的总累积成本,而不是与该单个步骤相关的特定成本.

    您的查询可以进行快速排序。它只有四行,在 0.079 毫秒内完成整个查询。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-07
      • 2022-01-16
      • 2022-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-08
      相关资源
      最近更新 更多