Перейти к содержанию

Как выполнять AQL

Запросы AQL можно выполнить с помощью:

  • веб-интерфейса,
  • Объект db (либо в Arangosh, либо в сервисе Foxx),
  • HTTP API.

В API сервера всегда есть вызовы API сервера, но веб-интерфейс и объект db абстрагируют детали связи низкого уровня и, таким образом, проще в использовании.

Веб-интерфейс ArangoDB имеет конкретную вкладку для выполнения AQL запросов.

Вы можете запустить запросы AQL из оболочки ArangoDB с помощью методов _query и _createStatement объекта db. В этой главе также описывается, как использовать параметры привязки, статистику, подсчет и курсоры с Arangosh.

Если вы используете FOXX, посмотрите, как написать запросы базы данных для примеров, включая тегированные шаблонные строки.

Если вы хотите запустить AQL-запросы из вашего приложения через HTTP REST API, см. Полное описание API на интерфейсе HTTP для курсоров AQL Query.

Выполнение запросов в arangosh

В оболочке ArangoDB вы можете использовать методы db._query() и db._createStatement() для выполнения запросов AQL. В этой главе также описывается, как использовать параметры, подсчет, статистику и курсоры.

db._query()

1
db._query(<queryString>) → cursor

Вы можете выполнить запросы с помощью метода _query() объекта db. Он выполняет указанный запрос в контексте выбранной в настоящее время базы данных и возвращает запрос результатов в курсор. Вы можете вывести результаты курсора, используя метод toArray():

1
2
3
arangosh> db._create("mycollection")
arangosh> db.mycollection.save({ _key: "testKey", Hello : "World" })
arangosh> db._query('FOR my IN mycollection RETURN my._key').toArray()
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[ArangoCollection 211, "mycollection" (type document, status loaded)]
{
    "_id" : "mycollection/testKey",
    "_key" : "testKey",
    "_rev" : "_fdPDVVO--_"
}

[
    "testKey"
]

db._query() параметры

1
db._query(<queryString>, <bindVars>) → cursor

Чтобы перенести параметры связывания в запрос, вы можете указать второй аргумент при вызове метода _query():

1
2
3
4
5
arangosh> db._query('FOR c IN @@collection FILTER c._key == @key RETURN c._key',
    {
       '@collection': 'mycollection',
       'key': 'testKey'
    }).toArray();
1
2
3
[
    "testKey"
]

ES6 шаблонные строки

1
aql`<queryTemplateString>`

Также возможно использовать строки шаблонов ES6 для генерации запросов AQL. Названная функция генератора строк шаблона с именем aql.

В следующем примере демонстрируется, что генерирует функция шаблонной строки:

1
2
arangosh> var key = 'testKey';
arangosh> aql`FOR c IN mycollection FILTER c._key == ${key} RETURN c._key`
1
2
3
4
5
6
7
{
    "query" : "FOR c IN mycollection FILTER c._key == @value0 RETURN c._key",
    "bindVars" : {
        "value0" : "testKey"
    },
    "_source" : () { ... }
}

Следующий пример напрямую использует сгенерированный результат для выполнения запроса:

1
2
3
4
arangosh> var key = 'testKey';
arangosh> db._query(
........> aql`FOR c IN mycollection FILTER c._key == ${key} RETURN c._key`
........> ).toArray();
1
2
3
[
"testKey"
]

Произвольные выражения JavaScript можно использовать в запросах, которые генерируются с помощью aql шаблонной строки. Объекты коллекции обрабатываются автоматически:

1
2
arangosh> var key = 'testKey';
arangosh> db._query(aql`FOR doc IN ${ db.mycollection } RETURN doc`).toArray();

Примечание: модифицирующие AQL запросы обычно не возвращают результат, если не указать оператор RETURN на верхнем уровне. Без оператора RETURN, метод toArray() вернет пустой массив.

Статистика и дополнительная информация

1
cursor.getExtra() → queryInfo

Всегда можно получить статистику для запроса с помощью метода getExtra():

