Информация по оптимизации функций
По умолчанию функция — это просто «черный ящик», о поведении которого СУБД знает очень мало. Однако это означает, что запросы, вызывающие функцию, могут выполняться менее эффективно, чем могли бы. Существует возможность предоставить планировщику дополнительную информацию, которая поможет ему оптимизировать вызовы функций.
Некоторые основные факты передаются декларативными аннотациями в команде CREATE FUNCTION. Наиболее важным из них является категория изменчивости функции (IMMUTABLE, STABLE или VOLATILE); при определении функции следует уделять особое внимание тому, чтобы правильно указать эту категорию. Также необходимо задать характеристику безопасности параллельного исполнения (PARALLEL UNSAFE, PARALLEL RESTRICTED или PARALLEL SAFE), если вы рассчитываете использовать эту функцию в параллельных запросах. Кроме того, может быть полезно указать примерную стоимость выполнения функции и/или количество строк, которые должна вернуть функция, возвращающая множества. Однако декларативный способ указания этих двух фактов позволяет указывать только константное значение, а этого зачастую недостаточно.
Также есть возможность прикрепить вспомогательную функцию для планировщика к функции, вызываемой из SQL (для вспомогательной она будет целевой функцией), и таким образом передать информацию о целевой функции, которая слишком сложна, чтобы ее можно было представить декларативно. Вспомогательную функцию для планировщика следует писать на языке C/RUST (хотя язык целевых функций может быть другим), поэтому ее можно отнести к расширенным возможностям, которыми будет пользоваться сравнительно небольшое число людей.
Вспомогательная функция для планировщика должна иметь следующую сигнатуру SQL:
supportfn(internal) returns internal
Чтобы соединить ее с целевой функций, нужно при создании последней добавить предложение SUPPORT.
Далее мы в общих чертах рассмотрим, что могут делать вспомогательные функции для планировщика. Множество возможных запросов к вспомогательной функции является расширяемым, поэтому в будущем могут появиться и другие возможности.
Некоторые вызовы функций можно упростить при планировании, исходя из характеристик самой функции. Например, функцию int4mul(n, 1) можно упростить до просто n. Преобразование такого рода может выполнять вспомогательная функция для планировщика, обрабатывая запросы типа SupportRequestSimplify. Вспомогательная функция будет вызываться всякий раз, когда в дереве проанализированного запроса будет найдена ее целевая функция. Если вспомогательная функция обнаружит, что этот конкретный вызов можно упростить до какого-либо другого вида, она может сформировать и возвратить дерево запроса, представляющее уже это измененное выражение. Это автоматически работает и для операторов, основанных на этой функции, — в данном примере n * 1 также будет упрощено до n. (Но имейте в виду, что это просто пример; конкретно эту оптимизацию стандартный QHB на самом деле не производит.) Мы не гарантируем, что QHB никогда не вызовет целевую функцию в случаях, которые может упростить вспомогательная функция. Следует обеспечить строгую идентичность между упрощенным выражением и фактическим выполнением целевой функции.
Для целевых функций, возвращающих boolean, часто бывает полезно оценить процент строк, которые будут выбраны предложением WHERE при помощи этой функции. Эту оценку может выполнить вспомогательная функция, обрабатывающая запросы типа SupportRequestSelectivity.
Если время выполнения целевой функции сильно зависит от ее входных аргументов, имеет смысл предоставить ей переменную оценку затрат. Это можно сделать при помощи вспомогательной функции, обрабатывающей запросы типа SupportRequestCost.
Для целевых функций, возвращающих множества, часто бывает полезно предоставить переменную оценку числа строк, которые будут возвращены. Это можно сделать с помощью вспомогательной функции, обрабатывающей запросы типа SupportRequestRows.
Для целевых функций, возвращающих boolean, существует возможность преобразовать вызов функции, находящейся в WHERE, в предложение (или предложения) с индексируемыми операторами. Преобразованные предложения должны быть строго идентичны условию функции либо могут быть в некоторой степени менее строгими (то есть они могут принимать некоторые значения, которые не принимает функция с этим условием). В последнем случае условие индекса считается неполным; его можно использовать для поиска по индексу, но для каждой строки, возвращаемой этим индексом, должен выполняться вызов функции, чтобы проверить, удовлетворяет ли строка условию WHERE. Для создания таких условий вспомогательная функция должна обрабатывать запросы типа SupportRequestIndexCondition.