YQL

Общие вопросы

Как выбрать из таблицы строчки по заданному списку ключей?

Выборка строчек таблицы по заданному списку значений первичного ключа (или префикса ключа) таблицы выполняется с помощью оператора IN:

DECLARE $keys AS List<UInt64>;

SELECT * FROM some_table
WHERE Key1 IN $keys;

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

DECLARE $keys AS List<Tuple<UInt64, String>>;

SELECT * FROM some_table
WHERE (Key1, Key2) IN $keys;

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

Осуществляется ли поиск по индексу для условий, содержащих оператор LIKE?

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

SELECT * FROM string_key_table
WHERE Key LIKE "some_prefix%";

Почему в результате запроса выводится только 1000 строк?

1000 строк — ограничение на размер одного результата для YQL запроса. В случае если результат запроса был обрезан, он будет помечен флагом Truncated. Чтобы получить большее количество строк из таблицы, можно воспользоваться постраничным выводом или операцией ReadTable.

Как экранировать кавычки JSON-строк при добавлении их в таблицу?

Рассмотрим пример c двумя возможными вариантами добавления JSON-строки в таблицу:

UPSERT INTO test_json(id, json_string)
VALUES
    (1, Json(@@[{"name":"Peter \"strong cat\" Kourbatov"}]@@)),
    (2, Json('[{"name":"Peter \\\"strong cat\\\" Kourbatov"}]'))
;

Для вставки значения в первой строке используется raw string и способ экранирования с помощью \". Для вставки второй строки используется экранирование через \\\".

Мы рекомендуем применять raw string и способ экранирования с помощью \", так как он более нагляден.

Как обновить только те значения, ключей которых нет в таблице?

Можно использовать операцию LEFT JOIN, чтобы пометить отсутствующие в таблице ключи, после чего обновить их значения:

DECLARE $values AS List<Struct<Key: UInt64, Value: String>>;

UPSERT INTO kv_table
SELECT v.Key AS Key, v.Value AS Value
FROM AS_TABLE($values) AS v
LEFT JOIN kv_table AS t
ON v.Key = t.Key
WHERE t.Key IS NULL;

Операции Join

Есть ли особенности в работе операции Join?

Операция Join в YDB выполняется одним из двух способов:

  • Common Join;
  • Index Lookup Join.

Common Join

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

Index lookup Join

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

Примечание

Для большинства OLTP запросов рекомендуется использовать Index Lookup Join с небольшим размером левой части. Такие операции читают мало данных и могут быть выполнены эффективно.

Как сделать Join с данными из параметров запроса?

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

DECLARE $data AS List<Struct<Key1: UInt64, Key2: String>>;

SELECT * FROM AS_TABLE($data) AS d
INNER JOIN some_table AS t
ON t.Key1 = d.Key1 AND t.Key2 = d.Key2;

Явного ограничения на количество записей в константной таблице нет, но нужно иметь в виду стандартное ограничение на общий размер параметров запроса (50 МБ).

Как лучше реализовать запрос вида (key1, key2) IN ((v1, v2), (v3, v4), ...)?

Это лучше записывать через JOIN с константной таблицей:

$keys = AsList(
    AsStruct(1 AS Key1, "One" AS Key2),
    AsStruct(2 AS Key1, "Three" AS Key2),
    AsStruct(4 AS Key1, "One" AS Key2)
);

SELECT t.* FROM AS_TABLE($keys) AS k
INNER JOIN table1 AS t
ON t.Key1 = k.Key1 AND t.Key2 = k.Key2;

Транзакции

Насколько эффективно выполнение нескольких запросов в транзакции?

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

Является ли отдельный запрос атомарным?

В общем случае YQL-запросы могут выполняться в несколько последовательных фаз. Например, запрос с операцией Join может быть выполнен в две фазы, читающие данные левой и правой таблицы соответственно. Этот аспект является важным при выполнении запроса в транзакции с низким уровнем изоляции (online_read_only), так как в этом случае данные между фазами выполнения могут быть изменены другими транзакциями.