1
2
3
arangosh> db._query(`FOR i IN 1..100
........>   INSERT { _key: CONCAT('test', TO_STRING(i)) } INTO mycollection`
........> ).getExtra();

Значение параметров статистики описано в статистике запросов.

Предупреждения запроса также сообщаются здесь. Если вы проектируете запросы на оболочке, обязательно проверьте предупреждения.

Основные параметры запроса

1
db._query(<queryString>, <bindVars>, <mainOptions>, <subOptions>) → cursor

Вы можете передать основные параметры в качестве третьего аргумента в db._query(). Если вы также передаете четвертый аргумент subOptions , то третий может быть пустым объектом {}.

count

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

Если включено, вы можете получить количество, вызывая метод count() курсора. Вы также можете подсчитать количество результатов на стороне клиента, например, с использованием cursor.toArray().length.

1
2
3
4
5
6
7
8
arangosh> var cursor = db._query(
........>   'FOR i IN 1..42 RETURN i',
........>   {},
........>   { count: true },
........>   {}
........> );
arangosh> cursor.count();
arangosh> cursor.toArray().length;
1
2
42
42

batchSize

Максимальное количество документов результатов, которые будут переданы с сервера на клиент за одну обработку. Если этот атрибут не установлен, используется значение по умолчанию, контролируемое сервером. Значение batchsize = 0 не разрешено.

1
2
3
4
5
6
arangosh> db._query(
........>   'FOR i IN 1..3 RETURN i',
........>   {},
........>   { batchSize: 2 },
........>   {}
........> ).toArray(); // full result retrieved in two batches
1
2
3
4
5
[
  1,
  2,
  3
]

ttl

Время для курсора (в секунды). Если набор результатов достаточно мал (меньше или равен batchsize), то результаты возвращаются сразу. В противном случае они хранятся в памяти и доступны через курсор относительно ttl. Курсор автоматически удаляется на сервере после указанного количества времени. Это полезно для обеспечения сбора мусора курсоров, которые не полностью извлечены клиентами. Если не установлено, используется серверное значение (по умолчанию: 30 секунд).

1
2
3
4
5
6
arangosh> db._query(
........>   'FOR i IN 1..2000 RETURN i',
........>   {},
........>   { ttl: 5 },
........>   {}
........> ).toArray(); // Each batch needs to be fetched within 5 seconds

cache

Должен ли использоваться кэш результатов AQL. Если установить на false, то любой поиск в кэше запросов пропускается. Если установить на true, он приводит к тому, что кэш запроса проверяется на запрос, если режим кэша запроса установлен на on или demand.

1
2
3
4
5
6
arangosh> db._query(
........> 'FOR i IN 1..2000 RETURN i',
........> {},
........> { cache: true },
........> {}
........> ).toArray(); // result may get taken from cache

memoryLimit

Чтобы установить предел памяти для запроса, установите options в методе _query(). Предел памяти определяет максимальное количество байтов, которое разрешено использовать запросу. Когда один запрос AQL достигает указанного предельного значения, запрос будет прерван с исключением превышен лимит ресурсов. В кластере учет памяти выполняется для шарда, поэтому предельное значение фактически является пределом памяти на запрос на шард.

1
2
3
4
5
arangosh> db._query(
........> 'FOR i IN 1..100000 SORT i RETURN i',
........> {},
........> { memoryLimit: 100000 }
........> ).toArray();
1
2
[ArangoError 32: AQL: query would use more memory than allowed
(while executing)]

Если предел памяти не указан, то значение по умолчанию сервера (управляемое с помощью параметра запуска --query.memory-limit) используется для ограничения максимального объема памяти, которую может использовать запрос. Значение предела памяти 0 означает, что максимальное количество памяти для запроса не ограничено.

Дополнительные параметры запроса

1
2
3
db._query(<queryString>, <bindVars>, <subOptions>) → cursor

db._query(<queryString>, <bindVars>, <mainOptions>, <subOptions>) → cursor

