带有LIMIT 1的索引ORDER BY

时间:2013-09-16 17:24:36

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

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

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)

1 个答案:

答案 0 :(得分:6)

假设我们正在处理大表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
  4. 因此,一次性效应随着时间的推移而恶化。 特定问题是硬编码条件:

    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,具体取决于您从表中实际检索到的内容。