Postgres:“ SELECT * FROM t WHERE a <CURRENT_TIMESTAMP ORDER BY b”的最佳索引是什么?

时间:2019-05-24 19:12:26

标签: sql postgresql

查询是:

SELECT *
FROM t
WHERE a < CURRENT_TIMESTAMP
ORDER BY b

什么是最佳索引?

如果我们还有另一个查询怎么办?

SELECT *
FROM t
WHERE a < CURRENT_TIMESTAMP AND c < CURRENT_TIMESTAMP
ORDER BY b

什么是最佳索引? 是否有一个可以同时服务于两个查询的索引?

编辑:对于已经写了一些答案的更改查询,我深表歉意。新查询更好地反映了我的情况。

编辑:其他可能相关的详细信息:

1)编写“ SELECT *”以简化问题(实际查询不使用*)。

2)如果可以提高整体性能,我可以使用LIMIT分解查询。

5 个答案:

答案 0 :(得分:2)

在这种特定情况下,您想要的是局部索引(过滤索引)。您可以在这里找到文档:https://www.postgresql.org/docs/current/indexes-partial.html

CREATE INDEX idx___xxx ON table (b)
     WHERE a<0;

在问题已更改的情况下进行编辑:只要where子句使用常量并且在索引操作之前知道该常量,此答案就很好。

答案 1 :(得分:2)

针对您的情况最好的索引是以下顺序的多列索引:(a, c, b)

对于第一个查询,计划者将按a < 0进行过滤,并使用第二列进行排序(查询末尾不需要排序)。

对于第二种情况,计划者将按a < 0 and c < 0进行过滤,并使用第三列对找到的记录进行排序(也跳过最后的排序)。

Dumitrescu Bogdan的答案有效,但需要在末尾进行排序,在第二种情况下,筛选出的记录数比我的方法要小。

学习多列索引的良好参考:https://use-the-index-luke.com/sql/where-clause/the-equals-operator/concatenated-keys

此外,这还解释了索引如何避免最后进行排序操作:https://use-the-index-luke.com/sql/sorting-grouping/indexed-order-by

更新

作者更新后,需要两个索引,以避免排序操作。

对于第一种情况,您将需要在(a, b)上建立索引。 对于第二种情况,您将需要在(a, c, b)上建立索引。使用这种配置,在两种情况下都可以避免最终的排序操作。

答案 2 :(得分:1)

可能有效的索引是:

CREATE INDEX ix_t_006 on t (a, c);

经过反复测试,我发现这是处理两个查询的“确定”索引。您会看到此索引处理了您的WHERE子句,但未处理ORDER BY b。

相反,ORDER BY由内存中的快速排序处理。这是因为正在对列(a,c)执行“位图索引扫描”,这意味着任何隐含的排序顺序都将被撤消。因此,在(a,c,b)上创建索引将无效,因为该订单将被撤销,因此,我们唯一要做的就是在(a,c)上创建索引。

问题中缺少的是您将获得的结果数量以及内存快速排序是否令人满意。

请使用EXPLAIN ANALYZE SELECT ...进行验证。

第一个查询导致:

EXPLAIN ANALYZE
SELECT *
FROM t
WHERE a < CURRENT_TIMESTAMP
ORDER BY b;

 Sort  (cost=59.91..61.61 rows=680 width=12) (actual time=0.012..0.012 rows=0 loops=1)
   Sort Key: b
   Sort Method: quicksort  Memory: 25kB
   ->  Bitmap Heap Scan on t  (cost=9.42..27.92 rows=680 width=12) (actual time=0.005..0.006 rows=0 loops=1)
         Recheck Cond: (a < 0)
         ->  Bitmap Index Scan on ix_t_006  (cost=0.00..9.25 rows=680 width=0) (actual time=0.004..0.004 rows=0 loops=1)
               Index Cond: (a < 0)
 Planning time: 0.091 ms
 Execution time: 0.042 ms

第二个查询导致:

EXPLAIN ANALYZE
SELECT *
FROM t
WHERE a < CURRENT_TIMESTAMP AND c < CURRENT_TIMESTAMP
ORDER BY b;

 Sort  (cost=33.30..33.86 rows=227 width=12) (actual time=0.012..0.013 rows=0 loops=1)
   Sort Key: b
   Sort Method: quicksort  Memory: 25kB
   ->  Bitmap Heap Scan on t  (cost=11.01..24.41 rows=227 width=12) (actual time=0.006..0.006 rows=0 loops=1)
         Recheck Cond: ((a < 0) AND (c < 0))
         ->  Bitmap Index Scan on ix_t_006  (cost=0.00..10.95 rows=227 width=0)(actual time=0.005..0.005 rows=0 loops=1)
               Index Cond: ((a < 0) AND (c < 0))

经过反复测试,我发现答案必须重复编辑。有一次,我发现自己想删除我的答案,因为我一直在进行很大的更改。令我失望的是我没有找到可以帮助您进行ORDER BY的答案。

我认为关键是继续尝试EXPLAIN ANALYZE,直到获得为止。

答案 3 :(得分:0)

可能没有索引比堆扫描(也就是全表扫描)更好。

您不包括表统计信息,但我假设过滤条件会检索到超过5%的行(最有可能)。如果是这种情况,堆扫描将比任何索引都快,并且资源占用更少。

这些查询返回百分之几的行? 50%,5%,0.5%?

答案 4 :(得分:0)

假设ac不包含空值,则可以这样写:

WHERE a < CURRENT_TIMESTAMP AND c < CURRENT_TIMESTAMP ORDER BY b

为:

WHERE GREATEST(a, c) < CURRENT_TIMESTAMP ORDER BY b

您可以在GREATEST(a, c)上创建索引并包括覆盖列:

CREATE INDEX ix2 ON t(GREATEST(a, c), b)

原始查询的速度可能会稍快(下面的数据库提示提示了相同的内容……290.823ms与91.689ms);但是验证这一点的唯一方法是针对实际数据运行查询。

Demo on db<>fiddle