Вы можете передать дополнительные опции в качестве третьего аргумента db._query(), если вы не предоставляете основные опции, или в качестве четвертого аргумента, если вы это сделаете.

fullCount

Если вы установите для fullCount значение true и если запрос содержит операцию LIMIT, то результат будет иметь дополнительный атрибут со stats вложенных атрибутов и fullCount, например { ... , "extra": { "stats": { "fullCount" : 123 } } }.

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

failOnWarning

Если вы установите для параметра failOnWarning значение true, запрос выдаст исключение и прервется в случае появления предупреждения. Вы должны использовать эту опцию в разработке, чтобы выявлять ошибки на ранней стадии. Если установлено значение false, предупреждения не распространяются на исключения и возвращаются вместе с результатами запроса. Также есть параметры запуска --query.fail-on-warning для установки значения по умолчанию для failOnWarning, поэтому вам не нужно устанавливать его на уровне каждого запроса.

cache

Если для параметра cache установлено значение true, это помещает результат запроса в кэш результатов запроса, если результат запроса подходит для кэширования и кэш запросов работает в режиме запроса. Если установлено значение false, результат запроса не вставляется в кэш результатов запроса. Обратите внимание, что результаты запроса никогда не вставляются в кэш результатов запроса, если кэш результатов запроса отключен, и что они автоматически вставляются в кэш результатов запроса, если он активен в режиме без запроса.

fillBlockCache

Если вы установите для fillBlockCache значение true или не укажете его, запрос сохранит данные, которые он считывает через механизм хранения RocksDB, в блочном кеше RocksDB. Обычно это желаемое поведение. Вы можете установить для параметра значение false для запросов, которые, как известно, либо считывают много данных, которые могут привести к перегрузке блочного кэша, либо для запросов, которые считывают данные, которые, как известно, находятся за пределами горячего набора. Установив для параметра значение false, данные, считанные запросом, не попадают в кеш блоков RocksDB, если они еще не находятся там, что оставляет больше места для фактического горячего набора.

profile

Если вы установите для profile значение true или 1, для запроса будет возвращена дополнительная информация о времени. Информация о времени доступна через метод getExtra() результата запроса. Если установлено значение 2, запрос включает статистику выполнения для каждого узла выполнения плана запроса в податрибуте stats.nodes дополнительного возвращаемого атрибута. Кроме того, план запроса возвращается в податрибуте extra.plan.

maxWarningCount

Параметр maxWarningCount ограничивает количество предупреждений, возвращаемых запросом, если для параметра failOnWarning не задано значение true. Значение по умолчанию — 10.

maxNumberOfPlans

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

optimizer

Параметры, связанные с оптимизатором запросов.

  • rules: в этот атрибут можно поместить список правил оптимизатора, которые должны быть включены или исключены, указывая оптимизатору, что следует включать или исключать определенные правила. Чтобы отключить правило, добавьте к его имени префикс -, чтобы включить правило, добавьте к нему префикс +. Также есть псевдоправило all, которое соответствует всем правилам оптимизатора. -all отключает все правила.

stream

Установите для параметра stream значение true, чтобы запрос выполнялся в потоковом режиме. Результат запроса не сохраняется на сервере, а вычисляется на лету.

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

Если установлено значение false, запрос выполняется сразу полностью. В этом случае результаты запроса либо возвращаются сразу (если набор результатов достаточно мал), либо сохраняются в экземпляре arangod, и к ним можно получить доступ через API курсора.

Параметры запроса cache, count и fullCount не работают с потоковыми запросами. Кроме того, статистика запросов, предупреждения и данные профилирования доступны только после завершения запроса. Значение по умолчанию false.

maxRuntime

Запрос должен быть выполнен в течение заданного времени выполнения, иначе он будет уничтожен. Значение указывается в секундах. Значение по умолчанию — 0.0 (без тайм-аута).

maxNodesPerCallstack

