Skip to content

Docs: describe diagnostics collection #19007

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 148 additions & 0 deletions ydb/docs/en/core/reference/ydb-cli/sql.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ View the description of this command by calling it with `--help` option:
|| `--explain` | Execute an explain request for the query. Displays the query's logical plan. The query is not actually executed and does not affect database data. ||
|| `--explain-ast` | Same as `--explain`, but in addition to the query's logical plan, an [abstract syntax tree (AST)](https://en.wikipedia.org/wiki/Abstract_syntax_tree) is printed. The AST section contains a representation in the internal [miniKQL](../../concepts/glossary.md#minikql) language. ||
|| `--explain-analyze` | Execute the query in `EXPLAIN ANALYZE` mode. Displays the query execution plan. Query results are ignored.<br/>**Important note: The query is actually executed, so any changes will be applied to the database**. ||
|| `--diagnostics-file` | Path to a file where the [diagnostics](#diagnostics-collection) will be saved. ||
|| `--format` | Output format.<br/>Available options:

{% include notitle [format](./_includes/result_format_common.md) %}
Expand All @@ -38,6 +39,153 @@ View the description of this command by calling it with `--help` option:
||
|#

### Diagnostics collection {#diagnostics-collection}

The `--diagnostics-file <path_to_diagnostics>` option saves extended information about SQL query execution to a separate JSON file.

Diagnostics for each query are saved to `<path_to_diagnostics>`, overwriting the file if it already exists, and the file includes the following fields:

- `plan` — query execution [plan](../../yql/query_plans.md).
- `stats` — query execution statistics.
- `meta` — additional query information in JSON format, collected when statistics gathering is enabled with `--stats full` or in `EXPLAIN` queries (with `--explain`, `--explain-ast` or `--explain-analyze`), including the following fields:
- `created_at` — query start time (timestamp in seconds).
- `query_cluster` — cluster or provider name (always a constant).
- `query_database` — database path.
- `query_id` — unique query identifier.
- `query_syntax` — query syntax used, V1 syntax is the default. Experimental PostgreSQL syntax is also available.
- `query_text` — SQL query text.
- `query_type` — query type, possible values: `QUERY_TYPE_SQL_GENERIC_QUERY`, `QUERY_TYPE_SQL_GENERIC_CONCURRENT_QUERY`.
- `table_metadata` — a list of Protobuf descriptions (serialized to JSON) for all tables included in the query. Each entry contains the table schema, indexes, and statistics, all originally in Protobuf format.

{% cut "Example of table description in table_metadata" %}

```json
{
"DoesExist": true,
"Cluster": "db",
"Name": "/local/users",
"SysView": "",
"PathId": {
"OwnerId": 72075186232723360,
"TableId": 33
},
"SchemaVersion": 1,
"Kind": 1,
"Columns": [
{
"Name": "emails",
"Id": 3,
"Type": "Utf8",
"TypeId": 4608,
"NotNull": false,
"DefaultFromSequence": "",
"DefaultKind": 0,
"DefaultFromLiteral": {},
"IsBuildInProgress": false,
"DefaultFromSequencePathId": {
"OwnerId": 18446744073709551615,
"TableId": 18446744073709551615
}
},
{
"Name": "id",
"Id": 1,
"Type": "Int32",
"TypeId": 1,
"NotNull": false,
"DefaultFromSequence": "",
"DefaultKind": 0,
"DefaultFromLiteral": {},
"IsBuildInProgress": false,
"DefaultFromSequencePathId": {
"OwnerId": 18446744073709551615,
"TableId": 18446744073709551615
}
},
{
"Name": "name",
"Id": 2,
"Type": "Utf8",
"TypeId": 4608,
"NotNull": false,
"DefaultFromSequence": "",
"DefaultKind": 0,
"DefaultFromLiteral": {},
"IsBuildInProgress": false,
"DefaultFromSequencePathId": {
"OwnerId": 18446744073709551615,
"TableId": 18446744073709551615
}
}
],
"KeyColunmNames": [
"id"
],
"RecordsCount": 0,
"DataSize": 0,
"StatsLoaded": false
}
```

{% endcut %}

- `ast` — abstract syntax tree [AST](https://en.wikipedia.org/wiki/Abstract_syntax_tree) for the query.

{% cut "Example of ast" %}

```text
(
(let (KqpTable '"/local/users" '"72075186232723360:33" '"" '1))
(let '('"emails" '"id" '"name"))
(let (KqpRowsSourceSettings '() (Void) '()))
(let (DqPhyStage '((DqSource (DataSource '"KqpReadRangesSource") )) (lambda '() (FromFlow (Filter (ToFlow ) (lambda '(0) (Coalesce (== (Member 0 '"emails") (String '"john@example.com")) (Bool 'false)))))) '('('"_logical_id" '401) '('"_id" '"45d03f9b-f40c98ba-b6705ab-90ee6ea"))))
(let (DqCnUnionAll (TDqOutput '"0")))
(let (DqPhyStage '() (lambda '(1) 1) '('('"_logical_id" '477) '('"_id" '"28936ac-4af296f3-7afa38af-7dc0798"))))
(let (DqCnResult (TDqOutput '"0") '()))
(let (OptionalType (DataType 'Utf8)))
(return (KqpPhysicalQuery '((KqpPhysicalTx '( ) '() '() '('('"type" '"generic")))) '((KqpTxResultBinding (ListType (StructType '('"emails" ) '('"id" (OptionalType (DataType 'Int32))) '('"name" ))) '"0" '"0")) '('('"type" '"query"))))
)
```

{% endcut %}


{% note warning %}

The diagnostics file may contain confidential information and sensitive data, especially in the `meta.query_text`, `plan`, and `ast` fields. Before sharing it with third parties (for example, technical support), carefully review and edit the file to remove or replace any sensitive data.

{% endnote %}

#### Example

Command to collect diagnostics in the `diagnostics.json` file and inspect its contents:

```bash
ydb -e <endpoint> -d <database> sql -s "SELECT * FROM users WHERE email = 'alice@example.com';" \
--stats full --diagnostics-file diagnostics.json
cat diagnostics.json
```

If you want to collect diagnostics related to a query plan without executing the query, run it in `EXPLAIN` mode by adding the `--explain` option:

```bash
ydb -e <endpoint> -d <database> sql -s "SELECT * FROM users WHERE email = 'alice@example.com';" --explain --diagnostics-file diagnostics.json
```

In the `diagnostics.json` file, in the `meta.query_text` field, the following string will appear:

```json
"query_text": "SELECT * FROM users WHERE email = 'alice@example.com';"
```

This contains sensitive information, such as a user’s email address. Before sharing the diagnostics file, replace actual values with placeholders:

```json
"query_text": "SELECT * FROM users WHERE email = '<EMAIL>';"
```

In this example, the email address can also be found in fields such as `plan` and `ast`, such entries should also be replaced.

### Working with parameterized queries {#parameterized-query}

For a detailed description with examples on how to use parameterized queries, see [{#T}](parameterized-query-execution.md).
Expand Down
147 changes: 147 additions & 0 deletions ydb/docs/ru/core/reference/ydb-cli/sql.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
|| `--explain` | Выполнить explain-запрос, будет выведен логический план запроса. Сам запрос не будет выполнен, поэтому не затронет данные в базе. ||
|| `--explain-ast` | То же, что и `--explain`, но вдобавок к логическому плану выводит [AST (abstract syntax tree)](https://ru.wikipedia.org/wiki/Абстрактное_синтаксическое_дерево). Раздел с AST содержит представление на внутреннем языке [miniKQL](../../concepts/glossary.md#minikql). ||
|| `--explain-analyze` | Выполнить запрос в режиме `EXPLAIN ANALYZE`. Показывает план выполнения запроса. Возвращаемые в рамках запроса данные игнорируются.<br/>**Важное замечание: Запрос фактически выполняется, поэтому может внести изменения в базу**. ||
|| `--diagnostics-file` | Путь для сохранения файла с диагностикой. ||
|| `--format` | Формат вывода.<br/>Возможные значения:

{% include notitle [format](./_includes/result_format_common.md) %}
Expand All @@ -38,6 +39,152 @@
||
|#

### Сбор диагностики {#diagnostics-collection}

Опция `--diagnostics-file <path_to_diagnostics>` позволяет сохранять расширенную информацию о выполнении SQL-запросов в отдельный JSON-файл.

Диагностика формируется при сборе статистики `--stats full`, а также при выполнении `EXPLAIN`-запросов. Для каждого запроса будет создан файл `<path_to_diagnostics>` со следующими полями:

- `plan` — [план](../../yql/query_plans.md) выполнения запроса.
- `stats` — статистика выполнения запроса.
- `meta` — дополнительная информация о запросе в JSON-формате, формируется при сборе статистики `--stats full`, а также при выполнении `EXPLAIN`-запросов (`--explain`, `--explain-ast` или `--explain-analyze`), включает следующие поля:
- `created_at` — время начала запроса (timestamp в секундах).
- `query_cluster` — название кластера или провайдера (всегда константа).
- `query_database` — путь к базе данных.
- `query_id` — уникальный идентификатор запроса.
- `query_syntax` — используемый синтаксис запроса; по умолчанию используется синтаксис V1. Также доступен экспериментальный синтаксис PostgreSQL.
- `query_text` — текст SQL-запроса.
- `query_type` — тип запроса, возможные значения: `QUERY_TYPE_SQL_GENERIC_QUERY`, `QUERY_TYPE_SQL_GENERIC_CONCURRENT_QUERY`.
- `table_metadata` — список Protobuf-описаний (сериализованных в JSON) для всех таблиц, участвующих в запросе. Каждый элемент списка содержит описание схемы таблицы, индексов и статистики, все эти поля изначально представлены в формате Protobuf.

{% cut "Пример описания таблицы в table_metadata" %}

```json
{
"DoesExist": true,
"Cluster": "db",
"Name": "/local/users",
"SysView": "",
"PathId": {
"OwnerId": 72075186232723360,
"TableId": 33
},
"SchemaVersion": 1,
"Kind": 1,
"Columns": [
{
"Name": "emails",
"Id": 3,
"Type": "Utf8",
"TypeId": 4608,
"NotNull": false,
"DefaultFromSequence": "",
"DefaultKind": 0,
"DefaultFromLiteral": {},
"IsBuildInProgress": false,
"DefaultFromSequencePathId": {
"OwnerId": 18446744073709551615,
"TableId": 18446744073709551615
}
},
{
"Name": "id",
"Id": 1,
"Type": "Int32",
"TypeId": 1,
"NotNull": false,
"DefaultFromSequence": "",
"DefaultKind": 0,
"DefaultFromLiteral": {},
"IsBuildInProgress": false,
"DefaultFromSequencePathId": {
"OwnerId": 18446744073709551615,
"TableId": 18446744073709551615
}
},
{
"Name": "name",
"Id": 2,
"Type": "Utf8",
"TypeId": 4608,
"NotNull": false,
"DefaultFromSequence": "",
"DefaultKind": 0,
"DefaultFromLiteral": {},
"IsBuildInProgress": false,
"DefaultFromSequencePathId": {
"OwnerId": 18446744073709551615,
"TableId": 18446744073709551615
}
}
],
"KeyColunmNames": [
"id"
],
"RecordsCount": 0,
"DataSize": 0,
"StatsLoaded": false
}
```

{% endcut %}

- `ast` — абстрактное синтаксическое дерево [AST](https://ru.wikipedia.org/wiki/Абстрактное_синтаксическое_дерево) запроса.

{% cut "Пример ast" %}

```text
(
(let (KqpTable '"/local/users" '"72075186232723360:33" '"" '1))
(let '('"emails" '"id" '"name"))
(let (KqpRowsSourceSettings '() (Void) '()))
(let (DqPhyStage '((DqSource (DataSource '"KqpReadRangesSource") )) (lambda '() (FromFlow (Filter (ToFlow ) (lambda '(0) (Coalesce (== (Member 0 '"emails") (String '"john@example.com")) (Bool 'false)))))) '('('"_logical_id" '401) '('"_id" '"45d03f9b-f40c98ba-b6705ab-90ee6ea"))))
(let (DqCnUnionAll (TDqOutput '"0")))
(let (DqPhyStage '() (lambda '(1) 1) '('('"_logical_id" '477) '('"_id" '"28936ac-4af296f3-7afa38af-7dc0798"))))
(let (DqCnResult (TDqOutput '"0") '()))
(let (OptionalType (DataType 'Utf8)))
(return (KqpPhysicalQuery '((KqpPhysicalTx '( ) '() '() '('('"type" '"generic")))) '((KqpTxResultBinding (ListType (StructType '('"emails" ) '('"id" (OptionalType (DataType 'Int32))) '('"name" ))) '"0" '"0")) '('('"type" '"query"))))
)
```

{% endcut %}

{% note warning %}

Файл диагностики может содержать конфиденциальные данные и чувствительную информацию, особенно в полях `meta.query_text`, `plan` и `ast`. Перед передачей такого файла сторонним лицам (например, в техническую поддержку) рекомендуется вручную просмотреть и отредактировать содержимое файла, чтобы удалить или заменить чувствительную информацию.

{% endnote %}

#### Пример

Команда, чтобы собрать диагностику в файл `diagnostics.json` и проверить его содержимое:

```bash
ydb -e <endpoint> -d <database> sql -s "SELECT * FROM users WHERE email = 'alice@example.com';" \
--stats full --diagnostics-file diagnostics.json
cat diagnostics.json
```

Если вы хотите получить диагностические данные, относящиеся к плану запроса, без фактического выполнения запроса, вы можете вместо этого выполнить `EXPLAIN`-запрос, добавив опцию `--explain`:

```bash
ydb -e <endpoint> -d <database> sql -s "SELECT * FROM users WHERE email = 'alice@example.com';" --explain --diagnostics-file diagnostics.json
```

В диагностическом файле `diagnostics.json` в поле `meta.query_text` будет содержаться такая строка:

```json
"query_text": "SELECT * FROM users WHERE email = 'alice@example.com';"
```

Здесь присутствует чувствительная информация — адрес электронной почты пользователя. Перед передачей диагностического файла рекомендуется заменить реальные значения на шаблонные:

```json
"query_text": "SELECT * FROM users WHERE email = '<EMAIL>';"
```

В данном примере адрес электронной почты можно обнаружить в полях `plan` и `ast`, такие вхождения тоже нужно заменить.

### Работа с параметризованными запросами {#parameterized-query}

Подробное описание работы с параметрами с примерами смотрите в статье [{#T}](parameterized-query-execution.md).
Expand Down