Как вы находите количество строк для всех ваших таблиц в Postgres - PullRequest
339 голосов
/ 08 апреля 2010

Я ищу способ найти количество строк для всех моих таблиц в Postgres.Я знаю, что могу сделать эту таблицу по одному с:

SELECT count(*) FROM table_name;

, но я хотел бы увидеть количество строк для всех таблиц, а затем упорядочить их, чтобы понять, насколько велики все моиТаблицы.

Ответы [ 12 ]

495 голосов
/ 10 апреля 2010

Существует три способа подсчета такого типа, каждый со своим собственным компромиссом.

Если вам нужен истинный счетчик, вы должны выполнить инструкцию SELECT, подобную той, которую вы использовали для каждой таблицы. Это связано с тем, что PostgreSQL хранит информацию о видимости строк в самой строке, а не где-либо еще, поэтому любой точный счет может быть только относительно некоторой транзакции. Вы получаете счет того, что видит эта транзакция в тот момент, когда она выполняется. Вы можете автоматизировать это для запуска каждой таблицы в базе данных, но вам, вероятно, не нужен такой уровень точности или вы хотите ждать так долго.

Второй подход отмечает, что сборщик статистики отслеживает, сколько строк «живое» (не удалено или не устарело в результате последующих обновлений) в любое время. Это значение может быть немного занижено при высокой активности, но обычно это хорошая оценка:

SELECT schemaname,relname,n_live_tup 
  FROM pg_stat_user_tables 
  ORDER BY n_live_tup DESC;

Это также может показать количество мертвых строк, что само по себе является интересным числом для отслеживания.

Третий способ - отметить, что системная команда ANALYZE, которая регулярно выполняется процессом автовакуума с PostgreSQL 8.3 для обновления статистики таблицы, также вычисляет оценку строки. Вы можете взять его так:

SELECT 
  nspname AS schemaname,relname,reltuples
FROM pg_class C
LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
WHERE 
  nspname NOT IN ('pg_catalog', 'information_schema') AND
  relkind='r' 
ORDER BY reltuples DESC;

Трудно сказать, какой из этих запросов лучше использовать. Обычно я принимаю это решение, основываясь на том, есть ли еще полезная информация, которую я также хочу использовать внутри pg_class или внутри pg_stat_user_tables. Для базовых целей подсчета, просто чтобы увидеть, насколько большие вещи в общем, либо должны быть достаточно точными.

39 голосов
/ 31 июля 2016

Вот решение, которое не требует функций для получения точного подсчета для каждой таблицы:

select table_schema, 
       table_name, 
       (xpath('/row/cnt/text()', xml_count))[1]::text::int as row_count
from (
  select table_name, table_schema, 
         query_to_xml(format('select count(*) as cnt from %I.%I', table_schema, table_name), false, true, '') as xml_count
  from information_schema.tables
  where table_schema = 'public' --<< change here for the schema you want
) t

query_to_xml запустит переданный SQL-запрос и вернет XML с результатом (количество строк для этой таблицы). Внешний xpath() затем извлечет информацию о количестве из этого xml и преобразует ее в число

Производная таблица на самом деле не нужна, но немного облегчает понимание xpath(), иначе весь query_to_xml() должен быть передан функции xpath().

21 голосов
/ 25 февраля 2015

Чтобы получить оценки, см. Ответ Грега Смита .

Чтобы получить точные значения, другие ответы пока сталкиваются с некоторыми проблемами, некоторые из которых являются серьезными (см. Ниже).Вот версия, которая, надеюсь, лучше:

CREATE FUNCTION rowcount_all(schema_name text default 'public')
  RETURNS table(table_name text, cnt bigint) as
$$
declare
 table_name text;
begin
  for table_name 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
    RETURN QUERY EXECUTE format('select cast(%L as text),count(*) from %I.%I',
       table_name, schema_name, table_name);
  END LOOP;
end
$$ language plpgsql;

В качестве параметра принимается имя схемы или public, если параметр не указан.

Для работы с конкретным списком схем илиСписок, поступающий из запроса без изменения функции, может вызываться из запроса, подобного следующему:

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

Это приводит к выводу из трех столбцов со схемой, таблицей и количеством строк.