Количество узлов выполнения в плане запроса после выполнения этого разделения стека, чтобы избежать возможного переполнения стека. По умолчанию используется настроенное значение параметра запуска --query.max-nodes-per-callstack.

Этот параметр полезен только для тестирования и отладки и обычно не требует настройки.

maxTransactionSize

Ограничение размера транзакции в байтах.

intermediateCommitSize

Максимальный общий размер операций, после которого автоматически выполняется промежуточная фиксация.

intermediateCommitCount

Максимальное количество операций, после которого автоматически выполняется промежуточная фиксация.

spillOverThresholdMemoryUsage

Добавлено в версии: v3.10.0

Этот параметр позволяет запросам временно сохранять промежуточные и окончательные результаты на диске, если объем используемой памяти (в байтах) превышает указанное значение. Это используется для уменьшения использования памяти во время выполнения запроса.

Этот параметр влияет только на запросы, которые используют операцию SORT, но без LIMIT, и если вы включите функцию переполнения, указав путь для каталога для хранения временных данных с запуском --temp.intermediate-results-path вариант.

Значение по-умолчанию: 128MB.

Перенос данных из ОЗУ на диск — это экспериментальная функция, которая по умолчанию отключена. Результаты запросов по-прежнему полностью создаются в ОЗУ на координаторах и отдельных серверах для непотоковых запросов. Чтобы избежать накопления всего результата запроса в оперативной памяти, используйте потоковый запрос (см. опцию потока).

spillOverThresholdNumRows

Добавлено в версии: v3.10.0

Этот параметр позволяет запросам временно сохранять промежуточные и окончательные результаты на диске, если количество строк, созданных запросом, превышает указанное значение. Это используется для уменьшения использования памяти во время выполнения запроса. В запросе, который перебирает коллекцию, содержащую документы, каждая строка является документом, а в запросе, который перебирает временные значения (например, FOR i IN 1..100), каждая строка является одним из таких временных значений.

Этот параметр влияет только на запросы, которые используют операцию SORT, но без LIMIT, и если вы включите функцию переполнения, указав путь для каталога для хранения временных данных с запуском --temp.intermediate-results-path вариант.

Значение по-умолчанию: 5000000 rows.

Перенос данных из ОЗУ на диск — это экспериментальная функция, которая по умолчанию отключена. Результаты запросов по-прежнему полностью создаются в ОЗУ на координаторах и отдельных серверах для непотоковых запросов. Чтобы избежать накопления всего результата запроса в оперативной памяти, используйте потоковый запрос (см. опцию потока).

db._createStatement()

Метод _query() — это сокращение для создания объекта ArangoStatement, его выполнения и итерации по результирующему курсору. Если требуется больший контроль над итерацией набора результатов, рекомендуется сначала создать объект ArangoStatement следующим образом:

1
arangosh> stmt = db._createStatement( { "query": "FOR i IN [ 1, 2 ] RETURN i * 2" } );
1
[object ArangoStatement]

Чтобы выполнить запрос, используйте метод execute() оператора:

1
arangosh> cursor = stmt.execute();
1
2
3
4
5
[
    2,
    4
]
[object ArangoQueryCursor, count: 2, cached: false, hasMore: false]

Курсоры

После выполнения запроса результаты запроса доступны в курсоре. Курсор может вернуть все свои результаты сразу, используя метод toArray(). Это короткий путь, который вы можете использовать, если хотите получить доступ к полному набору результатов, не повторяя его самостоятельно.

1
arangosh> cursor.toArray();
1
2
3
4
[
    2,
    4
]

Курсоры также можно использовать для итерации по результирующему набору документов. Для этого используйте методы курсора hasNext() и next():

1
arangosh> while (c.hasNext()) { require("@arangodb").print(c.next()); }
1
2
2
4

Обратите внимание, что вы можете перебирать результаты курсора только один раз, и что курсор будет пустым, когда вы полностью переберете его. Чтобы снова перебрать результаты, запрос необходимо выполнить повторно.

