Подтвердить что ты не робот

Быстрый способ узнать количество строк таблицы в PostgreSQL

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

Я могу использовать SELECT count(*) FROM table. Но если мое постоянное значение составляет 500 000, и у меня есть 5 000 000 000 строк в моей таблице, подсчет всех строк будет тратить много времени.

Можно ли остановить подсчет, как только мое постоянное значение будет превзойдено?

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

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

SELECT text,count(*), percentual_calculus()  
FROM token  
GROUP BY text  
ORDER BY count DESC;
4b9b3361

Ответ 1

Подсчет строк в больших таблицах, как известно, медленный в PostgreSQL. Чтобы получить точный номер, он должен делать полное количество строк из-за природы MVCC. Существует способ ускорить это резко, если счетчик не должен быть точным, как кажется, в вашем случае. p >

Вместо получения точного счета ( медленный с большими таблицами):

SELECT count(*) AS exact_count FROM myschema.mytable;

Вы получите близкую оценку (чрезвычайно быстро):

SELECT reltuples::bigint AS estimate FROM pg_class where relname='mytable';

Насколько близко оценка зависит от того, достаточно ли вы выполняете ANALYZE. Это, как правило, очень близко. См. Часто задаваемые вопросы по вики PostgreSQL.
Или выделенная страница wiki для производительности счетчика (*).

Еще лучше

В статье в PostgreSQL Wiki есть была немного неаккуратная. Он игнорировал возможность того, что в одной базе данных может быть несколько таблиц с одинаковым именем - в разных схемах. Чтобы учесть это:

SELECT c.reltuples::bigint AS estimate
FROM   pg_class c
JOIN   pg_namespace n ON n.oid = c.relnamespace
WHERE  c.relname = 'mytable'
AND    n.nspname = 'myschema'

Или еще лучше

SELECT reltuples::bigint AS estimate
FROM   pg_class
WHERE  oid = 'myschema.mytable'::regclass;

Быстрее, проще, безопаснее, элегантнее. См. Руководство по Типы идентификаторов объектов.

Используйте to_regclass('myschema.mytable') в Postgres 9.4+, чтобы избежать исключений для неверных имен таблиц:


TABLESAMPLE SYSTEM (n) в Postgres 9.5 +

SELECT 100 * count(*) AS estimate FROM mytable TABLESAMPLE SYSTEM (1);

Как @a_horse прокомментировал, новое добавленное предложение для команды SELECT может быть полезно, если статистика в pg_class по какой-то причине не достаточно актуальна. Например:

  • Нет autovacuum работает.
  • Сразу после большого INSERT или DELETE.
  • TEMPORARY таблицы (которые не покрываются autovacuum).

Это показывает только случайный n% (1 в примере) выбор блоков и подсчет строк в нем. Более крупный образец увеличивает стоимость и уменьшает ошибку, ваш выбор. Точность зависит от большего количества факторов:

  • Распределение размера строки. Если данный блок находится более широко, чем обычные строки, счетчик ниже обычного и т.д.
  • Мертвые кортежи или FILLFACTOR занимают пространство за блок. Если неравномерно распределено по таблице, оценка может быть отключена.
  • Общие ошибки округления.

В большинстве случаев оценка от pg_class будет быстрее и точнее.

Ответ на фактический вопрос

Во-первых, мне нужно знать количество строк в этой таблице, если общее количество count больше некоторой предопределенной константы,

И будет ли это...

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

Да. Вы можете использовать подзапрос с LIMIT:

SELECT count(*) FROM (SELECT 1 FROM token LIMIT 500000) t;

Postgres фактически перестает считать выше заданного предела, вы получаете точное и текущее количество до n строк (500000 в примере) и n в противном случае. Однако не так быстро, как оценка в pg_class.

Ответ 2

Я сделал это один раз в приложении postgres, запустив:

EXPLAIN SELECT * FROM foo;

Затем рассмотрим вывод с помощью регулярного выражения или аналогичной логики. Для простого SELECT * первая строка вывода должна выглядеть примерно так:

Seq Scan on uids  (cost=0.00..1.21 rows=8 width=75)

Вы можете использовать значение rows=(\d+) в качестве приблизительной оценки количества строк, которые будут возвращены, тогда только фактический SELECT COUNT(*), если оценка, скажем, меньше 1,5x вашего порога (или любого другого номера вы считаете смысл для своего приложения).

В зависимости от сложности вашего запроса это число может становиться все менее и менее точным. Фактически, в моем приложении, когда мы добавляли объединения и сложные условия, он стал настолько неточным, что он был совершенно бесполезным, даже чтобы знать, как в пределах 100 столетий, сколько мы вернули бы, поэтому нам пришлось отказаться от этой стратегии.

Но если ваш запрос достаточно прост, что Pg может предсказать с некоторым разумным пределом ошибки, сколько строк оно вернется, оно может сработать для вас.

Ответ 3

В Oracle вы можете использовать rownum, чтобы ограничить количество возвращаемых строк. Я предполагаю, что подобная конструкция существует и в других SQL. Итак, в примере, который вы указали, вы можете ограничить количество строк, возвращаемых на 500001, и применить count(*), а затем:

SELECT (case when cnt > 500000 then 500000 else cnt end) myCnt
FROM (SELECT count(*) cnt FROM table WHERE rownum<=500001)

Ответ 4

Насколько широк текстовый столбец?

С GROUP BY не так много можно сделать, чтобы избежать сканирования данных (по крайней мере, сканирование индекса).

Я бы рекомендовал:

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

  • Альтернативно, создавая сгенерированный столбец с HASH текста, тогда GROUP BY hash column. Опять же, это уменьшение рабочей нагрузки (сканирование через узкий индекс столбца)

Изменить:

Ваш оригинальный вопрос не совсем соответствовал вашим изменениям. Я не уверен, знаете ли вы, что COUNT, когда используется с GROUP BY, вернет количество элементов для каждой группы, а не количество элементов во всей таблице.

Ответ 5

Для SQL Server (2005 или выше) быстрый и надежный метод:

SELECT SUM (row_count)
FROM sys.dm_db_partition_stats
WHERE object_id=OBJECT_ID('MyTableName')   
AND (index_id=0 or index_id=1);

Подробности о sys.dm_db_partition_stats объясняются в MSDN

Запрос добавляет строки из всех частей (возможно) разделенной таблицы.

index_id = 0 - неупорядоченная таблица (Heap), а index_id = 1 - упорядоченная таблица (кластерный индекс)

Более быстрые (но ненадежные) методы подробно описаны здесь.

Ответ 6

Ссылка, взятая из этого блога.

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

Использование pg_class:

 SELECT reltuples::bigint AS EstimatedCount
    FROM   pg_class
    WHERE  oid = 'public.TableName'::regclass;

Использование pg_stat_user_tables:

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