6

我正在尝试获取表中的最新行。我有一个简单的时间戳created_at,它被索引。当我查询ORDER BY created_at DESC LIMIT 1时,它比我想象的要多得多(我的机器上 36k 行大约需要 50 毫秒)。

EXPLAIN -ing 声称它使用反向索引扫描,但我确认将索引更改为(created_at DESC)不会更改查询计划器中用于简单索引扫描的成本。

如何优化此用例?

运行 postgresql 9.2.4

编辑:

# EXPLAIN SELECT * FROM articles ORDER BY created_at DESC LIMIT 1;
                                                  QUERY PLAN                                                       
-----------------------------------------------------------------------------------------------------------------------
Limit  (cost=0.00..0.58 rows=1 width=1752)
   ->  Index Scan Backward using index_articles_on_created_at on articles  (cost=0.00..20667.37 rows=35696 width=1752)
(2 rows)
4

1 回答 1

6

假设我们正在处理一个大表部分索引可能会有所帮助:

CREATE INDEX tbl_created_recently_idx ON tbl (created_at DESC)
WHERE created_at > '2013-09-15 0:0'::timestamp;

正如您已经发现的那样:下降或上升在这里几乎不重要。Postgres 可以以几乎相同的速度向后扫描(例外情况适用于多列索引)。

查询以使用此索引:

SELECT * FROM tbl
WHERE  created_at > '2013-09-15 0:0'::timestamp -- matches index
ORDER  BY created_at DESC
LIMIT  1;

这里的重点是让索引更小,这样应该更容易缓存和维护。

  1. 您需要选择一个保证小于最新时间戳的时间戳。
  2. 您应该不时重新创建索引以切断旧数据。
  3. 条件需要IMMUTABLE

因此,一次性效果会随着时间的推移而恶化。具体问题是硬编码条件:

WHERE created_at > '2013-09-15 0:0'::timestamp

自动化

您可以不时手动更新索引和查询。或者,您可以借助以下功能将其自动化:

CREATE OR REPLACE FUNCTION f_min_ts()
  RETURNS timestamp LANGUAGE sql IMMUTABLE AS
$$SELECT '2013-09-15 0:0'::timestamp$$

指数:

CREATE INDEX tbl_created_recently_idx ON tbl (created_at DESC);
WHERE created_at > f_min_ts();

询问:

SELECT * FROM tbl
WHERE  created_at > f_min_ts()
ORDER  BY created_at DESC
LIMIT  1;

使用 cron 作业或一些基于触发器的事件来自动化娱乐。您的查询现在可以保持不变。但是您需要在更改此函数后以任何方式重新创建所有索引。只需放下并创建每一个。

第一的 ..

... 测试你是否真的用这个来击中瓶颈。

试试一个简单的是否DROP index ... ; CREATE index ...能完成这项工作。那么你的索引可能已经膨胀了。您的 autovacuum 设置可能已关闭。

或者尝试VACUUM FULL ANALYZE让您的整个表格和索引处于原始状态并再次检查。

其他选项包括通常的一般性能调整覆盖索引,具体取决于您从表中实际检索到的内容。

于 2013-09-16T17:44:16.707 回答