Материалы / Технические статьи / Recheck Cond: exact и lossy bitmap
Статья

Recheck Cond: exact и lossy bitmap

Что означают Recheck Cond, exact и lossy heap blocks и как нехватка work_mem влияет на Bitmap Heap Scan.

— Макс, я опять с планом, и он меня смущает, — Лена сдвинула на экране окно с результатами EXPLAIN. — Вот смотри: Bitmap Heap Scan, а под ним Recheck Cond. Выглядит так, будто Postgres сначала нашел что-то по индексу, а потом усомнился в себе: «А вдруг я ошибся? Дай-ка перепроверю». И тут в плане еще Heap Blocks: exact=502 lossy=1621. Как на это реагировать? Просто махнуть рукой и довериться оптимизатору?

Макс усмехнулся.

— Ты задала один из самых тонких вопросов. Это не недоверие, а наоборот — признак умной и хорошо продуманной подстраховки.

— Подстраховки от чего?

— От неидеальности мира, — Макс сделал глоток кофе. — Помнишь наш дрон, который составлял карту урожая (Bitmap Index Scan)? Представь, что поле огромное, а память под карту (work_mem) у нас ограничена. Дрон не может отметить на карте каждый отдельный куст.

Он сделал паузу, давая Лене время представить картину.

— Когда ему не хватает work_mem, он обводит на карте целые сектора (блоки), где точно есть нужные нам кусты. Но в этих секторах могут расти и другие растения. Такая карта называется неточной, или lossy. И вот когда наш трактор (Bitmap Heap Scan) приезжает в отмеченный сектор, он вынужден перепроверять (Recheck Cond) каждый куст, чтобы собрать только нужные.

— Ааа, то есть это плата за то, что у нас была неточная карта? — осенило Лену.

— Именно! Это не провал оптимизатора, а его штатный план «Б». Он сэкономил память на карте, но заплатил за это дополнительной проверкой на месте. В плане он это выделяет:

  • Heap Blocks: exact — это страницы, для которых карта содержит точную информацию о размещении каждой подходящей строки.

  • Heap Blocks: lossy — это “грубые” сектора карты. В памяти не хватило места, чтобы обозначить каждую строку, и Postgres вынужден помечать целую страницу целиком: “Может, здесь есть что-то подходящее — перепроверь вручную”.

— И что мне с этим делать?

— Вот тут самое главное. Не паниковать, а смотреть в EXPLAIN ANALYZE на строку Rows Removed by Index Recheck. Если там маленькое число, значит, всё отлично. Карта была почти точной. А вот если там тысячи отброшенных строк, это сигнал: наш трактор тратит слишком много времени на добычу и проверку «мусора».

— Поняла. Но у меня там как раз очень большое число! Почему?

— Прежде всего это означает, что bitmap стал неточным и PostgreSQL пришлось перепроверить много строк со страниц, отмеченных целиком. Обычно смотрят на объём lossy-страниц, доступный work_mem и селективность условия. Для некоторых типов индексов перепроверка может требоваться по природе самого оператора, даже без нехватки памяти. Мёртвые версии строк увеличивают общий объём работы с таблицей, но сами по себе не превращают точный bitmap в lossy.

Что запомнить:

  • Recheck Cond — это не ошибка, а плановая перепроверка для неточных (lossy) битовых карт.

  • Много lossy-блоков — нехватка памяти для построения точной карты (work_mem).

  • Большой Rows Removed by Index Recheck — повод сопоставить exact и lossy-страницы, проверить селективность условия и осторожно протестировать больший work_mem только для этой сессии.

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