sql - 索引 ORDER BY 与 LIMIT 1

标签 sql postgresql indexing sql-order-by postgresql-performance

我正在尝试获取表中的最新行。我有一个简单的时间戳 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)

最佳答案

假设我们正在处理一个大表,一个partial index可能有帮助:

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 使整个表和索引处于原始状态并再次检查。

其他选项包括 usual general performance tuningcovering indexes ,取决于您实际从表中检索的内容。

关于sql - 索引 ORDER BY 与 LIMIT 1,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18833832/

相关文章:

php - 根据另一列先前选择的值选择特定行

sql - Access SQL查询: How to only display most recent record of duplicates

PostgreSQL:使用for循环迭代表行,根据当前行检索列值

postgresql - postgres 将数据库复制到另一台服务器可减少数据库大小

mysql - 如何使用 SQL 将相同的列值分组在一起?

mysql - 根据条件更新查询

mysql - 我如何在 sql 中进行查询,使 o 拥有更多房屋的人?

MongoDB 复合索引优化键和范围条件更新

python - Numpy 索引 : Set values of an array given by conditions in different array

mysql - 在没有索引的 mysql 5.0 中运行时间良好,但在 5.1 中则不然