62.1. Индексы B-дерева#
62.1. Индексы B-дерева #
62.1.1. Введение #
Tantor SE-1C включает реализацию стандартной структуры данных индекса btree (многопутевое сбалансированное дерево). Любой тип данных, который может быть отсортирован в хорошо определенном линейном порядке, может быть проиндексирован с помощью индекса btree. Единственное ограничение состоит в том, что запись индекса не может превышать примерно одну треть страницы (после сжатия TOAST, если применимо).
Поскольку каждый класс операторов btree накладывает порядок сортировки на свой тип данных, классы операторов btree (или, на самом деле, семейства операторов) стали использоваться как общее представление и понимание семантики сортировки в Tantor SE-1C. Поэтому они приобрели некоторые функции, которые выходят за рамки того, что было бы необходимо только для поддержки индексов btree, и части системы, которые находятся довольно далеко от AM btree, используют их.
62.1.2. Поведение классов операторов B-дерева #
Как показано в Таблица 34.2, класс операторов 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
is false (закон о нерефлексивности)если
A
<
B
иB
<
C
, тоA
<
C
(транзитивный закон)
Кроме того, упорядочение является полным; то есть, для всех ненулевых значений
A
,B
:ровно одно из
A
<
B
,A
=
B
иB
<
A
истинно (закон трех частей)
(Закон трихотомии оправдывает определение функции сравнения, конечно).
Другие три оператора определены с использованием операторов =
и <
очевидным образом и должны действовать согласованно с ними.
Для семейства операторов, поддерживающего несколько типов данных, вышеуказанные законы должны выполняться, когда A
, B
, C
берутся из любых типов данных в семействе. Транзитивные законы являются самыми сложными для обеспечения, так как в случае перекрестных типов они представляют утверждения о согласованности поведения двух или трех разных операторов. Например, не будет работать, если поместить float8
и numeric
в одно семейство операторов, по крайней мере, не с текущей семантикой, что значения numeric
преобразуются в float8
для сравнения с float8
. Из-за ограниченной точности float8
это означает, что существуют различные значения numeric
, которые будут сравниваться равными с одним и тем же значением float8
, и, следовательно, транзитивный закон не будет выполняться.
Другим требованием для семейства множественных типов данных является то, что любые неявные или бинарные приведения типов, определенные между типами данных, включенными в семейство операторов, не должны изменять связанный порядок сортировки.
Должно быть ясно, почему индекс btree требует соблюдения этих правил в пределах одного типа данных: без них нет упорядочивания для упорядочивания ключей. Кроме того, поиск по индексу с использованием ключа сравнения другого типа данных требует, чтобы сравнения вели себя разумно для двух типов данных. Расширения до трех или более типов данных внутри семейства не являются строго обязательными для самого механизма индекса btree, но планировщик полагается на них в целях оптимизации.
62.1.3. Функции поддержки B-дерева #
Согласно Таблица 34.8, btree определяет одну обязательную и четыре дополнительные функции поддержки. Пять пользовательских методов включают:
order
Для каждой комбинации типов данных, для которых семейство операторов btree предоставляет операторы сравнения, оно должно предоставлять опорную функцию сравнения, зарегистрированную в
pg_amproc
с номером опорной функции 1 иamproclefttype
/amprocrighttype
, равными левому и правому типам данных для сравнения (т.е. тем же типам данных, с которыми зарегистрированы соответствующие операторы вpg_amop
). Функция сравнения должна принимать два ненулевых значенияA
иB
и возвращать значениеint32
, которое является<
0
,0
или>
0
, когдаA
<
B
,A
=
B
илиA
>
B
соответственно. Результат null запрещен: все значения типа данных должны быть сравнимыми. См. примеры вsrc/backend/access/nbtree/nbtcompare.c
.Если сравниваемые значения имеют тип данных, который поддерживает правило сортировки, соответствующий OID правила сортировки будет передан в функцию поддержки сравнения с использованием стандартного механизма
PG_GET_COLLATION()
.sortsupport
По желанию, семейство операторов btree может предоставлять функции поддержки сортировки, зарегистрированные под номером 2. Эти функции позволяют реализовать сравнения для целей сортировки более эффективным способом, чем просто вызов опорные функции сравнения. Соответствующие API определены в файле
src/include/utils/sortsupport.h
.in_range
По желанию, семейство операторов btree может предоставлять опорные функции in_range, зарегистрированные под номером 3. Они не используются во время операций индексирования btree; вместо этого они расширяют семантику семейства операторов таким образом, чтобы оно могло поддерживать оконные предложения, содержащие типы границ рамки
RANGE
offset
PRECEDING
иRANGE
offset
FOLLOWING
(см. Раздел 4.2.8). В основном, предоставляемая дополнительная информация определяет, как добавить или вычесть значениеoffset
таким образом, чтобы оно было совместимо с упорядочиванием данных семейства.Функция
in_range
должна иметь сигнатуруin_range(
val
type1,base
type1,offset
type2,sub
bool,less
bool) returns boolval
иbase
должны быть одного типа, который является одним из типов, поддерживаемых семейством операторов (т.е. типом, для которого он предоставляет упорядочение). Однако,offset
может быть другого типа, который может быть неподдерживаемым семейством. Примером является встроенное семействоtime_ops
, которое предоставляет функциюin_range
, у которойoffset
имеет типinterval
. Семейство может предоставлять функцииin_range
для любого из поддерживаемых типов и одного или нескольких типовoffset
. Каждая функцияin_range
должна быть введена вpg_amproc
сamproclefttype
, равнымtype1
, иamprocrighttype
, равнымtype2
.Существенная семантика функции
in_range
зависит от двух логических флаговых параметров. Она должна добавить или вычестьbase
иoffset
, затем сравнитьval
с результатом, следующим образом:если
!
sub
и!
less
, вернутьval
>=
(base
+
offset
)если
!
sub
иless
, вернутьval
<=
(base
+
offset
)если
sub
и!
less
, вернутьval
>=
(base
-
offset
)если
sub
иless
, вернутьval
<=
(base
-
offset
)
Перед этим функция должна проверить знак переменной
offset
: если он меньше нуля, вызвать ошибкуERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE
(22013) с текстом ошибки вида “недопустимый размер предшествующего или следующего значения в оконной функции”. (Это требуется стандартом SQL, хотя нестандартные семейства операторов, возможно, могут игнорировать это ограничение, так как, кажется, нет особой семантической необходимости в нем). Это требование делегируется функцииin_range
, чтобы основной код не должен был понимать, что означает “меньше нуля” для конкретного типа данных.Дополнительное ожидание состоит в том, что функции
in_range
должны, если это возможно, избегать генерации ошибки, еслиbase
+
offset
илиbase
-
offset
приведут к переполнению. Правильный результат сравнения может быть определен даже если это значение будет выходить за диапазон типа данных. Обратите внимание, что если тип данных включает понятия, такие как “бесконечность” или “NaN”, необходимо удостовериться, что результаты функцииin_range
согласуются с нормальным порядком сортировки семейства операторов.Результаты функции
in_range
должны быть согласованы с порядком сортировки, установленным операторной семьей. А именно, при заданных значенияхoffset
иsub
, должно выполняться следующее:Если
in_range
сless
= true истинно для некоторыхval1
иbase
, то оно должно быть истинно для каждогоval2
<=
val1
с тем жеbase
.Если
in_range
сless
= true равно false для некоторыхval1
иbase
, то оно должно быть false для каждогоval2
>=
val1
с тем жеbase
.Если
in_range
сless
= true истинно для некоторогоval
иbase1
, то оно должно быть истинно для каждогоbase2
>=
base1
с тем жеval
.Если
in_range
сless
= true равно false для некоторыхval
иbase1
, то оно должно быть false для каждогоbase2
<=
base1
с тем жеval
.
Аналогичные операторы с инвертированными условиями выполняются, когда
less
= false.Если заказываемый тип (
type1
) является сортируемым, соответствующий OID правила сортировки будет передан в функциюin_range
с использованием стандартного механизма PG_GET_COLLATION().in_range
функции не обязаны обрабатывать NULL входные данные и обычно будут помечены как строгие.equalimage
По желанию, семейство операторов btree может предоставлять опорные функции
equalimage
(“равенство подразумевает равенство изображения”), зарегистрированные под номером 4. Эти функции позволяют основному коду определить, когда безопасно применять оптимизацию дедупликации btree. В настоящее время функцииequalimage
вызываются только при создании или перестроении индекса.Функция
equalimage
должна иметь сигнатуруequalimage(
opcintype
oid
) returns boolВозвращаемое значение представляет собой статическую информацию о классе операторов и сортировке. Возвращение
true
указывает, что функцияorder
для класса операторов гарантированно возвращает только0
(“аргументы равны”), когда его аргументыA
иB
также взаимозаменяемы без потери семантической информации. Не регистрирование функцииequalimage
или возвращениеfalse
указывает на то, что это условие не может быть считано верным.Аргумент
opcintype
является
типа данных, индексируемого классом операторов. Это удобство, позволяющее повторно использовать одну и ту же базовую функциюpg_type
.oidequalimage
в разных классах операторов. Еслиopcintype
является сортируемым типом данных, соответствующий OID правила сортировки будет передан функцииequalimage
с использованием стандартного механизмаPG_GET_COLLATION()
.С точки зрения класса операторов, возвращение
true
указывает на то, что дедупликация безопасна (или безопасна для правила сортировки, идентификатор которого был передан в функциюequalimage
). Однако, основной код будет считать дедупликацию безопасной только для индекса, когда каждый индексируемый столбец использует класс операторов, который регистрирует функциюequalimage
, и каждая функция действительно возвращаетtrue
при вызове.Равенство изображений почти то же самое условие, что и простое побитовое равенство. Есть одно тонкое отличие: при индексировании типа данных varlena, представление на диске двух равных изображений может не быть побитово равным из-за несогласованного применения сжатия TOAST на входе. Формально, когда функция
equalimage
класса операторов возвращаетtrue
, можно считать, что функцияdatum_image_eq()
на языке C всегда согласуется с функциейorder
класса операторов (при условии, что один и тот же OID правила сортировки передается и в функциюequalimage
, и в функциюorder
).Основной код фундаментально неспособен вывести какую-либо информацию о статусе “равенство подразумевает равенство изображения” класса операторов внутри семейства множественных типов данных, основываясь на деталях других классов операторов в том же семействе. Кроме того, не имеет смысла для семейства операторов зарегистрировать функцию
equalimage
для перекрестного типа, и попытка сделать это приведет к ошибке. Это связано с тем, что статус “равенство подразумевает равенство изображения” не зависит только от семантики сортировки/равенства, которая более или менее определена на уровне семейства операторов. Обычно, семантику, которую реализует конкретный тип данных, необходимо рассматривать отдельно.Конвенция, которую следуют классы операторов, включенные в базовую дистрибуцию Tantor SE-1C, заключается в регистрации стандартной обобщенной функции
equalimage
. Большинство классов операторов регистрируютbtequalimage()
, что указывает на безопасность дедупликации безусловно. Классы операторов для сравнимых типов данных, таких какtext
, регистрируютbtvarstrequalimage()
, что указывает на безопасность дедупликации с детерминированными правилами сортировки. Лучшей практикой для сторонних расширений является регистрация собственной пользовательской функции для сохранения контроля.options
По желанию, семейство операторов B-дерева может предоставлять опорные функции
options
(“опции, специфичные для класса операторов”), зарегистрированные под номером 5. Эти функции определяют набор пользовательских параметров, которые управляют поведением класса операторов.Опорная функция
options
должна иметь сигнатуруoptions(
relopts
local_relopts *
) returns voidФункции передается указатель на структуру
local_relopts
, которую необходимо заполнить набором специфических для класса операторов опций. Опции могут быть доступны из других вспомогательных функций с использованием макросовPG_HAS_OPCLASS_OPTIONS()
иPG_GET_OPCLASS_OPTIONS()
.В настоящее время ни один класс операторов B-Tree не имеет функции поддержки
options
. B-дерево не позволяет гибкого представления ключей, как это делают GiST, SP-GiST, GIN и BRIN. Поэтому, вероятно,options
не имеет большого применения в текущем методе доступа к индексу B-дерева. Тем не менее, эта Опорная функция была добавлена в B-дерево для обеспечения единообразия и, вероятно, найдет применение во время дальнейшего развития B-дерева в Tantor SE-1C.
62.1.4. Реализация #
Этот раздел описывает детали реализации индекса B-Tree, которые могут быть полезны опытным пользователям. См. файл src/backend/access/nbtree/README
в исходном дистрибутиве для более подробного описания реализации B-Tree с фокусом на внутренних механизмах.
62.1.4.1. Структура B-дерева #
Tantor SE-1C B-Tree индексы являются многоуровневыми структурами дерева, где каждый уровень дерева может быть использован в качестве двусвязного списка страниц. Одна метастраница хранится в фиксированной позиции в начале первого сегментного файла индекса. Все остальные страницы являются либо листовыми страницами, либо внутренними страницами. Листовые страницы - это страницы на самом нижнем уровне дерева. Все остальные уровни состоят из внутренних страниц. Каждая листовая страница содержит кортежи, указывающие на строки таблицы. Каждая внутренняя страница содержит кортежи, указывающие на следующий уровень вниз по дереву. Обычно более 99% всех страниц являются листовыми страницами. Как внутренние, так и листовые страницы используют стандартный формат страницы, описанный в Раздел 63.6.
Новые листовые страницы добавляются в индекс B-дерева, когда существующая листовая страница не может вместить входящий кортеж. Операция разделения страницы освобождает место для элементов, которые изначально принадлежали переполненной странице, перемещая часть элементов на новую страницу. При разделении страницы также вставляется новая ссылка на нижний уровень на новую страницу в родительскую страницу, что может привести к разделению родительской страницы в свою очередь. Разделение страниц “распространяется вверх” рекурсивным образом. Когда корневая страница наконец не может вместить новую ссылку на нижний уровень, выполняется операция разделения корневой страницы. Это добавляет новый уровень в структуру дерева, создавая новую корневую страницу, которая находится на один уровень выше исходной корневой страницы.
62.1.4.2. Удаление индекса снизу вверх #
B-Tree индексы не знают о том, что в рамках MVCC может существовать несколько версий одной и той же логической строки таблицы; для индекса каждый кортеж является независимым объектом, который требует своей собственной записи в индексе. Кортежи “Version churn” иногда могут накапливаться и негативно влиять на задержку и пропускную способность запросов. Это обычно происходит при работе с нагрузкой, где преобладают операции UPDATE
, и большинство отдельных обновлений не могут использовать оптимизацию HOT. Изменение значения только одного столбца, покрытого одним индексом, во время UPDATE
всегда требует нового набора индексных кортежей — по одному для каждого индекса на таблице. Обратите внимание, что это включает индексы, которые не были “логически изменены” операцией UPDATE
. Все индексы будут нуждаться в последующем физическом кортеже индекса, который указывает на последнюю версию в таблице. Каждый новый кортеж в каждом индексе, как правило, должен сосуществовать с исходным “обновленным” кортежем в течение короткого периода времени (обычно до непосредственно после метки транзакции UPDATE
).
Индексы B-Tree пошагово удаляют версии устаревших кортежей индекса, выполняя проходы удаления индекса снизу вверх. Каждый проход удаления запускается в ответ на ожидаемое “разделение страницы из-за изменения версии”. Это происходит только с индексами, которые не изменяются логически с помощью операторов UPDATE
, иначе на определенных страницах могло бы накапливаться большое количество устаревших версий. Обычно разделение страницы избегается, хотя возможно, что некоторые эвристические алгоритмы на уровне реализации не смогут идентифицировать и удалить ни одного ненужного кортежа индекса (в этом случае разделение страницы или проход дедупликации разрешает проблему входящего нового кортежа, который не помещается на листовую страницу). Максимальное количество версий, которые должен просмотреть любой сканирующий индекс (для любой отдельной логической строки), является важным фактором общей отзывчивости и пропускной способности системы. Проход удаления индекса снизу вверх нацелен на предполагаемые ненужные кортежи на одной листовой странице на основе качественных различий, касающихся логических строк и версий. Это отличается от “сверху вниз” очистки индекса, выполняемой рабочими процессами автоочистки, которая запускается, когда превышаются определенные количественные пороги на уровне таблицы (см. Раздел 23.1.6).
Примечание
Не все операции удаления, выполняемые внутри индексов B-дерева, являются операциями удаления снизу вверх. Существует отдельная категория удаления кортежей индекса: удаление простого кортежа индекса. Это операция отложенного обслуживания, которая удаляет кортежи индекса, которые известно, что можно безопасно удалить (те, у которых бит LP_DEAD
в идентификаторе элемента уже установлен). Как и удаление индекса снизу вверх, удаление простого кортежа индекса происходит в тот момент, когда ожидается разделение страницы, чтобы избежать разделения.
Простое удаление является оптимистичным в том смысле, что оно может произойти только тогда, когда недавние сканирования индекса устанавливают биты LP_DEAD
для затронутых элементов в процессе прохождения. До версии Tantor SE-1C 14 единственная категория удаления в B-дереве было простое удаление. Основные различия между ним и удалением снизу вверх заключаются в том, что только первое оптимистически управляется активностью проходящих сканирований индекса, в то время как только последнее специально нацелено на версионные изменения от UPDATE
, которые логически не изменяют индексированные столбцы.
Удаление индексов снизу вверх выполняет подавляющее большинство всех операций очистки мусорных кортежей индекса для определенных индексов с определенной нагрузкой. Это ожидаемо для любого индекса B-Tree, который подвержен значительным изменениям версий от команд UPDATE
, которые редко или никогда логически не изменяют столбцы, которые покрывает индекс. Среднее и наихудшее количество версий на логическую строку можно поддерживать на низком уровне только через целенаправленные инкрементальные проходы удаления. Вполне возможно, что размер индексов на диске никогда не увеличится даже на одну страницу/блок, несмотря на постоянные изменения версий от команд UPDATE
. Даже в этом случае, исчерпывающая "чистка" операцией VACUUM
(обычно выполняемая в рабочем процессе автоматической очистки) в конечном итоге потребуется в качестве части коллективной очистки таблицы и каждого из ее индексов.
В отличие от VACUUM
, удаление индекса снизу вверх не обеспечивает никаких надежных гарантий относительно того, насколько старыми могут быть самые старые мусорные кортежи индекса. Ни одному индексу не разрешается сохранять “мусорные кортежи” индекса, которые стали мертвыми до консервативной точки отсечения, общей для таблицы и всех ее индексов в совокупности. Этот фундаментальный инвариант на уровне таблицы обеспечивает безопасность повторного использования идентификаторов строк таблицы TID. Именно таким образом возможно, чтобы различные логические строки повторно использовали один и тот же идентификатор строки таблицы TID со временем (хотя это никогда не может произойти с двумя логическими строками, чьи сроки службы охватывают один и тот же цикл VACUUM
).
62.1.4.3. Дедупликация #
Дубликатом является кортеж листовой страницы (кортеж, указывающий на строку таблицы), в котором все индексные ключевые столбцы имеют значения, совпадающие с соответствующими значениями столбцов из по крайней мере одного другого кортежа листовой страницы в том же индексе. Дублирующиеся кортежи довольно распространены на практике. Индексы В-дерева могут использовать специальное, экономичное по месту представление для дубликатов, когда используется необязательная техника: дедупликация.
Дедупликация работает путем периодического объединения групп дублирующихся кортежей, формируя для каждой группы единственный кортеж списка публикаций. Значение(я) ключа столбца появляется только один раз в этом представлении. Затем следует отсортированный массив TID, указывающий на строки в таблице. Это значительно уменьшает размер хранения индексов, где каждое значение (или каждая отдельная комбинация значений столбцов) в среднем появляется несколько раз. Задержка запросов может быть значительно снижена. Общая пропускная способность запросов может значительно увеличиться. Затраты на регулярную очистку индексов также могут быть значительно снижены.
Примечание
B-Tree дедупликация так же эффективна с “дубликатами”, содержащими значение NULL, даже если значения NULL никогда не равны друг другу согласно оператору =
любого класса операторов B-Tree. Для любой части реализации, которая понимает структуру B-Tree на диске, NULL является просто еще одним значением из области индексированных значений.
Процесс дедупликации происходит лениво, когда вставляется новый элемент, который не может поместиться на существующей листовой странице, хотя только в том случае, если удаление индексного кортежа не освободило достаточно места для нового элемента (обычно удаление кратковременно рассматривается, а затем пропускается). В отличие от кортежей списка публикаций GIN, кортежи списка публикаций B-дерева не нуждаются в расширении каждый раз при вставке нового дубликата; они являются всего лишь альтернативным физическим представлением исходного логического содержимого листовой страницы. Этот дизайн приоритезирует последовательную производительность при смешанных рабочих нагрузках чтения и записи. Большинство клиентских приложений, по крайней мере, получат умеренную выгоду от использования дедупликации. Дедупликация включена по умолчанию.
CREATE INDEX
и REINDEX
применяют дедупликацию для создания кортежей списка публикаций, хотя
стратегия, которую они используют, немного отличается. Каждая группа дублирующихся
обычных кортежей, встреченных в отсортированном вводе из таблицы,
объединяется в кортеж списка публикаций
перед добавлением на текущую ожидающую листовую
страницу. Отдельные кортежи списка публикаций упаковываются с максимальным
количеством TID. Листовые страницы записываются
обычным образом, без отдельного прохода по дедупликации. Эта
стратегия хорошо подходит для CREATE INDEX
и
REINDEX
, потому что они выполняются однократно
пакетными операциями.
Рабочие нагрузки, при которых выгода от удаления дубликатов отсутствует из-за наличия небольшого количества или отсутствия дублирующихся значений в индексах, будут иметь небольшое, фиксированное снижение производительности (если удаление дубликатов явно не отключено). Параметр хранения deduplicate_items
может быть использован для отключения удаления дубликатов в отдельных индексах. В случае только чтения нагрузки никогда не возникает снижение производительности, так как чтение кортежей списка публикаций по крайней мере так же эффективно, как чтение стандартного представления кортежа. Отключение удаления дубликатов обычно не является полезным.
Иногда уникальные индексы (а также уникальные ограничения) могут использовать дедупликацию. Это позволяет временно "поглотить" дубликаты версий на листовых страницах. Дедупликация в уникальных индексах дополняет стратегию удаления индекса снизу вверх, особенно в случаях, когда долговременная транзакция удерживает снимок, который блокирует сборку мусора. Цель состоит в том, чтобы купить время для повторного вступления в силу стратегии удаления индекса снизу вверх. Отсрочка разделения страниц до тех пор, пока не исчезнет единственная долговременная транзакция, может позволить успешно выполнить проход удаления снизу вверх, где ранее проход удаления не удался.
Подсказка
Применяется специальный эвристический алгоритм для определения, должен ли выполняться проход по дедупликации в уникальном индексе. Часто можно сразу перейти к разделению листовой страницы, избегая штрафа в производительности от потери циклов на бесполезные проходы по дедупликации. Если вам волнует издержки на дедупликацию, рассмотрите возможность выборочного отключения параметра deduplicate_items = off
. Оставление дедупликации включенной в уникальных индексах имеет небольшой недостаток.
Дедупликация не может быть использована во всех случаях из-за ограничений на уровне реализации. Безопасность дедупликации определяется при выполнении команды CREATE INDEX
или REINDEX
.
Обратите внимание, что дедупликация считается небезопасной и не может использоваться в следующих случаях, связанных с семантически значимыми различиями между равными данными:
text
,varchar
иchar
не могут использовать дедупликацию, когда используется недетерминированное правило сортировки. Различия в регистре и акцентах должны быть сохранены между равными данными.numeric
не может использовать дедупликацию. Числовая шкала отображения должна быть сохранена для одинаковых данных.jsonb
не может использовать дедупликацию, так как класс операторов B-Tree дляjsonb
использует внутренне типnumeric
.float4
иfloat8
не могут использовать дедупликацию. У этих типов есть отдельные представления для-0
и0
, которые, тем не менее, считаются равными. Это различие должно быть сохранено.
Есть еще одно ограничение на уровне реализации, которое может быть снято в будущих версиях Tantor SE-1C:
Типы контейнеров (такие как составные типы, массивы или типы диапазонов) не могут использовать дедупликацию.
Существует еще одно ограничение на уровне реализации, которое применяется независимо от класса оператора или правила сортировки:
INCLUDE
индексы никогда не могут использовать дедупликацию.