Поведение классов операторов B-дерева
Класс оператора btree
должен предоставлять пять операторов сравнения: <
, <=
, =
, >=
и >
. Можно было бы ожидать, что <>
также должен быть частью класса оператора, но это не так, потому что использовать <>
в предложении WHERE
для поиска по индексу практически бесполезно. (Для некоторых целей планировщик рассматривает <>
как связанный с классом оператора btree
; но он находит этот оператор через ссылку отрицателя оператора =
, а не из pg_amop
).
Когда несколько типов данных имеют практически идентичную семантику сортировки, их классы операторов можно объединить в семейство операторов. Это выгодно, поскольку позволяет планировщику делать выводы о межтиповых сравнениях. Каждый класс операторов в семействе должен содержать однотипные операторы (и связанные с ними вспомогательные функции) для своего типа входных данных, в то время как операторы межтипных сравнений и вспомогательные функции в семействе «свободны». Рекомендуется включать в семейство полный набор операторов межтиповых сравнений, чтобы планировщик мог представлять любые условия сравнения, которые он выводит из транзитивности.
Существует несколько основных предположений, которым должно удовлетворять семейство операторов btree
:
-
Оператор = должен быть отношением эквивалентности, то есть для всех ненулевых значений A, B, C типа данных:
- A = A истинно (рефлексивность);
- если A = B, то B = A (симметричность);
- Если A = B и B = C, то A = C (транзитивность);
-
Оператор < должен быть сильным отношением упорядочивания, то есть для всех ненулевых значений A, B, C:
- A < A ложно (антирефлексивность);
- Если A < B и B < C, то A < C (транзитивность);
-
Кроме того, упорядочивание является полным, то есть для всех ненулевых значений A, B:
-
Истинным является ровно одно из A < B, A = B и B < A (трихотомия).
(Закон трихотомии, конечно, оправдывает определение функции поддержки сравнения).
-
Остальные три оператора определяются в терминах =
и <
очевидным образом и должны действовать согласованно с ними.
Для семейства операторов, поддерживающих несколько типов данных, вышеуказанные законы должны выполняться, когда A, B, C берутся из любых типов данных семейства. Переходные законы обеспечить сложнее всего, поскольку в ситуациях с перекрестными типами они представляют собой утверждения о том, что поведение двух или трех различных операторов согласовано.
Например, не получится поместить float8
и numeric
в одно семейство операторов, по крайней мере, с текущей семантикой, согласно которой числовые значения преобразуются в float8
для сравнения с float8
. Из-за ограниченной точности float8
это означает, что существуют различные числовые значения, которые будут сравниваться с одним и тем же значением float8
, и, таким образом, транзитивный закон не работает.
Еще одно требование к семейству множественных типов данных заключается в том, что любые неявные или двоично-коэрцитивные приведения, определенные между типами данных, входящими в семейство операторов, не должны изменять связанный с ними порядок сортировки.
Должно быть понятно, почему для индекса btree
необходимо, чтобы эти законы действовали в пределах одного типа данных: без них невозможно упорядочить ключи. Кроме то го, поиск по индексу с использованием ключа сравнения другого типа данных требует, чтобы сравнения вели себя разумно в двух типах данных. Расширения до трех и более типов данных внутри семейства не являются строго обязательными для самого механизма индекса btree
, но планировщик полагается на них в целях оптимизации.