Postgresql 自动真空后的索引大小

Postgresql 自动真空后的索引大小,postgresql,reindex,vacuum,Postgresql,Reindex,Vacuum,你好。我正在阅读博士后关于真空处理和重新索引程序的官方文件。有些句子对我来说不清楚,所以我想澄清一下。第12版Postgres文档 首先。我知道autovacuum会检查表中的死元组,将它们的位置存储在名为maintenance_work_mem的特殊内存中,然后在内存已满时,真空删除所有索引中引用这些位置的对应页面。关于reindex的文档 完全为空的B树索引页将被回收用于 重复使用。然而,仍有可能存在使用效率低下的问题 空格:如果一个页面上除了几个索引键以外的所有索引键都已删除,则 页面仍被

你好。我正在阅读博士后关于真空处理和重新索引程序的官方文件。有些句子对我来说不清楚,所以我想澄清一下。第12版Postgres文档

首先。我知道autovacuum会检查表中的死元组,将它们的位置存储在名为maintenance_work_mem的特殊内存中,然后在内存已满时,真空删除所有索引中引用这些位置的对应页面。关于reindex的文档

完全为空的B树索引页将被回收用于 重复使用。然而,仍有可能存在使用效率低下的问题 空格:如果一个页面上除了几个索引键以外的所有索引键都已删除,则 页面仍被分配


问题是。如果页面保持已分配状态,是否意味着autovacuum不会将索引中已删除页面的物理空间返回操作系统?例如,索引占用1GB内存。我从表中删除了除一行以外的所有行,然后运行真空吸尘器。在这种情况下,索引仍将占用1GB内存。我说得对吗?

真空是,真空满时否:

select version();
                                                 version                                                 
---------------------------------------------------------------------------------------------------------
 PostgreSQL 12.3 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39), 64-bit
(1 row)

create table t(s text);
CREATE TABLE

insert into t select generate_series(1,300000)::text;
INSERT 0 300000

select pg_size_pretty(pg_table_size('t'));
 pg_size_pretty 
----------------
 10 MB
(1 row)

create index on t(s);
CREATE INDEX

select pg_size_pretty(pg_indexes_size('t'));
 pg_size_pretty 
----------------
 6600 kB
(1 row)

delete from t where s <> '1';
DELETE 299999

select count(*) from t;
 count 
-------
     1
(1 row)

select pg_size_pretty(pg_table_size('t'));
 pg_size_pretty 
----------------
 10 MB
(1 row)

select pg_size_pretty(pg_indexes_size('t'));
 pg_size_pretty 
----------------
 6600 kB
(1 row)

vacuum t;
VACUUM
select pg_size_pretty(pg_table_size('t'));
 pg_size_pretty 
----------------
 48 kB
(1 row)

select pg_size_pretty(pg_indexes_size('t'));
 pg_size_pretty 
----------------
 6600 kB
(1 row)

vacuum full t;
VACUUM
select pg_size_pretty(pg_table_size('t'));
 pg_size_pretty 
----------------
 16 kB
(1 row)

select pg_size_pretty(pg_indexes_size('t'));
 pg_size_pretty 
----------------
 16 kB
(1 row)
REINDEX没有:

select version();
                                                 version                                                 
---------------------------------------------------------------------------------------------------------
 PostgreSQL 12.3 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39), 64-bit
(1 row)

create table t(s text);
CREATE TABLE

insert into t select generate_series(1,300000)::text;
INSERT 0 300000

select pg_size_pretty(pg_table_size('t'));
 pg_size_pretty 
----------------
 10 MB
(1 row)

create index on t(s);
CREATE INDEX

select pg_size_pretty(pg_indexes_size('t'));
 pg_size_pretty 
----------------
 6600 kB
(1 row)

delete from t where s <> '1';
DELETE 299999

select count(*) from t;
 count 
-------
     1
(1 row)

select pg_size_pretty(pg_table_size('t'));
 pg_size_pretty 
----------------
 10 MB
(1 row)

select pg_size_pretty(pg_indexes_size('t'));
 pg_size_pretty 
----------------
 6600 kB
(1 row)

reindex table t;
REINDEX

select pg_size_pretty(pg_table_size('t'));
 pg_size_pretty 
----------------
 10 MB
(1 row)

select pg_size_pretty(pg_indexes_size('t'));
 pg_size_pretty 
----------------
 16 kB
(1 row)

真空时为是,真空满时为否:

select version();
                                                 version                                                 
---------------------------------------------------------------------------------------------------------
 PostgreSQL 12.3 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39), 64-bit
(1 row)

create table t(s text);
CREATE TABLE

insert into t select generate_series(1,300000)::text;
INSERT 0 300000

select pg_size_pretty(pg_table_size('t'));
 pg_size_pretty 
----------------
 10 MB
(1 row)

create index on t(s);
CREATE INDEX

select pg_size_pretty(pg_indexes_size('t'));
 pg_size_pretty 
----------------
 6600 kB
(1 row)

delete from t where s <> '1';
DELETE 299999

select count(*) from t;
 count 
-------
     1
(1 row)

select pg_size_pretty(pg_table_size('t'));
 pg_size_pretty 
----------------
 10 MB
(1 row)

select pg_size_pretty(pg_indexes_size('t'));
 pg_size_pretty 
----------------
 6600 kB
(1 row)

vacuum t;
VACUUM
select pg_size_pretty(pg_table_size('t'));
 pg_size_pretty 
----------------
 48 kB
(1 row)