Кроме того, итерация может выполняться только в прямом направлении. Нет обратной итерации или случайного доступа к элементам в курсоре.

Привязка параметров

Чтобы выполнить запрос AQL с использованием параметров привязки, вам нужно сначала создать оператор, а затем привязать к нему параметры перед выполнением:

1
2
3
4
arangosh> var stmt = db._createStatement( { "query": "FOR i IN [ @one, @two ] RETURN i * 2" } );
arangosh> stmt.bind("one", 1);
arangosh> stmt.bind("two", 2);
arangosh> cursor = stmt.execute();
1
2
3
4
5
[
    2,
    4
]
[object ArangoQueryCursor, count: 2, cached: false, hasMore: false]

Затем результаты курсора можно сбросить или повторить, как обычно, например:

1
arangosh> cursor.toArray();
1
2
3
4
[
    2,
    4
]

или

1
arangosh> while (cursor.hasNext()) { require("@arangodb").print(cursor.next()); }
1
2
2
4

Обратите внимание, что параметры привязки также могут быть переданы в метод _createStatement() напрямую, что делает его более удобным:

1
2
3
4
5
6
7
arangosh> stmt = db._createStatement( {
........> "query": "FOR i IN [ @one, @two ] RETURN i * 2",
........> "bindVars": {
........> "one": 1,
........> "two": 2
........> }
........> });
1
[object ArangoStatement]

Подсчет с помощью курсора

Курсоры также дополнительно отображают общее количество результатов. По умолчанию их нет. Чтобы сервер возвращал общее количество результатов, вы можете установить для атрибута count значение true при создании оператора:

1
2
3
arangosh> stmt = db._createStatement( {
........> "query": "FOR i IN [ 1, 2, 3, 4 ] RETURN i",
........> "count": true } );
1
[object ArangoStatement]

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

1
2
arangosh> var cursor = stmt.execute();
arangosh> cursor.count();
1
4

Обратите внимание, что метод count ничего не возвращает, если вы не указали атрибут count при создании запроса.

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

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

Получение дополнительной информации о внутренних таймингах

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

1
2
3
arangosh> stmt = db._createStatement( {
........> "query": "FOR i IN [ 1, 2, 3, 4 ] RETURN i",
........> options: {"profile": true}} );
1
[object ArangoStatement]

После выполнения этого запроса вы можете использовать метод курсора getExtra() для получения полученной статистики:

1
2
arangosh> var cursor = stmt.execute();
arangosh> cursor.getExtra();

Проверка запроса с помощью db._parse()

Метод _parse() объекта db можно использовать для синтаксического анализа и проверки запроса без его фактического выполнения.

1
arangosh> db._parse( "FOR i IN [ 1, 2 ] RETURN i" );

AQL с веб-интерфейсом ArangoDB

В веб-интерфейсе ArangoDB вкладка «Редактор AQL» позволяет выполнять специальные запросы AQL.

Введите запрос в основное поле и выполните его, нажав кнопку «Выполнить». Результат запроса будет показан на другой вкладке. Редактор предоставляет несколько примеров запросов, которые можно использовать в качестве шаблонов.

Он также предоставляет функцию объяснения запроса и проверки плана его выполнения (с помощью кнопки «Объяснить»).

Параметры привязки можно определить на правой боковой панели. Формат такой же, как и для параметров привязки в HTTP REST API и в коде приложения (JavaScript).

Вот пример:

1
2
3
FOR doc IN @@collection
  FILTER CONTAINS(LOWER(doc.author), @search, false)
  RETURN { "name": doc.name, "descr": doc.description, "author": doc.author }

Параметры привязки (режим просмотра JSON):

1
2
3
4
{
  "@collection": "_apps",
  "search": "arango"
}

Как работают параметры связывания, можно найти в AQL Fundamentals.

Запросы также можно сохранять в редакторе AQL вместе со значениями параметров привязки для последующего повторного использования. Эти данные хранятся в профиле пользователя в текущей базе данных (в системной таблице _users).

Комментарии