我正在尝试构建查询,使用pgstattuple扩展来检查所有用户表中的死元组,实时元组百分比,可用空间等。所以,我提出了这个问题:
SELECT schemaname,
relname,
(pgstattuple(schemaname ||'.'||relname)).*
FROM pg_statio_user_tables;
pg_statio_user_tables是一个pg_catalog视图,它使用另一个系统视图。所以乍一看这个查询看起来很简单,但最终在db中的882个对象的总执行时间为27分钟。
此查询的执行计划:
有没有办法使用pgstattuple重写查询,所以它会表现得体面?
答案 0 :(得分:2)
如果在子查询中运行该函数并且仅在下一级别分解生成的行类型,它会快得多:
SELECT s.schemaname, s.relname, st.*
FROM pg_statio_user_tables s
,pgstattuple(s.schemaname ||'.'|| s.relname) AS st;
(这是一个隐含的LATERAL JOIN
。在Postgres 9.3的版本中,使用子查询代替。)
这样,该函数仅在pg_statio_user_tables
中每行调用一次。不幸的是,你在Postgres查询规划器(解析器)中遇到了一个弱点。克雷格在这个相关答案中详细解释了:
如果pg_statio_user_tables
视图中只需要表格和模式名称,那么可以更快,但:
SELECT c.oid::regclass::text AS tbl, (st).*
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
,pgstattuple(c.oid::regclass::text) st
WHERE c.relkind = 'r' -- only tables
AND n.nspname NOT LIKE 'pg_%' -- exclude system schemas
ORDER BY 1;