Теперь в других ответах, которые эта функция избегает, есть некоторые проблемы:

  • Имена таблиц и схем не должны вставляться в исполняемый SQL без кавычек, либо с quote_ident или с более современной функцией format() со строкой формата %I.В противном случае злоумышленник может назвать свою таблицу tablename;DROP TABLE other_table, которая совершенно допустима как имя таблицы.

  • Даже без проблем с внедрением SQL и забавными символами, имя таблицы может существовать в вариантах, отличающихсядело.Если таблица называется ABCD, а другая - abcd, SELECT count(*) FROM... должен использовать имя в кавычках, в противном случае он пропустит ABCD и будет считать abcd дважды.Формат %I делает это автоматически.

  • information_schema.tables перечисляет пользовательские составные типы в дополнение к таблицам, даже если table_type равен 'BASE TABLE' (!).Как следствие, мы не можем перебрать information_schema.tables, в противном случае мы рискуем получить select count(*) from name_of_composite_type, и это не получится.OTOH pg_class where relkind='r' всегда должен работать нормально.

  • Тип COUNT (): bigint, а не int.Могут существовать таблицы с более чем 2,15 миллиардами строк (хотя подсчет (*) для них - плохая идея).

  • Не требуется создавать постоянный тип для функциивернуть набор результатов с несколькими столбцами.RETURNS TABLE(definition...) - лучшая альтернатива.

16 голосов
/ 08 апреля 2010

Если вы не возражаете против потенциально устаревших данных, вы можете получить доступ к той же статистике, которая используется оптимизатором запросов .

Что-то вроде:

SELECT relname, n_tup_ins - n_tup_del as rowcount FROM pg_stat_all_tables;
13 голосов
/ 31 июля 2016

Хакерский, практичный ответ для людей, пытающихся оценить, какой план Heroku им нужен, и не может дождаться обновления счетчика медленных рядов heroku:

В основном вы хотите запустить \dt в psql,скопируйте результаты в ваш любимый текстовый редактор (он будет выглядеть так:

 public | auth_group                     | table | axrsosvelhutvw
 public | auth_group_permissions         | table | axrsosvelhutvw
 public | auth_permission                | table | axrsosvelhutvw
 public | auth_user                      | table | axrsosvelhutvw
 public | auth_user_groups               | table | axrsosvelhutvw
 public | auth_user_user_permissions     | table | axrsosvelhutvw
 public | background_task                | table | axrsosvelhutvw
 public | django_admin_log               | table | axrsosvelhutvw
 public | django_content_type            | table | axrsosvelhutvw
 public | django_migrations              | table | axrsosvelhutvw
 public | django_session                 | table | axrsosvelhutvw
 public | exercises_assignment           | table | axrsosvelhutvw

), затем запустите поиск по регулярному выражению и замените его следующим образом:

^[^|]*\|\s+([^|]*?)\s+\| table \|.*$

на:

select '\1', count(*) from \1 union/g

, что даст вам нечто очень похожее на это:

select 'auth_group', count(*) from auth_group union
select 'auth_group_permissions', count(*) from auth_group_permissions union
select 'auth_permission', count(*) from auth_permission union
select 'auth_user', count(*) from auth_user union
select 'auth_user_groups', count(*) from auth_user_groups union
select 'auth_user_user_permissions', count(*) from auth_user_user_permissions union
select 'background_task', count(*) from background_task union
select 'django_admin_log', count(*) from django_admin_log union
select 'django_content_type', count(*) from django_content_type union
select 'django_migrations', count(*) from django_migrations union
select 'django_session', count(*) from django_session
;

(вам нужно удалить последний union и добавить точку с запятой в конце вручную)

Запустите его на psql и все готово.

            ?column?            | count
--------------------------------+-------
 auth_group_permissions         |     0
 auth_user_user_permissions     |     0
 django_session                 |  1306
 django_content_type            |    17
 auth_user_groups               |   162
 django_admin_log               |  9106
 django_migrations              |    19
[..]
11 голосов
/ 20 апреля 2011

Не уверен, что ответ в bash приемлем для вас, но FWIW ...

PGCOMMAND=" psql -h localhost -U fred -d mydb -At -c \"
            SELECT   table_name
            FROM     information_schema.tables
            WHERE    table_type='BASE TABLE'
            AND      table_schema='public'
            \""
TABLENAMES=$(export PGPASSWORD=test; eval "$PGCOMMAND")

