Перейти к основному содержимому

Поведение классов операторов 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, но планировщик полагается на них в целях оптимизации.