Recheck Cond: exact и lossy bitmap
Что означают Recheck Cond, exact и lossy heap blocks и как нехватка work_mem влияет на Bitmap Heap Scan.
PostgreSQLEXPLAINИндексыПроизводительность— Макс, я опять с планом, и он меня смущает, — Лена сдвинула на экране окно с результатами 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 глобально ради одного плана не стоит: значение применяется к отдельным узлам и при множестве одновременных запросов способно резко увеличить расход памяти.