×
Мы обрабатываем cookies, чтобы сделать наш сайт удобнее и персонализированнее для вас. Подробнее: политика использования «cookies» и «политики конфиденциальности».

Для самостоятельной настройки ознакомьтесь с инструкцией

Дополнительные настройки cookies в браузерах

Файлы cookie автоматически загружаются в ваш браузер при посещении веб-сайта. У вас есть возможность управлять этими файлами. Если Вы не согласны с использованием файлов cookies, запретите их сохранение на своём устройстве, удалите уже имеющиеся файлы cookies через настройки браузера или прекратите использование сайта.

При отключении обработки cookie наш сайт продолжит функционировать, однако будут использоваться исключительно необходимые технические файлы, без которых работа ресурса невозможна.

Инструкция по отключению cookies
Принять
Настроить
Отклонить

ДОКУМЕНТАЦИЯ

Выберите версию, форк и язык для СУБД Digital Q.DataBase, чтобы прочитать или скачать всю документацию.
Техподдержка
Документация
Диасофт
Авторские права © 2016–2025 ООО "Диасофт Экосистема"
Скачать всю документацию:

2.8.8. Частичные индексы

Частичный индекс частичный индекс — это индекс, построенный для определенного подмножества таблицы; подмножество определяется условным выражением (называемым предикат частичного индекса). Индекс содержит записи только для тех строк таблицы, которые удовлетворяют указанному предикату. Частичные индексы представляют собой специализированную функцию, однако существует ряд ситуаций, в которых их применение целесообразно.

Одной из основных причин использования частичного индекса является исключение индексации часто встречающихся значений. Поскольку запрос, выполняющий поиск часто встречающегося значения (которое составляет более нескольких процентов от всех строк таблицы), все равно не будет использовать индекс, нет смысла хранить данные строки в индексе. Это позволяет уменьшить размер индекса, что ускоряет выполнение запросов, использующих индекс. Это также ускорит многие операции обновления таблицы, так как индекс не во всех случаях требует обновления. Пример 2.8.1 демонстрирует возможное применение данной идеи.

Пример 2.8.1. Настройка частичного индекса для исключения часто встречающихся значений

Предположим, что логи доступа веб-сервера хранятся в базе данных. Большинство обращений поступает из диапазона IP-адресов вашей организации, однако некоторые приходят извне (например, от сотрудников, использующих коммутируемое соединение). Если поиск по IP-адресу выполняется преимущественно для внешних запросов, вероятно, нет необходимости индексировать диапазон IP-адресов, соответствующий подсети вашей организации.

Рассмотрим таблицу следующей структуры:

CREATE TABLE access_log (
    url varchar,
    client_ip inet,
    ...
);

Чтобы создать частичный индекс для нашего примера, используйте команду, подобную следующей:

CREATE INDEX access_log_client_ip_ix ON access_log (client_ip)
WHERE NOT (client_ip > inet '192.168.100.0' AND
           client_ip < inet '192.168.100.255');

Пример типичного запроса, в котором может быть задействован этот индекс:

SELECT *
FROM access_log
WHERE url = '/index.html' AND client_ip = inet '212.78.10.32';

В данном случае IP-адрес из запроса охватывается частичным индексом. Следующий запрос не может использовать частичный индекс, так как в нем указан IP-адрес, исключенный из индекса:

SELECT *
FROM access_log
WHERE url = '/index.html' AND client_ip = inet '192.168.100.23';

Обратите внимание, что частичный индекс такого типа требует предварительного определения часто встречающихся значений, поэтому такие частичные индексы целесообразно использовать для распределений данных, которые остаются неизменными. Такие индексы можно периодически пересоздавать для адаптации к новому распределению данных, однако это требует дополнительных затрат на обслуживание.


Другой возможный вариант применения частичного индекса заключается в исключении из него тех значений, которые не востребованы при типичной рабочей нагрузке запросов; это показано в Пример 2.8.2. Это обеспечивает те же преимущества, что перечислены выше, однако предотвращает «не представляющих интереса» значений от доступа через этот индекс, даже если сканирование индекса могло бы быть эффективным в данном случае. Очевидно, что настройка частичных индексов для подобных сценариев потребует тщательного подхода и проведения экспериментов.

Пример 2.8.2. Настройка частичного индекса для исключения не представляющих интереса значений

Если в таблице содержатся как оплаченные, так и неоплаченные заказы, при этом неоплаченные заказы составляют лишь малую часть всей таблицы, но являются наиболее часто запрашиваемыми строками, можно повысить производительность, создав индекс только для неоплаченных строк. Команда для создания индекса будет выглядеть следующим образом:

CREATE INDEX orders_unbilled_index ON orders (order_nr)
    WHERE billed is not true;

Примером запроса, использующего данный индекс, может быть:

SELECT * FROM orders WHERE billed is not true AND order_nr < 10000;

Однако этот индекс может также использоваться в запросах, которые вообще не содержат order_nr например:

SELECT * FROM orders WHERE billed is not true AND amount > 5000.00;

Это не так эффективно, как использование частичного индекса по amount столбцу, поскольку системе придется сканировать весь индекс. Тем не менее, если неоплаченных заказов относительно немного, использование этого частичного индекса только для поиска неоплаченных заказов может повысить производительность.

Обратите внимание, что данный запрос не может использовать этот индекс:

SELECT * FROM orders WHERE order_nr = 3501;

