Мне нужно знать количество строк в таблице, чтобы рассчитать процент. Если общее количество больше некоторой предопределенной константы, я буду использовать постоянное значение. В противном случае я буду использовать фактическое количество строк.
Я могу использовать SELECT count(*) FROM table
. Но если мое постоянное значение составляет 500 000, а в моей таблице 5 000 000 000 строк, подсчет всех строк будет тратить много времени.
Можно ли прекратить считать, как только моя постоянная стоимость будет превышена?
Мне нужно точное количество строк, только если оно ниже заданного предела. В противном случае, если счетчик превышает предел, я использую вместо этого предельное значение и хочу получить ответ как можно быстрее.
Что-то вроде этого:
SELECT text,count(*), percentual_calculus()
FROM token
GROUP BY text
ORDER BY count DESC;
sql
postgresql
count
row
Ренато Динхани
источник
источник
Ответы:
Как известно, подсчет строк в больших таблицах в PostgreSQL выполняется медленно. Чтобы получить точное число, он должен выполнить полный подсчет строк из-за природы MVCC . Есть способ значительно ускорить это, если подсчет не должен быть точным, как в вашем случае.
Вместо точного подсчета ( медленно с большими таблицами):
Вы получите такую близкую оценку ( очень быстро ):
Насколько близка оценка, зависит от того,
ANALYZE
достаточно ли вы бегаете . Обычно это очень близко.См. FAQ по PostgreSQL Wiki .
Или специальная вики-страница для подсчета (*) производительности .
Еще лучше
В статье в PostgreSQL Wiki
этобыло немного неаккуратно . Он игнорировал возможность того, что в одной базе данных может быть несколько таблиц с одинаковым именем - в разных схемах. Чтобы учесть это:Или еще лучше
Быстрее, проще, безопаснее, элегантнее. См. Руководство по типам идентификаторов объектов .
Используйте
to_regclass('myschema.mytable')
в Postgres 9.4+, чтобы избежать исключений для недопустимых имен таблиц:TABLESAMPLE SYSTEM (n)
в Postgres 9.5+Как и прокомментировал @a_horse , недавно добавленное предложение для
SELECT
команды может быть полезно, если статистикаpg_class
по какой-то причине недостаточно актуальна. Например:autovacuum
бега.INSERT
илиDELETE
.TEMPORARY
таблицы (которые не покрываютсяautovacuum
).Это только смотрит на случайный выбор n % (
1
в примере) блоков и подсчитывает строки в нем. Более крупный образец увеличивает стоимость и уменьшает ошибку, ваш выбор. Точность зависит от большего количества факторов:FILLFACTOR
занимаемое пространство на блок. При неравномерном распределении по таблице оценка может быть неверной.В большинстве случаев оценка
pg_class
будет быстрее и точнее.Ответ на актуальный вопрос
И будь это ...
Да. Вы можете использовать подзапрос с
LIMIT
:Postgres фактически перестает считать сверх заданного лимита, вы получаете точное и текущее количество до n строк (500000 в примере) и n в противном случае. Однако не так быстро, как предполагалось
pg_class
.источник
tablesample
предложения: напримерselect count(*) * 100 as cnt from mytable tablesample system (1);
SELECT count(*) FROM (Select * from (SELECT 1 FROM token) query) LIMIT 500000) limited_query;
(Я спрашиваю, потому что пытаюсь получить счет из произвольного запроса, в котором уже может быть предельное предложение)ORDER BY something
while он не может использовать индекс или с агрегатными функциями). Кроме того, обрабатывается только ограниченное количество строк из подзапроса.Я сделал это однажды в приложении postgres, запустив:
Затем проверьте результат с помощью регулярного выражения или аналогичной логики. Для простого SELECT * первая строка вывода должна выглядеть примерно так:
Вы можете использовать это
rows=(\d+)
значение в качестве приблизительной оценки количества возвращаемых строк, а затем делать только фактические,SELECT COUNT(*)
если оценка, скажем, меньше, чем в 1,5 раза превышает ваш порог (или любое другое число, которое, по вашему мнению, имеет смысл для вашего приложения).В зависимости от сложности вашего запроса это число может становиться все менее точным. Фактически, в моем приложении, когда мы добавляли соединения и сложные условия, оно становилось настолько неточным, что было совершенно бесполезно даже знать, как с точностью до 100, сколько строк мы бы вернули, поэтому нам пришлось отказаться от этой стратегии.
Но если ваш запрос достаточно прост, чтобы Pg мог предсказать с некоторой разумной погрешностью, сколько строк он вернет, он может сработать для вас.
источник
Ссылка взята из этого блога.
Вы можете использовать приведенный ниже запрос, чтобы найти количество строк.
Использование pg_class:
Использование pg_stat_user_tables:
источник
В Oracle вы можете использовать
rownum
для ограничения количества возвращаемых строк. Я предполагаю, что подобная конструкция существует и в других SQL. Итак, в приведенном вами примере вы можете ограничить количество возвращаемых строк до 500001 и применитьcount(*)
then:источник
count(*)
с использованием rownum, 1 с без использования rownum). Да,SELECT count(*) cnt FROM table
всегда будет возвращать 1 строку, но с условием LIMIT он вернет «500001», если размер таблицы превышает 500000, и <размер>, если размер таблицы <= 500000.Насколько широк текстовый столбец?
С GROUP BY мало что можно сделать, чтобы избежать сканирования данных (по крайней мере, сканирования индекса).
Я бы рекомендовал:
Если возможно, измените схему, чтобы убрать дублирование текстовых данных. Таким образом, счет будет происходить в узком поле внешнего ключа в таблице «многие».
В качестве альтернативы, создание сгенерированного столбца с HASH текста, а затем GROUP BY столбца хеша. Опять же, это сделано для уменьшения рабочей нагрузки (сканирование через индекс в узком столбце)
Редактировать:
Ваш исходный вопрос не совсем соответствовал вашей редакции. Я не уверен, знаете ли вы, что COUNT при использовании с GROUP BY вернет количество элементов в группе, а не количество элементов во всей таблице.
источник
Вы можете получить количество с помощью запроса ниже (без * или каких-либо имен столбцов).
источник
count(*)
.Для SQL Server (2005 или более поздней версии ) быстрый и надежный метод:
Подробности о sys.dm_db_partition_stats описаны в MSDN.
Запрос добавляет строки из всех частей (возможно) секционированной таблицы.
index_id = 0 - это неупорядоченная таблица (Heap), а index_id = 1 - это упорядоченная таблица (кластеризованный индекс)
Здесь подробно описаны даже более быстрые (но ненадежные) методы .
источник