由于您没有指定索引类型,我将默认使用B树索引。其他类型可能会有很大的不同。
这里是一个简单的函数,用于计算给定表和给定列上的索引的估计最小字节数:
CREATE OR REPLACE FUNCTION f_index_minimum_size(_tbl regclass, _cols VARIADIC text[], OUT estimated_minimum_size bigint)
LANGUAGE plpgsql AS
$func$
DECLARE
_missing_column text;
BEGIN
SELECT i.attname
FROM unnest(_cols) AS i(attname)
LEFT JOIN pg_catalog.pg_attribute a ON a.attname = i.attname
AND a.attrelid = _tbl
WHERE a.attname IS NULL
INTO _missing_column;
IF FOUND THEN
RAISE EXCEPTION 'Table % has no column named %', _tbl, quote_ident(_missing_column);
END IF;
SELECT INTO estimated_minimum_size
COALESCE(1 + ceil(reltuples/trunc((blocksize-page_overhead)/(4+tuple_size)))::int, 0) * blocksize
FROM (
SELECT maxalign, blocksize, reltuples, fillfactor, page_overhead
, (maxalign
+ CASE WHEN datawidth <= maxalign THEN maxalign
WHEN datawidth%maxalign = 0 THEN datawidth
ELSE (datawidth + maxalign) - datawidth%maxalign END
) AS tuple_size
FROM (
SELECT c.reltuples, count(*)
, 90 AS fillfactor
, current_setting('block_size')::bigint AS blocksize
, CASE WHEN version() ~ '64-bit|x86_64|ppc64|ia64|amd64|mingw32'
THEN 8 ELSE 4 END AS maxalign
, 40 AS page_overhead
, sum(ceil((1-COALESCE(s.null_frac, 0)) * COALESCE(s.avg_width, 1024))::int) AS datawidth
FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid
JOIN pg_catalog.pg_stats s ON s.schemaname = c.relnamespace::regnamespace::text
AND s.tablename = c.relname
AND s.attname = a.attname
WHERE c.oid = _tbl
AND a.attname = ANY(_cols)
GROUP BY 1
) sub1
) sub2;
END
$func$;
调用示例:
SELECT f_index_minimum_size('my_table', 'col1', 'col2', 'col3');
SELECT f_index_minimum_size('public.my_table', VARIADIC '{col1, col2, col3}');
db<>fiddle 这里
关于 VARIADIC
参数:
基本上,所有索引都使用通常为8 kb块大小(很少为4 kb)的数据页。对于B树索引,有一个数据页开销。每个附加的数据页具有40字节的固定开销(目前)。每个页面都存储如手册
here所示的元组。每个元组都有元组头(通常包括8个字节的对齐填充)、可能是空位图、数据(可能包括多列索引之间的对齐填充)以及可能对齐到下一个
MAXALIGN
倍数(通常为8个字节)。此外,每个元组还有一个4个字节的
ItemId
。对于B树索引,默认情况下会预留一些空间以供稍后添加使用90%的
fillfactor
。
重要说明和免责声明
报告的大小是估计的最小大小。实际索引通常会因页面分裂而增加约25%的自然膨胀。此外,该计算不考虑多个列之间可能存在的对齐填充。在极端情况下,可以增加另外几个百分点或更多。请参见:
估计基于视图
pg_stats
中的列统计信息,该视图基于系统表
pg_statistics
。特别地,计算基于
null_frac
,即“空列条目的分数”和
avg_width
,即“列条目的平均宽度(以字节为单位)”,以计算平均数据宽度-忽略多列索引的可能的附加对齐填充。
默认考虑了 90% 的
fillfactor
。 (可以指定不同的值。)
B 树索引通常会自然膨胀50%,无需担心。
不适用于表达式索引。
不支持部分索引。
如果传递了除现有纯列名称之外的任何内容,则该函数将引发异常。区分大小写!
如果表是新表(或在任何情况下统计信息可能已过时),请务必在调用函数之前对表运行
ANALYZE
以更新(甚至启动!)统计信息。
由于主要优化,
Postgres 12中的B树索引浪费的空间更少,通常更接近报告的最小大小。
不考虑
去重,它是使用
Postgres 13引入的,可以压缩具有重复值的索引。
代码的部分内容取自ioguix的膨胀估算查询,链接在此处:
更多关于Postgres源代码的细节在这里: