64.3. Сканирование индекса
В процессе сканирования индексный метод доступа отвечает только за выдачу идентификаторов всех кортежей, которые по его представлению соответствуют ключам сканирования. Метод доступа не участвует в самой процедуре выборки этих кортежей из основной таблицы и не определяет, удовлетворяют ли эти кортежи условиям видимости или другим ограничениям.
Ключом сканирования является внутреннее представление предложения WHERE
в виде ключ_индекса
оператор
константа
, где ключ индекса — один из столбцов индекса, а оператор — один из членов семейства операторов, связанного с типом данного столбца. При сканировании по индексу могут задаваться несколько или ноль ключей сканирования, результаты поиска которых должны неявно объединяться операцией AND — ожидается, что возвращаемые кортежи будут удовлетворять всем заданным условиям.
Метод доступа для конкретного запроса может сообщить, что индекс является неточным или, другими словами, требует перепроверки. Это подразумевает, что при сканировании индекса будут возвращены все записи, соответствующие ключу сканирования, плюс, возможно, дополнительные записи, которые ему не соответствуют. Внутренний механизм сканирования затем повторно применит условия индекса к кортежу данных, чтобы проверить, нужно ли его выбирать на самом деле. Если признак перепроверки не установлен, при сканировании индекса должны возвращаться только соответствующие ключам записи.
Заметьте, что именно метод доступа должен гарантировать, что корректно будут найдены все и только те записи, которые соответствуют всем переданным ключам сканирования. Также учтите, что ядро системы просто передаёт все предложения WHERE
с подходящими ключами индекса и семействами операторов, не проводя семантический анализ на предмет их избыточности или противоречивости. Например, с условием WHERE x > 4 AND x > 14
, где x
— столбец с индексом-B-деревом, именно самой функции amrescan
в методе B-дерева предоставляется возможность понять, что первый ключ сканирования избыточный и может быть отброшен. Объём предварительной обработки, которую нужно произвести для этого в amrescan
, зависит от того, до какой степени метод доступа должен сводить ключи к «нормализованной» форме.
Некоторые методы доступа возвращают записи индекса в чётко определённом порядке, в отличие от других. Фактически есть два различных варианта реализации упорядоченного вывода некоторым методом доступа:
Для методов доступа, которые всегда возвращают записи в порядке их естественной сортировки (как например, в B-дереве), устанавливается признак
amcanorder
. В настоящее время операторам проверки равенства и упорядочивания при этом должны назначаться номера соответствующих стратегий B-дерева.Для методов доступа, которые поддерживают операторы упорядочивания, устанавливается признак
amcanorderbyop
. Он показывает, что индекс может возвращать записи в порядке, определяемом предложениемORDER BY
ключ_индекса
оператор
константа
. Модификаторы для такого сканирования могут передаваться вamrescan
, как описывалось ранее.
У функции amgettuple
есть аргумент direction
, который может принимать значение ForwardScanDirection
(обычный вариант, сканирование вперёд) или BackwardScanDirection
(сканирование назад). Если в первом вызове после amrescan
указывается BackwardScanDirection
, то множество соответствующих записей индекса сканируется от конца к началу, а не в обычном направлении от начала к концу. В этом случае amgettuple
должна вернуть последний соответствующий кортеж индекса, а не первый как обычно. (Это распространяется только на методы доступа с установленным признаком amcanorder
.) После первого вызова amgettuple
должна быть готова продолжать сканирование в любом направлении от записи, выданной последней до этого. (Но если признак amcanbackward
не установлен, при всех последующих вызовах должно сохраняться то же направление, что было в первом.)
Методы доступа, которые поддерживают упорядоченное сканирование, должны уметь «помечать» позицию сканирования и затем возвращаться к помеченной позиции (возможно, несколько раз к одной и той же позиции). Но запоминаться должна только одна позиция в ходе сканирования; последующий вызов ammarkpos
переопределяет ранее сохранённую позицию. Метод доступа, не поддерживающий упорядоченное сканирование, не должен определять функции ammarkpos
и amrestrpos
в IndexAmRoutine
; достаточно записать в эти указатели NULL.
И позиция сканирования, и отмеченная позиция (при наличии) должны поддерживаться в согласованном состоянии с учётом одновременных добавлений или удалений записей в индексе. Не будет ошибкой, если только что вставленная запись не будет выдана при сканировании, которое могло бы найти эту запись, если бы она существовала до его начала, либо если сканирование выдаст такую запись после перезапуска или возврата, даже если она не была выдана в первый раз. Подобным образом, параллельное удаление может отражаться, а может и не отражаться в результатах сканирования. Важно только, чтобы при таких операциях добавления или удаления не происходило потерь или дублирования записей, которые в этих операциях не участвовали.
Если индекс сохраняет исходные индексируемые значения данных (а не их искажённое представление), обычно полезно поддержать сканирование только индекса, при котором индекс возвращает фактические данные, а не только TID кортежа данных. Это позволит соптимизировать ввод/вывод, только если карта видимости показывает, что TID относится к полностью видимой странице; в противном случае всё равно придётся посетить кортеж, чтобы проверить его видимость для MVCC. Но это не является заботой метода доступа.
Вместо amgettuple
, сканирование индекса может осуществляться функцией amgetbitmap
, которая выбирает все кортежи за один вызов. Это может быть значительно эффективнее amgettuple
, так как позволяет избежать циклов блокировки/разблокировки в методе доступа. В принципе, amgetbitmap
должна давать тот же эффект, что и многократные вызовы amgettuple
, но простоты ради мы накладываем ряд дополнительных ограничений. Во-первых, amgetbitmap
возвращает все кортежи сразу и не поддерживает пометку позиций и возвращение к ним. Во-вторых, кортежи, возвращаемые в битовой карте, не упорядочиваются каким-либо определённым образом, поэтому amgetbitmap
не принимает аргумент direction
. (И операторы упорядочивания никогда не будут передаваться для такого сканирования.) Кроме того, сканирование только индекса с amgetbitmap
неосуществимо, так как нет никакой возможности возвратить содержимое кортежей индекса. Наконец, amgetbitmap
не гарантирует, что будут установлены какие-либо блокировки для возвращаемых кортежей, и следствия этого описаны в Разделе 64.4.
Заметьте, что метод доступа может реализовывать только функцию amgetbitmap
, но не amgettuple
, и наоборот, если его внутренняя реализация несовместима с одной из этих функций.