Как стать автором
Обновить

Комментарии 36

Огромное спасибо за статью!


Интересно, а насколько сложно сделать эстиматор из последнего примера надёжным?

Возможно наверно через права доступа (execute) самой функции
Последний пример мне кажется слегка странным. Нет никакой проблемы добавить слово EXPLAIN к нужному запросу непосредственно в коде и там же получить нужный кусок плана.

Кроме того все эти данные без костылей есть в системных таблицах, это уже 5 лет назад изложено в вики постгреса: wiki.postgresql.org/wiki/Count_estimate

Вот то что вам нужно:
SELECT reltuples::BIGINT AS estimate
FROM pg_class
WHERE oid = 'schema_name.table_name'::regclass;

Хм… И правда ларчик просто открывался. Спасибо!

Емнип, в своё время в оракле лайфхак для разгона count-а был писать не select count(*), a select count(1). Что по нонешним временам — не знаю.
Всё еще работает.
Ну, я бы сказал «странно», ибо уже могли бы допилить парсеры до понимания, что не надо весь dictionary тащить в клиента, если поля не указаны в каунте.

Я-то, по старой привычке, пользуюсь, но не думал, что имеет смысл.
Ну так оракл же, они вообще неторопливые ребята.

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

Нет, не было такого никогда. Count(*) уже сам по себе оптимален. Никакие count(1) улучшить его не могут, а вот ухудшить всякие вариации типа count(rowid) или count(-2) могут. Это были мифы а-ля Бурлесоновщина…

По памяти, оптимизация count(1) vs count(*) была в том, что во втором случае оракл лез в дата дикшнари, чтобы получить метаданные. В первом случае это не требуется. Повторюсь, мой опыт с этим — это 15 лет назад. Просто привык тогда писать count(1) так и пишу, не более.
Да я знаю про этот миф. Я не знаю как и кто его породил, а главное — почему люди так наивно в это верят, ведь в оракле все легко проверяется, например трассировкой 10053.

Ссылки по теме:
jonathanlewis.wordpress.com/2008/10/31/count
jonathanlewis.wordpress.com/2020/02/25/count-again-2
Ok, спасибо.
Аналогично поведению PostgreSQL. Для count(1) есть проверка на NULL, поэтому медленнее count(*)

Не аналогично. В оракле count(1) заменяется на звёздочку автоматически

Вот этого не знаю про замену. В примере по ссылке и другом примере count(*) чуть чуть быстрее count(1), хотя может быть это просто погрешность

Дочитайте до конца — там шутка про скорость набора. Оптимизатор трансформирует запрос ещё до выполнения — прочитайте по моей ссылке у льюиса

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

10122, 00000, "Disable transformation of count(col) to count(*)"

Резюмируя — давайте пользоваться открытым по чтобы не строить догадки )

Это не ошибка, а event, позволяющий отключить эту трансформацию. И оракл на порядок более документирован и имеет неимоверное количество средств же ага и траблшутинга. По возможностям оптимизатора, количеству трансформаций, гибкости и мощности движка, и бэкграунд сервисов он также всех опережает. Например, тот же full table scan или index fast full scan могут работать в параллели с direct path reads, в отличие от PostgreSql. У него, конечно же, есть свои огромные минусы(например, цена и выводящая из себя тех поддержка), но закрытость ПО — это несерьезный довод.

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

Да что вы говорите… Более предсказуема? Кому? И давно вы анализировали код PostgreSql? Достаточен ли ваш уровень чтобы анализировать его код? А сколько вообще разработчиков, работающей с СУБД с достаточным уровнем c/c++? Как вы считаете, что быстрее и удобнее и правильнее: прочитать гайд, документацию или исходный код СУБД?


Зы. Что-то своих статей не пишите с анализом кода pg, а только переводите чужие в которых нет ни одного куска кода...


Зыы. Может уже остановитесь со своей маркетинговой чушью?

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

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

п.с. я не понимаю, зачем вы стараетесь выгородить оракл, описывая его преимущества (маркетинговые), хотя речи об этом не было совсем. Может быть вы лично заинтересованы, не знаю
Боюсь что при попытке сделать это реально, а не абстрактно-теоретически — окажется что в современном мире это не так уж и просто))))))))
Буквально на днях это проделывал в исходниках postgres
Кстати не так уж и трудно. Я с ClickHouse только рак работаю, других вариантов просто нет.

:D это смотря какую IDE использовать :D во многих из них count(*) вставляется автокомплитом, а 1 придётся вручную вводить, так что звездочка рулит :D

Ну у меня это просто мышечная память, тут сложнее её заменить, с count(1) на *

Ну как я уже показывал по ссылке 1 заменяется на звёздочку в современных версиях оракл :) но в случае автоматических кодоанализаторов, да и просто, чтобы не давать такому мифу развиваться, я бы советовал использовать звёздочку

Статья вызвала эмоцию «Твою мать, почему я до сих пор этого не знал?». Правда я 1С-ник, но это не отменяет того, что для подсчёта количества строк нужно использовать в запросе конструкцию «ВЫБРАТЬ КОЛИЧЕСТВО(*) ИЗ Таблица», а не городить велосипеды, что я раньше делал. Причём это даже в справке написано.
Очень актуальна для постоянно распухающей БД Zabbix
Тут лучше удалять на регулярной основе старые записи, после чего чистить vacuumdb -z -f, сжимая файлы таблиц
До полноценной статьи не мешало бы добавить бенчмарки и графики. В текущем виде нет понимания, что в какой ситуации следует выбрать.

И в целом кодстайл так себе, процедуры счётчика лучше было разделить на две или три — позволит избежать интересных ошибок. Впрочем это перевод, так что претензии наверное не по адресу :-)
Вот здесь и бенчмарки и все остальное. И объяснение, что count(*) в Postgres на самом деле count(), а * появилась позже
Запись count (1) или count (id) на самом деле медленнее, чем count (*)

А если Id — это поле (или колонка) NOT NULL, по которому построен уникальный индекс?
Помнится, это по крайней мере в некоторых реляционных СУБД давало заметное ускорение.

Решение с mytable_count
Использование deferred constraint trigger гарантирует, что блокировка строки в mytable_count будет максимально короткой
Это верно, но для TRUNCATE mytable триггер выполняется немедленно, и это может быть проблемой. Рассмотрим такой пример:
транзакция 1: begin; TRUNCATE mytable;…… commit; --начинается раньше, но долгая
транзакция 2: begin; Insert into mytable; commit; — позже и короткая
Но транзакции 2 придётся ожидать окончания транзакции 1, поскольку транзакция 1 заблокировала таблицу mytable_count
И надо учитывать, что deferred constraint trigger может привести к такой проблеме:
в транзакции сначала вставили\удалили строки в mytable, а позже есть логика, завязанная на количество записей в mytable, и берём мы его из mytable_count, но в mytable_count не учтены вставили\удаления, выполненные в этой транзакции
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории