NikolayS / postgres_dba

The missing set of useful tools for Postgres DBAs and all engineers
BSD 3-Clause "New" or "Revised" License
1.03k stars 113 forks source link

New report: check int2 and int4 PK columns to be out-of-capacity soon #27

Closed NikolayS closed 4 years ago

NikolayS commented 6 years ago

Report name: c1_integer_pk_columns_check

Idea: check int4 PKs to be out-of-capacity in the nearest future (is max value is approaching 2^31 soon?). The same for int2 PKs (limit: 2^15).

Advanced idea: if created or created_at column is present in the table, forecast reaching the limit.

The goal of this report: warn about approaching int4/int2 limits, propose using int8/in4 instead.

NikolayS commented 6 years ago

The very 1st draft (requires plpgsql, now works checks only int4 PKs):

do $$
declare
  rec record;
  out text;
  val int8;
  ratio numeric;
begin
  out := '';
  for rec in 
    select 
      c.oid,
      (select spcname from pg_tablespace where oid = reltablespace) as tblspace,
      nspname as schema_name,
      relname as table_name,
      t.typname,
      attname
    from pg_index i
    join pg_class c on c.oid = i.indrelid
    left join pg_namespace n on n.oid = c.relnamespace
    join pg_attribute a on
      a.attrelid = i.indrelid
      and a.attnum = any(i.indkey)
    join pg_type t on t.oid = atttypid 
    where
      i.indisprimary
      and t.typname in ('int2', 'int4')
      and nspname <> 'pg_toast'
  loop
    execute format('select max(%I) from %I.%I;', rec.attname, rec.schema_name, rec.table_name) into val;
    if rec.typname = 'int4' then
      ratio := (val::numeric / 2^31)::numeric;
    elsif rec.typname = 'int2' then
      ratio := (val::numeric / 2^15)::numeric;
    else
      assert false, 'unreachable point';
    end if;
    if ratio > 0.01 then -- report only if > 1% of capacity is reached
      out := out || format(
        e'\nTable: %I.%I, column: %I, type: %s, reached value: %s (%s%%)',
        rec.schema_name,
        rec.table_name,
        rec.attname,
        rec.typname,
        val,
        round(100 * ratio, 2)
      );
    end if;
  end loop;
  raise info '%', out;
end;
$$ language plpgsql;
NikolayS commented 6 years ago

TODO:

NikolayS commented 6 years ago

Also to consider:

NikolayS commented 4 years ago

Implemented in https://gitlab.com/postgres-ai/postgres-checkup (report L003)