diff --git a/ydb/docs/en/core/reference/ydb-cli/sql.md b/ydb/docs/en/core/reference/ydb-cli/sql.md
index 87dea3e2da05..ac98e83587cb 100644
--- a/ydb/docs/en/core/reference/ydb-cli/sql.md
+++ b/ydb/docs/en/core/reference/ydb-cli/sql.md
@@ -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.
**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.
Available options:
{% include notitle [format](./_includes/result_format_common.md) %}
@@ -38,6 +39,153 @@ View the description of this command by calling it with `--help` option:
||
|#
+### Diagnostics collection {#diagnostics-collection}
+
+The `--diagnostics-file ` option saves extended information about SQL query execution to a separate JSON file.
+
+Diagnostics for each query are saved to ``, 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 -d 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 -d 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 = '';"
+```
+
+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).
diff --git a/ydb/docs/ru/core/reference/ydb-cli/sql.md b/ydb/docs/ru/core/reference/ydb-cli/sql.md
index 3cd2096364ed..54040741e8c8 100644
--- a/ydb/docs/ru/core/reference/ydb-cli/sql.md
+++ b/ydb/docs/ru/core/reference/ydb-cli/sql.md
@@ -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`. Показывает план выполнения запроса. Возвращаемые в рамках запроса данные игнорируются.
**Важное замечание: Запрос фактически выполняется, поэтому может внести изменения в базу**. ||
+|| `--diagnostics-file` | Путь для сохранения файла с диагностикой. ||
|| `--format` | Формат вывода.
Возможные значения:
{% include notitle [format](./_includes/result_format_common.md) %}
@@ -38,6 +39,152 @@
||
|#
+### Сбор диагностики {#diagnostics-collection}
+
+Опция `--diagnostics-file ` позволяет сохранять расширенную информацию о выполнении SQL-запросов в отдельный JSON-файл.
+
+Диагностика формируется при сборе статистики `--stats full`, а также при выполнении `EXPLAIN`-запросов. Для каждого запроса будет создан файл `` со следующими полями:
+
+- `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 -d sql -s "SELECT * FROM users WHERE email = 'alice@example.com';" \
+--stats full --diagnostics-file diagnostics.json
+cat diagnostics.json
+```
+
+Если вы хотите получить диагностические данные, относящиеся к плану запроса, без фактического выполнения запроса, вы можете вместо этого выполнить `EXPLAIN`-запрос, добавив опцию `--explain`:
+
+```bash
+ydb -e -d 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 = '';"
+```
+
+В данном примере адрес электронной почты можно обнаружить в полях `plan` и `ast`, такие вхождения тоже нужно заменить.
+
### Работа с параметризованными запросами {#parameterized-query}
Подробное описание работы с параметрами с примерами смотрите в статье [{#T}](parameterized-query-execution.md).