select pg_size_pretty(pg_indexes_size('t'));
 pg_size_pretty 
----------------
 6600 kB
(1 row)

vacuum full t;
VACUUM
select pg_size_pretty(pg_table_size('t'));
 pg_size_pretty 
----------------
 16 kB
(1 row)

select pg_size_pretty(pg_indexes_size('t'));
 pg_size_pretty 
----------------
 16 kB
(1 row)
REINDEX没有:

select version();
                                                 version                                                 
---------------------------------------------------------------------------------------------------------
 PostgreSQL 12.3 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39), 64-bit
(1 row)

create table t(s text);
CREATE TABLE

insert into t select generate_series(1,300000)::text;
INSERT 0 300000

select pg_size_pretty(pg_table_size('t'));
 pg_size_pretty 
----------------
 10 MB
(1 row)

create index on t(s);
CREATE INDEX

select pg_size_pretty(pg_indexes_size('t'));
 pg_size_pretty 
----------------
 6600 kB
(1 row)

delete from t where s <> '1';
DELETE 299999

select count(*) from t;
 count 
-------
     1
(1 row)

select pg_size_pretty(pg_table_size('t'));
 pg_size_pretty 
----------------
 10 MB
(1 row)

select pg_size_pretty(pg_indexes_size('t'));
 pg_size_pretty 
----------------
 6600 kB
(1 row)

reindex table t;
REINDEX

select pg_size_pretty(pg_table_size('t'));
 pg_size_pretty 
----------------
 10 MB
(1 row)

select pg_size_pretty(pg_indexes_size('t'));
 pg_size_pretty 
----------------
 16 kB
(1 row)
src/backend/access/nbtree中的自述文件对此有很多深入的信息。这个答案中的引语来自那里

如果确实删除了表中除一行以外的所有行,则索引中的几乎所有页面都将被删除

<>我们考虑只从BTALL中删除整个页面,直到它变成 完全没有物品。合并部分完整的页面将允许更好的 空间重用,但将现有数据项向左或向右移动似乎不切实际 这样做是正确的——扫描方向相反 如果是这样,可能会错过这些项目。而且,我们从不删除最右边的页面 在树级别上,此限制简化了遍历算法,如下所示: 解释如下。页面删除总是从空页开始。一 内部页面只能作为删除整个子树的一部分删除。 这始终是一个由内部页面链组成的瘦子树 加上一页。子树的每一层上都有一页, 并且每个级别/页面覆盖相同的键空间

空间不会释放到操作系统,但是:

回收页面实际上并不会改变它在磁盘上的状态,我们只是简单地说 将其记录在共享内存可用空间映射中,并从中删除 下一次拆分页面需要新页面时分发

树将变得“瘦”,因为索引的深度永远不会缩小。PostgreSQL对此进行了优化:

因为我们从不删除任何级别最右边的页面,尤其是 永远不要删除根,树的高度是不可能删除的 减少在大量删除之后,我们可能会出现这样一种情况: 树很瘦,根下面有几个单页级别。 在这种情况下,操作仍然是正确的,但我们会浪费周期 在单页级别中递减。为了解决这个问题,我们使用了一个想法 来自Lanin和Shasha:我们跟踪快速根级别,即 最低的单页级别。元数据页面保留指向此的指针 级别以及真正的根。所有普通操作都会启动它们的 在快速根处搜索,而不是在真实根处搜索

如果在索引上运行REINDEX INDEX或清空整个表,索引将被重建,空间将被释放。

src/backend/access/nbtree中的自述文件有很多关于这方面的深入信息。这个答案中的引语来自那里

如果确实删除了表中除一行以外的所有行,则索引中的几乎所有页面都将被删除

<>我们考虑只从BTALL中删除整个页面,直到它变成 完全没有物品。合并部分完整的页面将允许更好的 空间重用,但将现有数据项向左或向右移动似乎不切实际 这样做是正确的——扫描方向相反 如果是这样,可能会错过这些项目。而且,我们从不删除最右边的页面 在树级别上,此限制简化了遍历算法,如下所示: 解释如下。页面删除总是从空页开始。一 内部页面只能作为删除整个子树的一部分删除。 这始终是一个由内部页面链组成的瘦子树 加上一页。子树的每一层上都有一页, 并且每个级别/页面覆盖相同的键空间

空间不会释放到操作系统,但是:

回收页面实际上并不会改变它在磁盘上的状态,我们只是简单地说 将其记录在共享内存可用空间映射中,并从中删除 下一次拆分页面需要新页面时分发

树将变得“瘦”,因为索引的深度永远不会缩小。PostgreSQL对此进行了优化:

因为我们从不删除任何级别最右边的页面,尤其是 永远不要删除根,它是impo 这棵树的高度可以 减少在大量删除之后,我们可能会出现这样一种情况: 树很瘦,根下面有几个单页级别。 在这种情况下,操作仍然是正确的,但我们会浪费周期 在单页级别中递减。为了解决这个问题,我们使用了一个想法 来自Lanin和Shasha:我们跟踪快速根级别,即 最低的单页级别。元数据页面保留指向此的指针 级别以及真正的根。所有普通操作都会启动它们的 在快速根处搜索,而不是在真实根处搜索


如果在索引上运行REINDEX INDEX或清空表,索引将被重建,空间将被释放。

感谢您的响应。我想知道为什么我的表中的索引如此之大,即使在吸尘器清理之后也感谢您的回复。我想知道为什么我的表中的索引即使在吸尘之后也会这么大