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).