Sah*_*sci 3 postgresql index index-tuning postgresql-performance
假设我有一个表,其描述如下:
create table my_table (
id serial,
create_date timestamp with time zone default now(),
data text
);
Run Code Online (Sandbox Code Playgroud)
和这样的查询:
select * from my_table
where create_date >= timestamp with time zone 'yesterday'
Run Code Online (Sandbox Code Playgroud)
理论上哪个索引会更快,为什么?
create index index_a on my_table (create_date);
create index index_b on my_table (create_date DESC);
Run Code Online (Sandbox Code Playgroud)
我不喜欢名称为“create_date”的列,该列实际上不是 adate而是timestamptz. 使用“created_at”代替。
由于created_at可以NULL,所以第三个变体会更快(即使不是很多):
CREATE INDEX index_c ON my_table (created_at DESC NULLS LAST);
Run Code Online (Sandbox Code Playgroud)
NULL默认情况下,值在最大值之后排序。DESCENDING排序顺序是完美的倒置,因此NULL值排在第一位。看:
Postgres 可以以几乎相同的速度向后扫描 B 树索引,因此您的两个变体几乎是相同的。但该运算符>=排除了NULL值(与大多数运算符一样)。因此 Postgres 必须NULL首先分别跳过前导/尾随值。通常不贵,但仍然如此。
DESC NULLS LAST带(或)的索引NULLS FIRST首先具有最大值,NULL最后具有值(反之亦然),因此查询可以直接从索引的顶部(底部)开始读取。
如果没有NULL值,就不会有明显的差异。并且您应该声明该列NOT NULL。(你应该这么说。)
如果插入带有严格升序的时间戳(并且没有更新!) - 或者如果对于自“昨天”以来最近插入的行至少是这样,(相关)行会自动按时间戳进行物理集群。否则,有时需要对行进行物理集群。(同时不会干扰数据库上的并发负载!)这可以产生更大的差异,因为它将必须读取的数据页数量保持在最低限度。看:
如果你的表很大,部分索引可以支付:
CREATE INDEX index_c_partial ON my_table (created_at DESC NULLS LAST)
WHERE created_at >= '2021-06-26 0:0'; -- recent but before yesterday
Run Code Online (Sandbox Code Playgroud)
它会切断大部分旧行,以便索引的大小缩小到一小部分。
但由于您的截止 ( 'yesterday') 是一个移动目标,您必须不时重新创建该索引以删除旧元组,否则好处会随着时间的推移而恶化。比如,每天、每周、每月——你决定。
使用热缓存,部分索引不会比完整索引快很多,但由于它小得多,因此保留在缓存中的机会相应更大(取决于您的完整设置),这通常会产生很大的差异。(而且它一开始就不会占用那么多资源。)
由于我们现在有一个很小的索引,而且我们只处理这么少的列(或者您实际上不需要从头SELECT *开始?!),我们不妨将其设为覆盖索引(Postgres 11 或更高版本):
CREATE INDEX index_c_partial_covering ON my_table
(created_at DESC NULLS LAST) INCLUDE (id, data)
WHERE created_at >= '2021-06-26 0:0';
Run Code Online (Sandbox Code Playgroud)
同样,细节取决于整体情况。有关的:
如果满足一些先决条件,您现在可以获得更便宜的仅索引扫描。在这种情况下,表中行的物理顺序并不重要。
哦,将该timestamptz列移动到表定义中的不同位置。现在的方式由于对齐填充而最大化了膨胀。该列的任何其他位置都timestamptz更好。喜欢:
CREATE TABLE my_table (
, created_at timestamptz DEFAULT now() NOT NULL
, id serial NOT NULL PRIMARY KEY
, data text
);
Run Code Online (Sandbox Code Playgroud)
看:
| 归档时间: |
|
| 查看次数: |
2899 次 |
| 最近记录: |