for TABLENAME in $TABLENAMES; do
    PGCOMMAND=" psql -h localhost -U fred -d mydb -At -c \"
                SELECT   '$TABLENAME',
                         count(*) 
                FROM     $TABLENAME
                \""
    eval "$PGCOMMAND"
done
7 голосов
/ 14 ноября 2013

Я обычно не полагаюсь на статистику, особенно в PostgreSQL.

SELECT table_name, dsql2('select count(*) from '||table_name) as rownum
FROM information_schema.tables
WHERE table_type='BASE TABLE'
    AND table_schema='livescreen'
ORDER BY 2 DESC;
CREATE OR REPLACE FUNCTION dsql2(i_text text)
  RETURNS int AS
$BODY$
Declare
  v_val int;
BEGIN
  execute i_text into v_val;
  return v_val;
END; 
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
6 голосов
/ 15 апреля 2010

Я не помню URL, откуда я это забрал. Но надеюсь, это поможет вам:

CREATE TYPE table_count AS (table_name TEXT, num_rows INTEGER); 

CREATE OR REPLACE FUNCTION count_em_all () RETURNS SETOF table_count  AS '
DECLARE 
    the_count RECORD; 
    t_name RECORD; 
    r table_count%ROWTYPE; 

BEGIN
    FOR t_name IN 
        SELECT 
            c.relname
        FROM
            pg_catalog.pg_class c LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
        WHERE 
            c.relkind = ''r''
            AND n.nspname = ''public'' 
        ORDER BY 1 
        LOOP
            FOR the_count IN EXECUTE ''SELECT COUNT(*) AS "count" FROM '' || t_name.relname 
            LOOP 
            END LOOP; 

            r.table_name := t_name.relname; 
            r.num_rows := the_count.count; 
            RETURN NEXT r; 
        END LOOP; 
        RETURN; 
END;
' LANGUAGE plpgsql; 

Выполнение select count_em_all(); должно дать вам количество строк всех ваших таблиц.

5 голосов
/ 20 ноября 2014

Я сделал небольшой вариант, чтобы включить все таблицы, в том числе и для непубличных таблиц.

CREATE TYPE table_count AS (table_schema TEXT,table_name TEXT, num_rows INTEGER); 

CREATE OR REPLACE FUNCTION count_em_all () RETURNS SETOF table_count  AS '
DECLARE 
    the_count RECORD; 
    t_name RECORD; 
    r table_count%ROWTYPE; 

BEGIN
    FOR t_name IN 
        SELECT table_schema,table_name
        FROM information_schema.tables
        where table_schema !=''pg_catalog''
          and table_schema !=''information_schema''
        ORDER BY 1,2
        LOOP
            FOR the_count IN EXECUTE ''SELECT COUNT(*) AS "count" FROM '' || t_name.table_schema||''.''||t_name.table_name
            LOOP 
            END LOOP; 

            r.table_schema := t_name.table_schema;
            r.table_name := t_name.table_name; 
            r.num_rows := the_count.count; 
            RETURN NEXT r; 
        END LOOP; 
        RETURN; 
END;
' LANGUAGE plpgsql; 

используйте select count_em_all(); для вызова.

Надеюсь, вы найдете это полезным. Пол

4 голосов
/ 25 мая 2018

Простые два шага:(Примечание: не нужно ничего менять - просто скопируйте и вставьте) 1.функция создания

create function 
cnt_rows(schema text, tablename text) returns integer
as
$body$
declare
  result integer;
  query varchar;
begin
  query := 'SELECT count(1) FROM ' || schema || '.' || tablename;
  execute query into result;
  return result;
end;
$body$
language plpgsql;

2.Запустите этот запрос, чтобы получить количество строк для всех таблиц

select sum(cnt_rows) as total_no_of_rows from (select 
  cnt_rows(table_schema, table_name)
from information_schema.tables
where 
  table_schema not in ('pg_catalog', 'information_schema') 
  and table_type='BASE TABLE') as subq;

или Чтобы получить количество строк в табличном виде

select
  table_schema,
  table_name, 
  cnt_rows(table_schema, table_name)
from information_schema.tables
where 
  table_schema not in ('pg_catalog', 'information_schema') 
  and table_type='BASE TABLE'
order by 3 desc;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...