Bas*_*que 2 postgresql performance index index-tuning query-performance
如何获取列中具有最新值的TIMESTAMPZ
行?是否需要索引?指数会改变策略吗?行为会因数据库而异吗(我使用的是 Postgres 9.4)?
我的应用程序记录来自数据馈送的数据。另一个过程无休止地查询以获取最新的最新条目。较旧的数据有时可能来自二手资料。所以最近插入的行通常但不一定是最新的数据。
我正在使用这种 SQL where when_
is a TIMESTAMP WITH TIME ZONE
column:
SELECT *
FROM my_table_
ORDER BY when_ DESC
LIMIT 1
;
Run Code Online (Sandbox Code Playgroud)
此代码有效(如果数据中没有 NULL 值!)。但是可能有几百万行,并且每 10 秒查询一次,我很担心性能。
when_
列上没有任何索引,此语句是否需要对所有行进行全面扫描?
添加索引会改变性能吗?Postgres 会自动扫描索引以定位最近的行,还是我必须做些什么才能进行索引扫描?
使用when_
列上的索引,我是否应该更改此 SQL 以使用其他一些查询方法/策略?
有没有其他方法来收集新插入的行?我的主键使用UUID而不是SERIAL 类型,并且可能会在多个数据库实例之间联合数据,因此排除了检查不断增加的整数的可能性。
由于您选择了几个大列,因此仅索引扫描可能不是一个可行的选择。
此代码有效(如果数据中没有 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
不断增加并且从不(或很少)减少(删除/更新最新的行),您可以使用非常小的部分索引。
基本实现:
运行一次查询以检索 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 或更高版本中。
创建不包括旧行的部分索引:
CREATE INDEX my_table_when_idx ON my_table_ (when_ DESC)
WHERE when_ > f_when_cutoff();
Run Code Online (Sandbox Code Playgroud)
对于数百万行,大小差异可能非常大。这只对更小的索引才有意义。只是一半大小或其他东西不会削减它。索引访问本身不会因更大的索引而减慢太多。它主要是索引的绝对大小,需要读取和缓存。(并且可能避免额外的索引写入,但在您的情况下几乎没有。)
在所有相关查询中使用该函数。包括相同的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
不时地重新创建没有或很少并发访问的函数。仅在添加相关行数后重新索引。几千个条目并不重要。我们这样做是为了减少数百万人的生活。
它的美妙之处在于:查询不会改变。
具有自动更新部分索引的功能的实现:
更一般的建议: