3

我们在同一张表上有 2 个相同的(双精度)列,有 2 个相同的索引运行 2 个相同的查询。然而,一个运行速度比另一个快近 10 倍。这是什么原因造成的?

1) SELECT MIN("reports"."longitude") AS min_id FROM "reports" WHERE (area2 = 18)

2) SELECT MIN("reports"."latitude") AS min_id FROM "reports" WHERE (area2 = 18)

1 次在 28 毫秒内运行,2 次在 >300 毫秒内运行

以下是“解释”:
1)

Result  (cost=6.07..6.08 rows=1 width=0)"
InitPlan 1 (returns $0)"
  ->  Limit  (cost=0.00..6.07 rows=1 width=8)"
      ->  Index Scan using longitude on reports  (cost=0.00..139617.49 rows=22983 width=8)"
            Index Cond: (longitude IS NOT NULL)"
            Filter: (area2 = 18)"

2)

Result  (cost=5.95..5.96 rows=1 width=0)"
InitPlan 1 (returns $0)"
  ->  Limit  (cost=0.00..5.95 rows=1 width=8)"
      ->  Index Scan using latitude on reports  (cost=0.00..136754.07 rows=22983 width=8)"
            Index Cond: (latitude IS NOT NULL)"
            Filter: (area2 = 18)"

这里要求的是解释分析输出...

1)

Result  (cost=6.07..6.08 rows=1 width=0) (actual time=10.992..10.993 rows=1 loops=1)"
InitPlan 1 (returns $0)"
    ->  Limit  (cost=0.00..6.07 rows=1 width=8) (actual time=10.985..10.986 rows=1 loops=1)"
          ->  Index Scan using longitude on reports  (cost=0.00..139617.49 rows=22983 width=8) (actual time=10.983..10.983 rows=1 loops=1)"
                Index Cond: (longitude IS NOT NULL)"
                Filter: (area2 = 18)"
Total runtime: 11.033 ms"

2)

 Result  (cost=5.95..5.96 rows=1 width=0) (actual time=259.749..259.749 rows=1 loops=1)"
InitPlan 1 (returns $0)"
    ->  Limit  (cost=0.00..5.95 rows=1 width=8) (actual time=259.740..259.740 rows=1 loops=1)"
          ->  Index Scan using latitude on reports  (cost=0.00..136754.07 rows=22983 width=8) (actual time=259.739..259.739 rows=1 loops=1)"
                Index Cond: (latitude IS NOT NULL)"
                Filter: (area2 = 18)"
Total runtime: 259.789 ms"
---------------------

到底是怎么回事?如何让第二个查询正常运行并快速运行?据我所知,这两种设置都是相同的。

4

2 回答 2

3

首先,不能保证索引会加快查询速度。其次,在进行性能考虑时,您需要多次运行每个查询。加载索引和将页面加载到缓存中会产生开销,这会影响查询的长度。

我不是 Postgres 的专家,但考虑到这一点,我并不感到惊讶。

查询计划循环遍历索引,找到与 area2 = 18 匹配的相应行,然后希望在第一个处停止(它正在使用索引,因此它可以从最低值开始向上移动)。这是对其工作方式的猜测;我不知道 Postgres 正在这样做。

在任何情况下,发生的情况是该区域更接近经度索引的起点,而不是纬度索引的起点。所以,它首先在那里找到第一个匹配的记录。如果这个解释是正确的,那么与数据库中的其他事物相比,这表明该区域相对西(经度低)和相对北(纬度高)。

顺便说一句,假设有很多区域,在 Area2 上使用索引可能会得到更好的结果。

于 2012-07-11T16:32:32.473 回答
2

您正在进行索引扫描,但检查的记录数取决于您必须在列表的多远才能匹配area2条件。

除非您的 area2 分布很奇怪,否则要优化此查询,您应该将复合索引放在(area2, latitude)and上(area2, longitude)。我怀疑你会得到<10毫秒。PG 还可以area2使用其位图堆扫描功能将单独的索引与现有索引组合,以代替复合索引。

于 2012-07-11T18:13:17.737 回答