Работа с SQL и Apache Calcite#
Описание SQL-движка на основе Apache Calcite#
Внимание
Новый SQL-движок находится в статусе beta.
Начиная с версии 4.2130 DataGrid поставляется с новым SQL-движком, который основан на фреймворке Apache Calcite.
Apache Calcite — фреймворк динамического управления данными, который служит посредником между приложениями, одним или несколькими местами хранения данных и механизмами их обработки.
У текущего SQL-движка, основанного на H2, есть набор фундаментальных ограничений, которые связаны с исполнением SQL-запросов в распределенной среде. Новый движок позволяет обойти эти ограничения. Он использует инструменты Apache Calcite для планирования и обработки запросов и новый процесс для их исполнения.
Фазы выполнения запроса через Calcite:
Обработка:
Вход — строка самого запроса.
Выход — синтаксическое дерево (AST — Abstract Syntax Tree).
Валидация (семантический анализ):
Вход — синтаксическое дерево (AST) и метаданные. На данном этапе синтаксическое дерево проверяется на соответствие метаданным.
Выход — AST с привязкой к конкретным метаданным.
Построение логического плана запроса на основе AST:
Вход — AST.
Выход — логический план запроса (дерево реляционных операторов).
Оптимизация:
Вход — логический план запроса и статистика.
Выход — физический план запроса (дерево реляционных операторов с привязкой к конкретному способу выполнения запроса).
Выполнение:
Вход — физический план запроса.
Выход — результат выполнения (курсор).
Способы настройки SQL-движка на основе Apache Calcite#
Режим Standalone#
При запуске кластера в режиме Standalone перед запуском скрипта ignite.sh или ignite.bat переместите подкаталоги optional/ignite-calcite и optional/ignite-slf4j в каталог libs. В этом случае контент папки, в которой находится модуль, добавится в classpath.
Конфигурация Maven#
Если в проекте используются библиотеки DataGrid, добавьте в зависимости модуль ignite-calcite. В случае использования Maven добавьте следующую зависимость (замените параметр ${ignite.version} на необходимую версию DataGrid):
<dependency>
<groupId>org.apache.ignite</groupId>
<artifactId>ignite-calcite</artifactId>
<version>${ignite.version}</version>
</dependency>
Конфигурация SQL-движков#
Для включения SQL-движка на основе Apache Calcite укажите CalciteQueryEngineConfiguration в разделе SqlConfiguration.QueryEnginesConfiguration.
Пример конфигурации двух SQL-движков (H2 и Calcite), где движок по умолчанию — Calcite:
<bean class="org.apache.ignite.configuration.IgniteConfiguration">
<property name="sqlConfiguration">
<bean class="org.apache.ignite.configuration.SqlConfiguration">
<property name="queryEnginesConfiguration">
<list>
<bean class="org.apache.ignite.indexing.IndexingQueryEngineConfiguration">
<property name="default" value="false"/>
</bean>
<bean class="org.apache.ignite.calcite.CalciteQueryEngineConfiguration">
<property name="default" value="true"/>
</bean>
</list>
</property>
</bean>
</property>
...
</bean>
IgniteConfiguration cfg = new IgniteConfiguration().setSqlConfiguration(
new SqlConfiguration().setQueryEnginesConfiguration(
new IndexingQueryEngineConfiguration(),
new CalciteQueryEngineConfiguration().setDefault(true)
)
);
Исполнение запросов с указанием SQL-движка#
Обычно все запросы направляются в SQL-движок, который настроен по умолчанию. Если в queryEnginesConfiguration настроено более одного движка, можно указать один из них для исполнения отдельных запросов или всего подключения к базе данных.
JDBC#
Чтобы выбрать SQL-движок для JDBC-соединения, используйте параметр queryEngine.
Пример
jdbc:ignite:thin://xxx.x.x.x:10800?queryEngine=calcite
где queryEngine=calcite — используемый движок.
ODBC#
SQL-движок для ODBC-соединения можно настроить с помощью свойства QUERY_ENGINE.
Пример
[IGNITE_CALCITE]
DRIVER={Apache Ignite};
SERVER=xxx.x.x.x;
PORT=10800;
SCHEMA=PUBLIC;
QUERY_ENGINE=CALCITE
Подсказка QUERY_ENGINE#
Используйте подсказку (hint) QUERY_ENGINE, чтобы выбрать определенный движок для отдельных запросов:
SELECT /*+ QUERY_ENGINE('calcite') */ fld FROM table;
Плагин calcite-oracle-dialect-plugin#
Плагин calcite-oracle-dialect-plugin добавляет в SQL-движок, который основан на Apache Calcite, некоторые операторы из диалекта Oracle.
Конфигурация#
Способы конфигурации:
Добавьте новый плагин в конфигурацию серверного узла
<bean class="com.sbt.ignite.calcite.CalciteOracleDialectPluginProvider"/>:<property name="pluginProviders"> <list> <bean class="com.sbt.ignite.calcite.CalciteOracleDialectPluginProvider"/> </list> </property>Переместите библиотеку
ise-calcite-oracle-dialect-pluginиз поддиректорииlibs/optionalsв директориюlibs.
Дополните конфигурацию IgniteConfiguration:
IgniteConfiguration cfg = ...
cfg.setPluginProviders(new CalciteOracleDialectPluginProvider());
Пример успешного запуска плагина в лог-файле серверного узла
YYYY-MM-DD 10:43:12.223 [INFO ][main][org.apache.ignite.internal.processors.plugin.IgnitePluginProcessor] ^-- CALCITE_ORACLE_DIALECT_PROVIDER 1.0
YYYY-MM-DD 10:43:12.223 [INFO ][main][org.apache.ignite.internal.processors.plugin.IgnitePluginProcessor] ^-- null
YYYY-MM-DD 10:43:12.223 [INFO ][main][org.apache.ignite.internal.processors.plugin.IgnitePluginProcessor]
YYYY-MM-DD 10:43:12.224 [INFO ][main][org.apache.ignite.internal.processors.plugin.IgnitePluginProcessor] ^-- Check Parameters 1.0.0-SNAPSHOT
YYYY-MM-DD 10:43:12.224 [INFO ][main][org.apache.ignite.internal.processors.plugin.IgnitePluginProcessor] ^-- SberTech
YYYY-MM-DD 10:43:12.224 [INFO ][main][org.apache.ignite.internal.processors.plugin.IgnitePluginProcessor]
Операторы#
Плагин добавляет в SQL-движок операторы:
Арифметика между датами и числами (
DATE + NUMBER | NUMBER + DATE | DATE - NUMBER | TIMESTAMP + NUMBER | NUMBER + TIMESTAMP | TIMESTAMP - NUMBER). Для данного оператора числовой аргумент означает количество дней (в том числе с плавающей точкой).SUBSTR(STRING, NUMERIC, NUMERIC) / SUBSTR(STRING, NUMERIC)— аналогSUBSTRINGс теми же параметрами.TRUNC(d TIMESTAMP)— аналогFLOOR(d TO DAY).LTRIM(s STRING, c STRING)— аналогTRIM(LEADING c FROM s).RTRIM(s STRING, c STRING)— аналогTRIM(TRAILING c FROM s).NVL2(s STRING, a1 ANY, a2 ANY)— аналогCASE s IS NOT NULL THEN a1 ELSE a2 END.TO_NUMBER(STRING)— перевод строки в число.TO_CHAR(NUMBER, STRING)— перевод числа в строку с пользовательским форматом.INSTR(string STRING, seek STRING[, from INTEGER[, occurrence INTEGER]])— аналогPOSITION(seek, string, from, occurrence).REPLACE(a STRING, b STRING)— аналогREPLACE(a, b, ‘’).REGEXP_INSTR(STRING, STRING[, INTEGER[, INTEGER]])— поиск шаблона в строке по регулярному выражению.LPAD(STRING, NUMERIC[, STRING])/RPAD(STRING, NUMERIC[, STRING])— дополнение строки слева или справа до заданного размера.
Пользовательские SQL-функции#
Пользовательские SQL-функции — публичные статические методы, которые помечены аннотацией @QuerySqlFunction. SQL-движок позволяет добавлять пользовательские SQL-функции на Java в перечень SQL-функций, которые определены спецификацией ANSI-99.
Класс, в котором находится пользовательская SQL-функция, нужно зарегистрировать в конфигурации кеша (CacheConfiguration) с помощью метода setSqlFunctionClasses(...). При запуске кеша с указанной конфигурацией появится возможность вызова пользовательской функции внутри SQL-запросов.
Пользовательская SQL-функция может быть реализована в виде табличной функции (User-Defined Table Functions, UDTF). Результат табличной функции представлен в виде набора строк (таблицы), который доступен другим SQL-операторам. UDTF позволяет пользователям определять собственные табличные функции, которые могут возвращать наборы строк и использоваться в SQL-запросах как обычные таблицы.
Пример использования
SELECT * FROM TABLE(my_custom_function(param1, param2))
где my_custom_function — пользовательская табличная функция, которая принимает параметры param1 и param2 и возвращает результат в виде таблицы.
Пользовательская SQL-функция в виде табличной функции представлена как публичный метод с аннотацией @QuerySqlTableFunction. Метод должен возвращать объект типа Iterable, который состоит из набора строк. Каждая строка может быть представлена массивом объектов Object[] или коллекцией. Количество элементов в массиве или коллекции должно совпадать с количеством колонок, которые описаны в аннотации. Типы значений в строках должны совпадать с типами столбцов или допускать преобразование в соответствующие типы.
Аннотация должна описывать возвращаемые колонки и их типы данных.
Пример аннотации
@QuerySqlTableFunction(
alias = "persons",
columnNames = {"ID", "NAME", "SALARY"},
columnTypes = {Integer.class, String.class, Double.class}
)
public static Iterable<Object[]> persons() {
return List.of(
new Object[] {1, "Name 1", 100d},
new Object[] {2, "Name 2", 200d}
);
}
Примечание
В настоящее время табличные функции доступны только совместно с Apache Calcite.
Примечание
Классы, которые зарегистрированы с помощью метода CacheConfiguration.setSqlFunctionClasses(...), необходимо включить в classpath всех узлов, где могут быть запущены эти пользовательские функции. В противном случае при попытке их использования сгенерируется исключение ClassNotFoundException.
Пользовательские метки SQL-запросов#
В DataGrid при создании SQL-запроса можно опционально указать пользовательскую метку, которая будет отображаться в системных представлениях. Пользовательские метки могут облегчить последующий мониторинг и диагностику проблем.
Пользовательские метки (Id) указываются с помощью свойства setQueryInitiatorId в объекте SqlFieldsQuery. Список активных и выполненных запросов можно посмотреть с помощью системных представлений SQL_QUERIES_HISTORY и SQL_QUERIES.
Планировщик задач для блокировки запросов в Apache Calcite#
Архитектура SQL-движка Apache Calcite в DataGrid требует, чтобы задачи по одному и тому же запросу не могли выполняться конкурентно. Выполнение SQL-запроса и относящихся к нему задач привязывается к конкретному потоку из пула. Для привязки используется хеш-код идентификатора запроса. Если пользователь добавил собственную SQL-функцию (User-Defined Function, UDF), которая также выполняет некоторый SQL-запрос, это может привести к коллизиям при выборе потока и к взаимоблокировке (deadlock). Поток блокируется задачей, которая синхронно ждет выполнения нового SQL-запроса, а он не может быть выполнен, так как новый SQL-запрос по идентификатору запроса назначен на тот же поток.
Для решения этой проблемы в DataGrid добавлен новый исполнитель задач (task executor) — QueryBlockingTaskExecutor. Он основан на общей очереди задач для всех потоков, но за счет дополнительной синхронизации позволяет обеспечить гарантии, которые требуются SQL-движку при отсутствии конкуренции между задачами одного запроса. Это позволяет избежать взаимоблокировок при выполнении SQL-запросов внутри пользовательской функции.
Важно
Свойство IGNITE_CALCITE_USE_QUERY_BLOCKING_TASK_EXECUTOR позволяет переключить стандартный способ выполнения задач запросов StripedQueryTaskExecutor в Apache Calcite на общую очередь — QueryBlockingTaskExecutor.
Свойство IGNITE_CALCITE_USE_QUERY_BLOCKING_TASK_EXECUTOR позволяет вызывать запросы внутри пользовательских SQL-функций, но уменьшает производительность, поэтому включается опционально (значение по умолчанию — false, свойство выключено).
Пример создания пользовательской SQL-функции и SQL-запроса внутри нее
import java.io.File;
import java.util.Collections;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.Ignition;
import org.apache.ignite.cache.QueryEntity;
import org.apache.ignite.cache.query.SqlFieldsQuery;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.internal.processors.query.QuerySqlFunction;
import java.util.Collections;
import java.util.List;
public class IgniteUdfExample {
public static void main(String[] args) {
// Включите механизм выполнения задач `QueryBlockingTaskExecutor`.
System.setProperty("IGNITE_CALCITE_USE_QUERY_BLOCKING_TASK_EXECUTOR", "true");
Ignite ignite = Ignition.start();
IgniteUdfExample example = new IgniteUdfExample();
example.testInnerSql();
example.testUdfInSql();
}
// Создайте конфигурацию кеша.
public CacheConfiguration<Integer, Employer> cacheConfiguration() {
return new CacheConfiguration<Integer, Employer>()
.setName("emp4")
.setSqlFunctionClasses(UserDefinedSqlFunction.class)
.setSqlSchema("PUBLIC")
.setQueryEntities(Collections.singletonList(
new QueryEntity(Integer.class, Employer.class).setTableName("emp4")
));
}
// Создайте кеш и заполните его данными.
public void testInnerSql() {
IgniteCache<Integer, Employer> emp4 = ignite.getOrCreateCache(this.cacheConfiguration());
for (int i = 0; i < 100; i++) {
emp4.put(i, new Employer("Name" + i, (double) i));
}
}
public void testUdfInSql() {
// Создайте кеш.
IgniteCache<Integer, Employer> emp4 = ignite.getOrCreateCache(this.cacheConfiguration());
// Вызовите SQL-запрос внутри пользовательской SQL-функции.
SqlFieldsQuery sql = new SqlFieldsQuery("SELECT name, salary(?, key) FROM emp4 WHERE key = ?")
.setArgs("igniteInstanceName", 1);
List<List<?>> result = emp4.query(sql).getAll();
for (List<?> row : result) {
System.out.println("Name: " + row.get(0) + ", Salary: " + row.get(1));
}
}
// Создайте пользовательскую SQL-функцию.
public static class UserDefinedSqlFunction {
@QuerySqlFunction
public static double salary(String igniteInstanceName, int key) {
return (double) Ignition.ignite(igniteInstanceName)
.cache("emp4")
.query(new SqlFieldsQuery("SELECT salary FROM emp4 WHERE _key = ?").setArgs(key))
.getAll().get(0).get(0);
}
}
// Создайте класс `Employer` для хранения информации о сотрудниках.
public static class Employer {
private String name;
private double salary;
public Employer(String name, double salary) {
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
public double getSalary() {
return salary;
}
}
}
SQL с поддержкой транзакций и scan-запросы#
SQL с поддержкой транзакций и scan-запросы в настоящее время поддерживаются только для SQL-запросов на основе Apache Calcite и уровня изоляции READ_COMMITTED. Для обеспечения обратной совместимости поддержка транзакций по умолчанию отключена. Чтобы включить поддержку транзакций для SQL- и scan-запросов, установите свойство txAwareQueriesEnabled в конфигурации транзакций (TransactionConfiguration):
Пример конфигурации txAwareQueriesEnabled:
<bean class="org.apache.ignite.configuration.IgniteConfiguration">
<property name="transactionConfiguration">
<bean class="org.apache.ignite.configuration.TransactionConfiguration">
<property name="txAwareQueriesEnabled" value="true" />
...
</bean>
</property>
...
</bean>
IgniteConfiguration cfg = new IgniteConfiguration();
cfg.getTransactionConfiguration().setTxAwareQueriesEnabled(true);
API, которые поддерживают работу с транзакциями:
Key-Value API;
SQL-запросы, поступившие из SQL-движка на основе Apache Calcite;
scan-запросы (scan queries);
индексированные scan-запросы (index scan query).
Поддержка работы с транзакциями означает, что:
ACID-свойства будут соблюдаться на уровне Key-Value API.
Измененные или удаленные в рамках транзакции данные не видны другим параллельным транзакциям до момента коммита данной транзакции.
Данные, которые изменили/вставили на предыдущих шагах в рамках одной транзакции, будут видны на последующих шагах в этой транзакции.
Поэтому при включении txAwareQueriesEnabled = true можно:
использовать операторы
INSERT,UPDATEиDELETEс обычными транзакционными гарантиями;комбинировать Key-Value-, SQL- и scan-запросы для последующей транзакционной обработки данных.
Примечание
В настоящее время операторы UPDATE и SELECT не содержат блокировок. Оператор SELECT ... FOR UPDATE не поддерживается. Это означает, что при одновременном изменении одного и того же ключа в нескольких транзакциях возможно появление lost-update anomaly (аномалии потерянного обновления).
Например, при выполнении запроса вида SET salary = salary + 50 WHERE id = 1 одновременно в нескольких потоках может возникнуть lost-update anomaly. При корректном выполнении запроса значение salary должно быть равно сумме исходной зарплаты, увеличенной на 50 единиц для каждого задействованного потока. Но из-за lost-update anomaly итоговый результат может быть неверным: сумма salary не увеличится на 50 единиц для каждого потока.
try (Transaction tx = srv.transactions().txStart(PESSIMISTIC, READ_COMMITTED)) {
cache.put(1, 2);
List<List<?>> sqlData = cache.query(new SqlFieldsQuery("SELECT COUNT(*) FROM TBL"));
assertEquals("Must see transaction related data", 1L, sqlData.get(0).get(0));
assertEquals("Must see transaction related data", 1, scanData.size());
tx.commit();
}
Проверка соответствия данных схеме#
DataGrid позволяет проверить, соответствуют ли вставленные в таблицу значения типам столбцов и ограничениям, которые заявлены в ее SQL-схеме. По умолчанию DataGrid выполняет такие проверки только для индексированных столбцов. Чтобы проверить все столбцы, включите проверку на стороне сервера на каждом узле перед его запуском:
SqlConfiguration sqlCfg = new SqlConfiguration()
.setValidationEnabled(true);
IgniteConfiguration cfg = new IgniteConfiguration()
.setSqlConfiguration(sqlCfg);
<property name="sqlConfiguration">
<bean class="org.apache.ignite.configuration.SqlConfiguration">
<property name="validationEnabled" value="true"/>
</bean>
</property>
Когда опция SqlConfiguration#validationEnabled включена, DataGrid:
Выполняет дополнительные проверки для каждого SQL-запроса типа
INSERT,MERGEиUPDATEи для API-вызовов, которые изменяют управляемые с помощью SQL-запросов таблицы.Отклоняет данные, которые нарушают SQL-схему.
Для SQL-клиентов (JDBC, ODBC, REST) нарушения схемы приводят к генерации исключения IgniteSQLException, а для вызовов Key-Value API — CacheException (корнем этого исключения также является IgniteSQLException). В обоих случаях приложение может обработать ошибку, и некорректные данные не будут сохранены.
Операции SQL DML пытаются привести типы значений к указанным в таблице, поэтому несоответствия типов обычно появляются при записи данных с помощью кеш-API или бинарных объектов:
// CREATE TABLE Person (id INT PRIMARY KEY, age INT);
IgniteCache<Integer, BinaryObject> cache = ignite.cache("SQL_PUBLIC_PERSON").withKeepBinary();
BinaryObject invalidPerson = ignite.binary().builder("Person")
.setField("id", 2)
.setField("age", "forty-two") // Строка (String) вместо столбца типа int.
.build();
cache.put(2, invalidPerson); // Исключение `CacheException`, внутри которого при включенной проверке находится исключение `IgniteSQLException`.
С настройками по умолчанию (при отключенной для неиндексированных столбцов проверке соответствия) команда put из примера выше будет успешно выполнена, хотя хранимый BinaryObject не соответствует SQL-схеме. При включенной проверке DataGrid отклонит обновление и защитит таблицу от появления искаженных данных.
Используйте опцию проверки соответствия данных схеме SqlConfiguration#validationEnabled, когда требуются более надежные гарантии, что динамические или предоставленные пользователем данные не нарушат определение таблицы. Если затраты на дополнительные проверки перевешивают риск некорректных данных, отключите проверку.
Справочник по SQL#
DDL#
DDL-команды (Data Definition Language, язык описания данных) совместимы со старым движком на основе H2. Подробнее об этом написано в официальной документации Apache Ignite.
DML#
Новый SQL-движок в основном наследует синтаксис DML (Data Manipulation Language, язык манипулирования данными) от фреймворка Apache Calcite.
В большинстве случаев синтаксис команд совместим со старым SQL-движком, но есть некоторые отличия между DML-диалектами в движках на основе H2 и Calcite. Например, изменился синтаксис команды MERGE. Подробнее об этом написано в SQL-справочнике Apache Calcite.
Поддерживаемые функции#
SQL-движок на основе Calcite на данный момент поддерживает пользовательские функции и операторы, которые описаны ниже.
Агрегатные функции:
Имя |
Синтаксис |
Описание |
|---|---|---|
|
|
Возвращает количество входных строк или ненулевых ( |
|
|
Возвращает сумму числовых входных значений |
|
|
Возвращает среднее значение числовых входных значений |
|
|
Возвращает минимальное входное значение |
|
|
Возвращает максимальное входное значение |
|
|
Возвращает одно произвольное входное значение |
|
|
Объединяет значения из группы в заданном порядке |
|
|
Объединяет значения из группы, опционально используя разделитель и сортировку |
|
|
Объединяет строковые значения из группы с помощью разделителя |
|
|
Собирает входные значения в массив |
|
|
Объединяет массивы из входных строк в один массив |
|
|
Возвращает значение |
|
|
Возвращает значение |
|
|
Агрегирует целые числа с помощью побитового |
|
|
Агрегирует целые числа с помощью побитового |
|
|
Агрегирует целые числа с помощью побитового |
Конструкция |
|
Применяет агрегатную функцию только к тем входным строкам, которые удовлетворяют условию |
Строковые функции и предикаты:
Имя |
Синтаксис |
Описание |
|---|---|---|
|
|
Преобразует строку в верхний регистр |
|
|
Преобразует строку в нижний регистр |
|
|
Преобразует каждое слово так, чтобы первая буква была заглавной, а остальные — строчными |
|
|
Кодирует строку в формате Base64 |
|
|
Декодирует строку из формата Base64 |
|
|
Возвращает |
|
|
Возвращает |
|
|
Возвращает подстроку, начиная с указанной позиции |
|
|
Возвращает указанное количество символов с левого края строки |
|
|
Возвращает указанное количество символов с правого края строки |
|
|
Заменяет все вхождения искомой строки на указанную строку |
|
|
Заменяет символы из одного набора соответствующими символами из другого набора |
|
|
Возвращает символ, который соответствует указанному коду (code point) |
|
|
Возвращает количество символов в строке |
|
|
Эквивалентно |
|
|
Псевдоним для функции |
|
|
Объединяет две строки |
|
|
Объединяет строки |
|
|
Заменяет часть строки другой строкой |
|
|
Возвращает позицию первого вхождения подстроки |
|
|
Возвращает код первого символа строки |
|
|
Возвращает строку, которая повторяется указанное количество раз |
|
|
Возвращает строку, которая состоит из указанного количества пробелов |
|
|
Сравнивает две строки и возвращает результат сравнения в виде целого числа |
|
|
Возвращает фонетическое представление строки |
|
|
Возвращает оценку сходства значений |
|
|
Возвращает строку с символами в обратном порядке |
|
|
Удаляет символы из начала, конца или с обеих сторон строки |
|
|
Удаляет пробелы в начале строки |
|
|
Удаляет пробелы в конце строки |
|
|
Проверяет, соответствует ли строка SQL-шаблону |
|
|
Проверяет, соответствует ли строка шаблону регулярного выражения SQL |
Функции и операторы регулярных выражений:
Имя |
Синтаксис |
Описание |
|---|---|---|
|
|
Проверяет, соответствует ли строка регулярному выражению |
|
|
Проверяет, соответствует ли строка регулярному выражению |
|
|
Проверяет, что строка не соответствует регулярному выражению |
|
|
Проверяет, что строка не соответствует регулярному выражению |
|
|
Заменяет подстроки, которые соответствуют регулярному выражению |
|
|
Возвращает подстроку, которая соответствует регулярному выражению |
Числовые и математические функции:
Имя |
Синтаксис |
Описание |
|---|---|---|
|
|
Возвращает остаток от деления |
|
|
Возвращает результат побитовой операции |
|
|
Возвращает результат побитовой операции |
|
|
Возвращает результат побитовой операции |
|
|
Возвращает число Эйлера, возведенное в указанную степень |
|
|
Возвращает число, возведенное в степень другого числа |
|
|
Возвращает натуральный логарифм |
|
|
Возвращает десятичный логарифм |
|
|
Возвращает абсолютное значение (модуль числа) |
|
|
Возвращает случайное значение типа double |
|
|
Возвращает случайное целое число от |
|
|
Возвращает арккосинус |
|
|
Возвращает обратный гиперболический косинус |
|
|
Возвращает арксинус |
|
|
Возвращает обратный гиперболический синус |
|
|
Возвращает арктангенс |
|
|
Возвращает обратный гиперболический тангенс |
|
|
Возвращает угол, который был вычислен по прямоугольным координатам |
|
|
Возвращает квадратный корень |
|
|
Возвращает кубический корень |
|
|
Возвращает косинус |
|
|
Возвращает гиперболический косинус |
|
|
Возвращает котангенс |
|
|
Возвращает гиперболический котангенс |
|
|
Преобразует радианы в градусы |
|
|
Преобразует градусы в радианы |
|
|
Округляет число до указанной точности (scale) |
|
|
Возвращает знак числового значения |
|
|
Возвращает синус |
|
|
Возвращает гиперболический синус |
|
|
Возвращает тангенс |
|
|
Возвращает гиперболический тангенс |
|
|
Возвращает секанс |
|
|
Возвращает гиперболический секанс |
|
|
Возвращает косеканс |
|
|
Возвращает гиперболический косеканс |
|
|
Отсекает дробную часть числа до указанной точности (scale) |
|
|
Возвращает приближенное значение числа пи |
Функции даты и времени:
Имя |
Синтаксис |
Описание |
|---|---|---|
|
|
Возвращает указанное поле из значения даты, времени или временной метки (timestamp) |
|
|
Округляет значение даты, времени или временной метки в меньшую сторону до указанной единицы |
|
|
Округляет значение даты, времени или временной метки в большую сторону до указанной единицы |
|
|
Добавляет интервал к временной метке |
|
|
Возвращает количество границ указанных единиц времени между двумя значениями |
|
|
Возвращает дату последнего дня месяца |
|
|
Возвращает название дня недели |
|
|
Возвращает название месяца |
|
|
Возвращает день месяца |
|
|
Возвращает день недели |
|
|
Возвращает день года |
|
|
Возвращает год |
|
|
Возвращает квартал года |
|
|
Возвращает номер месяца |
|
|
Возвращает номер недели |
|
|
Возвращает час |
|
|
Возвращает минуту |
|
|
Возвращает секунду |
|
|
Преобразует количество секунд с 00:00:00 01.01.1970 во временную метку |
|
|
Преобразует количество миллисекунд с 00:00:00 01.01.1970 во временную метку |
|
|
Преобразует количество микросекунд с 00:00:00 01.01.1970 во временную метку |
|
|
Возвращает количество секунд с 00:00:00 01.01.1970 |
|
|
Возвращает количество миллисекунд с 00:00:00 01.01.1970 |
|
|
Возвращает количество микросекунд с 00:00:00 01.01.1970 |
|
|
Возвращает количество дней с 01.01.1970 |
|
|
Преобразует количество дней с 01.01.1970 в дату |
|
|
Преобразует значение в дату или создает дату из отдельных полей |
|
|
Преобразует значение в время или создает время из отдельных полей |
|
|
Преобразует значение во временную метку или создает ее из полей даты и времени |
|
|
Возвращает текущее время |
|
|
Возвращает текущую временную метку |
|
|
Возвращает текущую дату |
|
|
Возвращает текущее местное время |
|
|
Возвращает текущую местную временную метку |
JDBC-функции для экранирования текущего времени |
|
JDBC-псевдонимы экранирования для текущих даты, времени и временной метки |
|
|
Форматирует значение даты, времени или временной метки |
|
|
Преобразует строку в дату |
|
|
Преобразует строку во временную метку |
XML-функции:
Имя |
Синтаксис |
Описание |
|---|---|---|
|
|
Возвращает текст, который был выбран с помощью выражения |
|
|
Преобразует XML с помощью таблицы стилей XSLT |
|
|
Возвращает фрагмент XML, который был выбран с помощью выражения |
|
|
Возвращает значение |
JSON-функции и предикаты:
Имя |
Синтаксис |
Описание |
|---|---|---|
|
|
Помечает значение как входные данные в JSON-формате |
|
|
Извлекает скалярное значение SQL из JSON с помощью выражения JSON-пути |
|
|
Извлекает JSON-объект или массив из JSON с помощью выражения JSON-пути |
|
|
Возвращает тип значения JSON |
|
|
Возвращает значение |
|
|
Возвращает глубину вложенности значения JSON |
|
|
Возвращает ключи JSON-объекта |
|
|
Возвращает JSON с форматированием (в удобочитаемом виде) |
|
|
Возвращает длину значения JSON |
|
|
Удаляет данные, которые были выбраны выражениями путей, и возвращает обновленный JSON |
|
|
Возвращает количество байт, которые используются бинарным представлением JSON |
|
|
Создает JSON-объект из пар «ключ-значение» |
|
|
Создает JSON-массив из значений |
|
|
Проверяет, является ли значение JSON или нет |
|
|
Проверяет, является ли значение JSON-объектом или нет |
|
|
Проверяет, является ли значение JSON-массивом или нет |
|
|
Проверяет, является ли значение скалярным значением JSON или нет |
Функции и операторы коллекций:
Имя |
Синтаксис |
Описание |
|---|---|---|
|
|
Создает массив из значений или из результата запроса |
|
|
Создает карту (map) из пар «ключ-значение» или из результата запроса |
|
|
Возвращает элемент из массива или карты |
|
|
Возвращает количество элементов в коллекции |
|
|
Проверяет, является ли коллекция пустой (не содержит элементов) |
|
|
Проверяет, содержит ли коллекция хотя бы один элемент |
Другие функции и операторы:
Имя |
Синтаксис |
Описание |
|---|---|---|
|
|
Создает строковое значение |
|
|
Преобразует значение в указанный тип |
|
|
Преобразует значение в указанный тип с помощью синтаксиса приведения PostgreSQL |
|
|
Возвращает тип значения в DataGrid SQL |
|
|
Возвращает первое значение из списка, которое не является |
|
|
Возвращает значение |
|
|
Возвращает |
|
|
Возвращает результат, который был выбран на основе условий ветвления |
|
|
Сравнивает значение с искомыми значениями и возвращает соответствующий результат |
|
|
Возвращает наименьшее значение из переданных аргументов |
|
|
Возвращает наибольшее значение из переданных аргументов |
|
|
Сжимает строку и возвращает данные в бинарном виде |
|
|
Возвращает количество байт в бинарных данных |
|
|
Возвращает имя движка запросов, который используется для выполнения данного запроса |
|
|
Возвращает таблицу с одним столбцом |
Поддерживаемые типы данных#
Типы данных, которые поддерживает SQL-движок на основе Calcite:
Тип данных |
Java-класс |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Оптимизация запросов с помощью подсказок#
Оптимизатор запросов пытается построить самый быстрый план выполнения, но это возможно сделать не для всех случаев. Пользователь больше знает о структуре данных, архитектуре приложения и распределении данных в кластере. Чтобы сделать оптимизацию более рациональной и быстрее построить план выполнения запросов, можно использовать подсказки (hints) SQL.
Примечание
Подсказки SQL не обязательно использовать, в некоторых случаях их можно пропустить.
Формат подсказок#
Подсказки SQL задаются специальным комментарием /*+ HINT */, который называется блоком подсказок. Пробелы до и после названия подсказки обязательны. Блок подсказок размещается сразу после реляционного оператора, обычно после SELECT. Несколько блоков для одного реляционного оператора использовать нельзя.
Пример
SELECT /*+ NO_INDEX */ T1.* FROM TBL1 where T1.V1=? and T1.V2=?
Допускается задавать несколько подсказок для одного реляционного оператора. Для этого разделите их запятыми (пробелы необязательны).
Пример
SELECT /*+ NO_INDEX, EXPAND_DISTINCT_AGG */ SUM(DISTINCT V1), AVG(DISTINCT V2) FROM TBL1 GROUP BY V3 WHERE V3=?
Параметры подсказок#
Если требуются параметры подсказок, поместите их в скобки после названия подсказки и разделите запятыми.
Параметры можно заключать в кавычки — они становятся чувствительными к регистру. Параметры с кавычками и без них нельзя определить для одной и той же подсказки.
Пример
SELECT /*+ FORCE_INDEX(TBL1_IDX2,TBL2_IDX1) */ T1.V1, T2.V1 FROM TBL1 T1, TBL2 T2 WHERE T1.V1 = T2.V1 AND T1.V2 > ? AND T2.V2 > ?;
SELECT /*+ FORCE_INDEX('TBL2_idx1') */ T1.V1, T2.V1 FROM TBL1 T1, TBL2 T2 WHERE T1.V1 = T2.V1 AND T1.V2 > ? AND T2.V2 > ?;
Области видимости подсказок#
Подсказки определяются для реляционного оператора, обычно для SELECT.
Большинство подсказок видны своим реляционным операторам, последующим операторам, запросам и подзапросам. Определенные в подзапросе подсказки видны только ему самому и его подзапросам. Подсказку не видно предыдущему реляционному оператору, если ее определили после него.
Пример
SELECT /*+ NO_INDEX(TBL1_IDX2), FORCE_INDEX(TBL2_IDX2) */ T1.V1 FROM TBL1 T1 WHERE T1.V2 IN (SELECT T2.V2 FROM TBL2 T2 WHERE T2.V1=? AND T2.V2=?);
SELECT T1.V1 FROM TBL1 T1 WHERE T1.V2 IN (SELECT /*+ FORCE_INDEX(TBL2_IDX2) */ T2.V2 FROM TBL2 T2 WHERE T2.V1=? AND T2.V2=?);
В примере ниже подсказка есть только у первого запроса:
SELECT /*+ FORCE_INDEX */ V1 FROM TBL1 WHERE V1=? AND V2=?
UNION ALL
SELECT V1 FROM TBL1 WHERE V3>?
Исключение: подсказки уровня движка или оптимизатора, например DISABLE_RULE и QUERY_ENGINE, нужно определять в начале запроса. Они относятся ко всему запросу.
Ошибки в подсказках#
Оптимизатор пытается применить каждую подсказку и ее параметры, если это возможно. Он пропускает подсказку или параметр, если:
такой подсказки не существует или она не поддерживается;
не передали необходимые для подсказки параметры;
параметры подсказки передали, но она их не поддерживает;
параметр подсказки некорректен или ссылается на несуществующий объект (например, индекс или таблицу);
текущая подсказка или ее параметры несовместимы с предыдущими, например принудительное использование и отключение одного и того же индекса.
Поддерживаемые подсказки#
FORCE_INDEX#
Принудительно использует индексы для сканирования таблиц.
Параметры:
Пусто — принудительно использует индексы для сканирования таблиц. Оптимизатор выберет любой доступный индекс.
Одно название индекса — оптимизатор использует указанный индекс.
Несколько названий индексов (могут относиться к разным таблицам) — оптимизатор выберет указанные индексы при сканировании.
Пример
SELECT /*+ FORCE_INDEX */ T1.* FROM TBL1 T1 WHERE T1.V1 = T2.V1 AND T1.V2 > ?;
SELECT /*+ FORCE_INDEX(TBL1_IDX2, TBL2_IDX1) */ T1.V1, T2.V1 FROM TBL1 T1, TBL2 T2 WHERE T1.V1 = T2.V1 AND T1.V2 > ? AND T2.V2 > ?;
NO_INDEX#
Отключает сканирование индексов.
Параметры:
Пусто — не использовать индексы при сканировании таблиц. Оптимизатор отключит все индексы.
Одно название индекса — оптимизатор пропустит указанный индекс.
Несколько названий индексов (могут относиться к разным таблицам) — оптимизатор пропустит указанные индексы при сканировании.
Пример
SELECT /*+ NO_INDEX */ T1.* FROM TBL1 T1 WHERE T1.V1 = T2.V1 AND T1.V2 > ?;
SELECT /*+ NO_INDEX(TBL1_IDX2, TBL2_IDX1) */ T1.V1, T2.V1 FROM TBL1 T1, TBL2 T2 WHERE T1.V1 = T2.V1 AND T1.V2 > ? AND T2.V2 > ?;
ENFORCE_JOIN_ORDER#
Устанавливает порядок соединений (JOIN), который указан в запросе. Оптимизатор не будет пытаться изменить порядок исполнения. Позволяет ускорить построение плана запроса с большим количеством соединений.
Пример
SELECT /*+ ENFORCE_JOIN_ORDER */ T1.V1, T2.V1, T2.V2, T3.V1, T3.V2, T3.V3 FROM TBL1 T1 JOIN TBL2 T2 ON T1.V3=T2.V1 JOIN TBL3 T3 ON T2.V3=T3.V1 AND T2.V2=T3.V2
SELECT t1.v1, t3.v2 FROM TBL1 t1 JOIN TBL3 t3 on t1.v3=t3.v3 WHERE t1.v2 in (SELECT /*+ ENFORCE_JOIN_ORDER */ t2.v2 FROM TBL2 t2 JOIN TBL3 t3 ON t2.v1=t3.v1)
EXPAND_DISTINCT_AGG#
Принудительно разворачивает несколько операций агрегирования с ключевым словом DISTINCT через соединения (JOIN). Удаляет дубликаты перед объединением (JOIN) и ускоряет его.
Пример
SELECT /*+ EXPAND_DISTINCT_AGG */ SUM(DISTINCT V1), AVG(DISTINCT V2) FROM TBL1 GROUP BY V3
QUERY_ENGINE#
Выбирает конкретный движок для выполнения отдельных запросов. Указание на уровне движка.
Параметры:
Требуется один параметр — название движка.
Пример
SELECT /*+ QUERY_ENGINE('calcite') */ V1 FROM TBL1
DISABLE_RULE#
Отключает определенные правила оптимизатора. Указание на уровне оптимизатора.
Параметры:
Одно или несколько правил оптимизатора для пропуска.
Пример
SELECT /*+ DISABLE_RULE('MergeJoinConverter') */ T1.* FROM TBL1 T1 JOIN TBL2 T2 ON T1.V1=T2.V1 WHERE T2.V2=?