Заказ под номером 3501 может находиться как среди оплаченных, так и среди неоплаченных заказов.


Пример 2.8.2 также демонстрирует, что индексируемый столбец и столбец, используемый в предикате, не обязательно должны совпадать. Digital Q.DataBase поддерживает частичные индексы с произвольными предикатами, при условии, что в них задействованы только столбцы индексируемой таблицы. Однако следует учитывать, что предикат должен соответствовать условиям в тех запросах, производительность которых должен повысить данный индекс. Точнее говоря, частичный индекс может быть использован в запросе только в том случае, если система определит, что WHERE условие запроса математически влечет за собой выполнение предиката индекса. Digital Q.DataBase не обладает развитым механизмом доказательства теорем, способным распознавать математически эквивалентные выражения, записанные в разных формах. (Мало того что разработка такого универсального механизма крайне сложна, он, вероятно, работал бы слишком медленно для практического применения.) Система может распознавать простые логические следствия из неравенств, например «x < 1» влечет «x < 2»; в противном случае условие предиката должно точно соответствовать части условия WHERE запроса, иначе индекс не будет идентифицирован как подходящий. Сопоставление выполняется на этапе планирования запроса, а не во время его выполнения. В результате параметризованные условия запроса не работают с частичным индексом. Например, подготовленный запрос с параметром может содержать условие «x < ?» которое никогда не будет логически следовать из условия «x < 2» для всех возможных значений параметра.

Третий возможный способ использования частичных индексов вообще не требует их применения в запросах. Идея заключается в том, чтобы создать уникальный индекс для подмножества таблицы, как в примере Пример 2.8.3. Это обеспечивает уникальность среди строк, удовлетворяющих предикату индекса, не накладывая ограничений на те строки, которые ему не соответствуют.

Пример 2.8.3. Настройка частичного уникального индекса

Предположим, имеется таблица, описывающая результаты тестирования. Необходимо гарантировать наличие только одной «успешной» записи для заданной комбинации столбцов subject и target, при этом может существовать любое количество «неуспешных» записей. Ниже приведен один из способов реализации:

CREATE TABLE tests (
    subject text,
    target text,
    success boolean,
    ...
);

CREATE UNIQUE INDEX tests_success_constraint ON tests (subject, target)
    WHERE success;

Этот подход особенно эффективен в тех случаях, когда количество успешных тестов невелико, а неуспешных — значительно. Также существует возможность разрешить наличие только одного значения NULL в столбце, создав уникальный частичный индекс с IS NULL ограничением.


Наконец, частичный индекс может применяться для переопределения выбора плана запроса, сделанного системой. Кроме того, наборы данных со специфическим распределением могут привести к тому, что система будет использовать индекс в тех случаях, когда этого делать не следует. В такой ситуации индекс можно настроить таким образом, чтобы он был недоступен для проблемного запроса. Как правило, Digital Q.DataBase принимает обоснованные решения относительно использования индексов (например, избегает их при извлечении часто встречающихся значений, поэтому приведенный ранее пример в действительности лишь экономит размер индекса, а не является обязательным для исключения его использования), и грубые ошибки при выборе плана являются поводом для составления отчета об ошибке.

Следует учитывать, что создание частичного индекса подразумевает наличие у вас как минимум того же объема информации, которым располагает планировщик запросов; в частности, вы понимаете, в каких случаях использование индекса будет целесообразным. Для накопления таких знаний требуются опыт и понимание того, как работают индексы в Digital Q.DataBase системе. В большинстве случаев преимущество частичного индекса перед обычным будет минимальным. Бывают ситуации, когда они крайне неэффективны, как в случае Пример 2.8.4.

Пример 2.8.4. Не используйте частичные индексы в качестве замены секционированию

У вас может возникнуть соблазн создать большой набор неперекрывающихся частичных индексов, например:

CREATE INDEX mytable_cat_1 ON mytable (data) WHERE category = 1;
CREATE INDEX mytable_cat_2 ON mytable (data) WHERE category = 2;
CREATE INDEX mytable_cat_3 ON mytable (data) WHERE category = 3;
...
CREATE INDEX mytable_cat_N ON mytable (data) WHERE category = N;

Это плохая идея! Почти наверняка будет лучше использовать один обычный индекс, объявленный следующим образом:

CREATE INDEX mytable_cat_data ON mytable (category, data);

(Поместите столбец category первым по причинам, описанным в Раздел 2.8.3.) Хотя поиск в таком индексе большего размера может потребовать прохождения через большее количество уровней дерева, чем поиск в индексе меньшего размера, это почти наверняка будет менее затратно, чем ресурсы планировщика запросов, необходимые для выбора подходящего частичного индекса. Основная проблема заключается в том, что система не понимает взаимосвязь между частичными индексами и будет последовательно проверять каждый из них на применимость к текущему запросу.

Если таблица настолько велика, что использование одного индекса является нецелесообразным, следует рассмотреть возможность использования секционирования (см. Раздел 2.2.12). При использовании этого механизма система учитывает, что таблицы и индексы не перекрываются, что позволяет достичь гораздо более высокой производительности.


Дополнительные сведения о частичных индексах приведены в [ston89b], [olson93], и [seshadri95].

Наверх
свяжитесь
с нами
контакты
Для прямой связи с нами вы можете использовать контакты ниже, либо оставить заявку через форму обратной связи, и мы обязательно свяжемся с вами

*поля обязательные к заполнению