计算所有表中所有模式(已授予权限)中的行数

Count rows in all schemas (with permission granted) in all tables

我正在尝试计算数据库中所有 table 中的行数。由于我想得到的答案必须区分不同的模式,因此我还考虑了特定 table 所在的模式。

这个 answer 最有帮助,但事实证明我没有访问数据库中所有模式的权限。

我知道我可以通过执行以下查询来检查我对特定 table 或模式的权限:

select count(*) from (
SELECT grantee, privilege_type 
FROM information_schema.role_table_grants 
WHERE table_name='data' and privilege_type = 'SELECT') as foo

并检查输出是否等于或大于 1。

我现在的代码如下:

CREATE or replace function rowcount_all(schema_name text default 'public')
  RETURNS table(table_name_var text, cnt bigint) as
$$
declare
 table_name_var text;
begin
  for table_name_var in SELECT c.relname FROM pg_class c
    JOIN pg_namespace s ON (c.relnamespace=s.oid)
    WHERE c.relkind = 'r' AND s.nspname=schema_name
  loop
    if (
    select count(*) from (
    SELECT grantee, privilege_type 
    FROM information_schema.role_table_grants 
    WHERE table_name=table_name_var and privilege_type = 'SELECT') as foo
  ) >= 1 then 
    RETURN QUERY EXECUTE format('select cast(%L as text),count(*) from %I.%I',
       table_name_var, schema_name, table_name_var);
    end if;
  END loop;
end
$$ language plpgsql;

在执行以下查询时

WITH rc(schema_name,tbl) AS (
  select s.n,rowcount_all(s.n) from (values ('schema1'),
    ('schema2'), ('schema3'), ('schema4')) as s(n)
)
SELECT schema_name,(tbl).* FROM rc;

我收到一条错误消息,指出 ERROR: permission denied for relation table1 其中 table1 在我无权访问的架构中。我假设我在 IF 语句中的逻辑以某种方式不会过滤掉我无权访问的 tables。

information_schema,作为数据库元数据的 SQL 标准表示,如果您尝试为 table 构建某些东西,它很有用,但如果我只是想管理一个 Postgres 服务器。

检查权限最简单的方法是使用 privilege check functions。我相信这 return 只有 table 您可以查询的:

select oid::regclass::text
from pg_class
where relkind = 'r'
  and relnamespace = schema_name::regnamespace
  and has_schema_privilege(relnamespace, 'USAGE')
  and has_any_column_privilege(oid, 'SELECT')

请注意,您的情况是 has_any_column_privilege() 有用的少数情况之一(与更明显的 has_table_privilege() 相比),因为您不需要完整的 table 权限select count(*),只需访问其中一列(但哪一列并不重要)。

另请注意,oid::regclass::text 将 return 一个 table 名称,该名称已被引号和模式限定(如有必要),因此您的 format() 调用可以使用一个简单的 %s 而不是 %I.%I.

如果你能凑合使用一个近似的和稍微过时的记录计数,你可以通过查询来自最后 VACUUM 运行:

select
  oid::regclass::text,
  reltuples
from pg_class
where relkind = 'r'
  and relnamespace = schema_name::regnamespace