具有最新时间戳的行

Bas*_*que 2 postgresql performance index index-tuning query-performance

如何获取列中具有最新值的TIMESTAMPZ行?是否需要索引?指数会改变策略吗?行为会因数据库而异吗(我使用的是 Postgres 9.4)?

我的应用程序记录来自数据馈送的数据。另一个过程无休止地查询以获取最新的最新条目。较旧的数据有时可能来自二手资料。所以最近插入的行通常但不一定是最新的数据。

我正在使用这种 SQL where when_is a TIMESTAMP WITH TIME ZONEcolumn:

SELECT *
FROM my_table_ 
ORDER BY when_ DESC
LIMIT 1
;
Run Code Online (Sandbox Code Playgroud)

此代码有效(如果数据中没有 NULL 值!)。但是可能有几百万行,并且每 10 秒查询一次,我很担心性能。

when_列上没有任何索引,此语句是否需要对所有行进行全面扫描?

添加索引会改变性能吗?Postgres 会自动扫描索引以定位最近的行,还是我必须做些什么才能进行索引扫描?

使用when_列上的索引,我是否应该更改此 SQL 以使用其他一些查询方法/策略?

有没有其他方法来收集新插入的行?我的主键使用UUID而不是SERIAL 类型,并且可能会在多个数据库实例之间联合数据,因此排除了检查不断增加的整数的可能性。

Erw*_*ter 5

基本答案

由于您选择了几个大列,因此仅索引扫描可能不是一个可行的选择。

此代码有效(如果数据中没有 NULL 值!)

虽然未定义列NOT NULL,但添加NULLS LAST到排序顺序以使其在任何情况下都能工作,即使是NULL值也是如此。理想情况下,在相应的索引中也使用该子句:

SELECT <some big columns>
FROM   my_table_ 
ORDER  BY when_ DESC NULLS LAST
LIMIT  1;
Run Code Online (Sandbox Code Playgroud)

when_列上没有任何索引,此语句是否需要对所有行进行全面扫描?

是的。没有索引,就没有其他选择了。(嗯,还有表分区,其中键列上的索引不是严格要求的,它可以帮助分区修剪。但您通常也会在那里的键列上有一个索引。)

使用when_列上的索引,我是否应该更改此 SQL 以使用其他一些查询方法/策略?

基本上,这是一个完美的查询。有与高级索引结合使用的选项:


先进技术

假设一NOT NULL列。否则,NULLS LAST按照上面的建议添加到索引和查询。

您有大量的行与 later when_。假设最新的_when 不断增加并且从不(或很少)减少(删除/更新最新的行),您可以使用非常小的部分索引

基本实现

  1. 运行一次查询以检索 latest when_减去安全边距(以防止丢失最新行)并IMMUTABLE基于它创建一个函数。基本上是一个“假全局常量”:

    CREATE OR REPLACE FUNCTION f_when_cutoff()
      RETURNS timestamptz LANGUAGE sql COST 1 IMMUTABLE PARALLEL SAFE AS
    $$SELECT timestamptz '2015-07-25 01:00+02'$$;
    Run Code Online (Sandbox Code Playgroud)

    PARALLEL SAFE 仅在 Postgres 9.6 或更高版本中。

  2. 创建不包括旧行的部分索引:

    CREATE INDEX my_table_when_idx ON my_table_ (when_ DESC)
    WHERE when_ > f_when_cutoff();
    Run Code Online (Sandbox Code Playgroud)

    对于数百万行,大小差异可能非常大。这只对更小的索引才有意义。只是一半大小或其他东西不会削减它。索引访问本身不会因更大的索引而减慢太多。它主要是索引的绝对大小,需要读取和缓存。(并且可能避免额外的索引写入,但在您的情况下几乎没有。)

  3. 在所有相关查询中使用该函数。包括相同的WHERE条件(即使在逻辑上是冗余的)以说服查询规划器索引是适用的。对于简单查询:

    SELECT <some big columns>
    FROM   my_table_ 
    WHERE  when_ > f_when_cutoff()
    ORDER  BY when_ DESC
    LIMIT  1;
    Run Code Online (Sandbox Code Playgroud)

索引的大小随着新的(稍后的)条目而增长。使用较晚的时间戳重新创建函数,并且REINDEX不时地重新创建没有或很少并发访问的函数。仅在添加相关行数后重新索引。几千个条目并不重要。我们这样做是为了减少数百万人的生活
它的美妙之处在于:查询不会改变

具有自动更新部分索引的功能的实现:

更一般的建议: