我有一个表,其中包含两个包含大量文本的文本字段。出于某种原因,我们的桌子开始呈指数增长。我怀疑 TOAST(postgres 中文本字段的压缩)不能自动工作。在我们的表定义中,我们没有定义任何子句来强制压缩这些字段。有没有办法检查压缩是否对该表起作用?
4 回答
从文档。. .
如果表的任何列都支持 TOAST,则该表将具有关联的 TOAST 表,其 OID 存储在表的 pg_class.reltoastrelid 条目中。离线 TOAST 值保存在 TOAST 表中,如下文更详细描述。
所以可以通过查询pg_class 系统目录来判断 TOAST 表是否存在。这应该让你接近你正在寻找的东西。
select t1.oid, t1.relname, t1.relkind, t2.relkind, t2.relpages, t2.reltuples
from pg_class t1
inner join pg_class t2
on t1.reltoastrelid = t2.oid
where t1.relkind = 'r'
and t2.relkind = 't';
在 psql 中,您可以使用\d+
. 我将使用 pg_class 系统目录作为示例;你会使用你自己的表名。
sandbox=# \d+ pg_class
Column | Type | Modifiers | Storage | Stats target | Description
----------------+-----------+-----------+----------+--------------+-------------
relname | name | not null | plain | |
relnamespace | oid | not null | plain | |
[snip]
relacl | aclitem[] | | extended | |
reloptions | text[] | | extended | |
在 Storage 被“扩展”的情况下,PostgreSQL 将尝试通过首先压缩来减少行大小,然后通过存储数据外线。当 Storage 是“main”(未显示)时,PostgreSQL 将尝试压缩。
在您的特定情况下,您可能会发现监视大小随时间的变化很有用。您可以使用此查询,并保存结果以供以后分析。
select table_catalog, table_schema, table_name,
pg_total_relation_size(table_catalog || '.' || table_schema|| '.' || table_name) as pg_total_relation_size,
pg_relation_size(table_catalog || '.' || table_schema|| '.' || table_name) as pg_relation_size,
pg_table_size(table_catalog || '.' || table_schema|| '.' || table_name) as pg_table_size
from information_schema.tables
PostgreSQL 管理函数详细说明了每个函数在其计算中包含的内容。
您可以通过使用参数启动 psql 来查看运行的查询-E
,然后运行普通命令:
在这种情况下,归结为首先查找表的 oid:
SELECT c.oid,
n.nspname,
c.relname
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname ~ '^(YOUR_TABLE_NAME_HERE)$'
AND pg_catalog.pg_table_is_visible(c.oid)
ORDER BY 2, 3;
然后它执行这个来查找更多关于它的统计信息:
SELECT a.attname, pg_catalog.format_type(a.atttypid, a.atttypmod),
(SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)
FROM pg_catalog.pg_attrdef d
WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef),
a.attnotnull, a.attnum,
(SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type t
WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation) AS attcollation,
NULL AS indexdef,
NULL AS attfdwoptions,
a.attstorage,
CASE WHEN a.attstattarget=-1 THEN NULL ELSE a.attstattarget END AS attstattarget, pg_catalog.col_description(a.attrelid, a.attnum)
FROM pg_catalog.pg_attribute a
WHERE a.attrelid = '57692' AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum;
x.attrstorage 是您关心的p
是 PLAIN,x
是 EXTENDED 我敢打赌。
这是旧的,但我最近在类似的问题上取得了一些成功。ANALYZE VERBOSE 显示我们的一些表已经增长到每个元组超过 1 页磁盘,而 EXPLAIN ANALYZE 显示在 27K 行的表上顺序扫描最多需要 30 秒。对活动行数的估计越来越差。
经过大量搜索,我了解到只有在更新后没有打开的事务时才能清除行。该表每 3 分钟重写一次,并且有一个 3 天前的“空闲事务”连接。你可以算算。
在这种情况下,我们不得不
- 终止与打开事务的连接
- 重新连接到数据库。不幸的是,当前(从 9.3 开始)可以清理的行的最大事务 ID 存储在连接中,因此清理满的行将不起作用。
- VACUUUM FULL 您的表(这将取出一个 ACCESS EXCLUSIVE 锁,这将阻止包括读取在内的所有内容。您可能希望首先运行 VACUUM(非阻塞),以加快 VACUUM FULL 的时间)。
这可能不是您的问题,但是如果您想查看您自己的数据库中的表是否受到影响,我编写了一个查询来按存储在磁盘页面中的平均元组数对表进行排序。具有大行的表应该位于顶部 - ANALYZE VERBOSE 应该让您了解这些表中死元组与活元组的比率。 适用于 9.3 - 这可能需要对其他版本进行一些小的调整:
SELECT rolname AS owner,
nspname AS schemaname
, relname AS tablename
, relpages, reltuples, (reltuples::FLOAT / relpages::FLOAT) AS tuples_per_page
FROM pg_class
JOIN pg_namespace ON relnamespace = pg_namespace.oid
JOIN pg_roles ON relowner = pg_roles.oid
WHERE relkind = 'r' AND relpages > 20 AND reltuples > 1000
AND nspname != 'pg_catalog'
ORDER BY tuples_per_page;
如果清理 rhe 表将其从 80GB 剥离到 19GB,您可能会看到 MVCC 在工作:死行占用空间,直到清理或重新使用。