aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikolay Shumkov <shumkovnd@ydb.tech>2025-02-14 21:08:44 +0300
committerGitHub <noreply@github.com>2025-02-14 21:08:44 +0300
commit5b11bce7be23074d80e0e3a6eb78345118602cb5 (patch)
tree332568b083e513fa62fc6614049d96b98a53cec6
parent010e83fee42c48e44c89fbb43af2f80980b7c379 (diff)
downloadydb-5b11bce7be23074d80e0e3a6eb78345118602cb5.tar.gz
Support QueryMeta and diagnostics (#11371)
Co-authored-by: Bulat <bylatgr@gmail.com>
-rw-r--r--ydb/core/grpc_services/query/rpc_execute_query.cpp23
-rw-r--r--ydb/core/grpc_services/rpc_execute_data_query.cpp15
-rw-r--r--ydb/core/grpc_services/rpc_stream_execute_scan_query.cpp28
-rw-r--r--ydb/core/kqp/common/compilation/events.h4
-rw-r--r--ydb/core/kqp/common/compilation/result.h11
-rw-r--r--ydb/core/kqp/compile_service/kqp_compile_actor.cpp8
-rw-r--r--ydb/core/kqp/compile_service/kqp_compile_service.cpp13
-rw-r--r--ydb/core/kqp/session_actor/kqp_query_state.cpp7
-rw-r--r--ydb/core/kqp/ut/indexes/kqp_indexes_ut.cpp4
-rw-r--r--ydb/core/kqp/ut/olap/helpers/query_executor.cpp16
-rw-r--r--ydb/core/kqp/ut/olap/kqp_olap_ut.cpp50
-rw-r--r--ydb/core/kqp/ut/query/kqp_query_ut.cpp72
-rw-r--r--ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp210
-rw-r--r--ydb/public/api/protos/ydb_query_stats.proto3
-rw-r--r--ydb/public/api/protos/ydb_table.proto4
-rw-r--r--ydb/public/lib/ydb_cli/commands/ydb_service_table.cpp88
-rw-r--r--ydb/public/lib/ydb_cli/commands/ydb_service_table.h1
-rw-r--r--ydb/public/lib/ydb_cli/commands/ydb_sql.cpp36
-rw-r--r--ydb/public/lib/ydb_cli/commands/ydb_sql.h1
-rw-r--r--ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/query/stats.h1
-rw-r--r--ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/table/query_stats/stats.h2
-rw-r--r--ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/table/table.h2
-rw-r--r--ydb/public/sdk/cpp/src/client/query/stats.cpp11
23 files changed, 542 insertions, 68 deletions
diff --git a/ydb/core/grpc_services/query/rpc_execute_query.cpp b/ydb/core/grpc_services/query/rpc_execute_query.cpp
index dcf0d45b38..8e0fe72525 100644
--- a/ydb/core/grpc_services/query/rpc_execute_query.cpp
+++ b/ydb/core/grpc_services/query/rpc_execute_query.cpp
@@ -179,6 +179,25 @@ bool NeedReportAst(const Ydb::Query::ExecuteQueryRequest& req) {
}
}
+bool NeedCollectDiagnostics(const Ydb::Query::ExecuteQueryRequest& req) {
+ switch (req.exec_mode()) {
+ case Ydb::Query::EXEC_MODE_EXPLAIN:
+ return true;
+
+ case Ydb::Query::EXEC_MODE_EXECUTE:
+ switch (req.stats_mode()) {
+ case Ydb::Query::StatsMode::STATS_MODE_FULL:
+ case Ydb::Query::StatsMode::STATS_MODE_PROFILE:
+ return true;
+ default:
+ return false;
+ }
+
+ default:
+ return false;
+ }
+}
+
class TExecuteQueryRPC : public TActorBootstrapped<TExecuteQueryRPC> {
public:
static constexpr NKikimrServices::TActivity::EType ActorActivityType() {
@@ -284,6 +303,7 @@ private:
req->pool_id());
ev->SetProgressStatsPeriod(TDuration::MilliSeconds(req->stats_period_ms()));
+ ev->Record.MutableRequest()->SetCollectDiagnostics(NeedCollectDiagnostics(*req));
if (!ctx.Send(NKqp::MakeKqpProxyID(ctx.SelfID.NodeId()), ev.Release(), 0, 0, Span_.GetTraceId())) {
NYql::TIssues issues;
@@ -403,6 +423,9 @@ private:
if (NeedReportAst(*Request_->GetProtoRequest())) {
response.mutable_exec_stats()->set_query_ast(kqpResponse.GetQueryAst());
}
+ if (NeedCollectDiagnostics(*Request_->GetProtoRequest())) {
+ response.mutable_exec_stats()->set_query_meta(kqpResponse.GetQueryDiagnostics());
+ }
}
if (record.GetYdbStatus() == Ydb::StatusIds::SUCCESS) {
diff --git a/ydb/core/grpc_services/rpc_execute_data_query.cpp b/ydb/core/grpc_services/rpc_execute_data_query.cpp
index f134adf399..eb98c29674 100644
--- a/ydb/core/grpc_services/rpc_execute_data_query.cpp
+++ b/ydb/core/grpc_services/rpc_execute_data_query.cpp
@@ -27,6 +27,16 @@ using namespace Ydb;
using namespace Ydb::Table;
using namespace NKqp;
+bool NeedCollectDiagnostics(const Ydb::Table::ExecuteDataQueryRequest& req) {
+ switch (req.collect_stats()) {
+ case Ydb::Table::QueryStatsCollection::STATS_COLLECTION_FULL:
+ case Ydb::Table::QueryStatsCollection::STATS_COLLECTION_PROFILE:
+ return true;
+ default:
+ return false;
+ }
+}
+
using TEvExecuteDataQueryRequest = TGrpcRequestOperationCall<Ydb::Table::ExecuteDataQueryRequest,
Ydb::Table::ExecuteDataQueryResponse>;
@@ -147,6 +157,8 @@ public:
req->has_query_cache_policy() ? &req->query_cache_policy() : nullptr,
req->has_operation_params() ? &req->operation_params() : nullptr);
+ ev->Record.MutableRequest()->SetCollectDiagnostics(NeedCollectDiagnostics(*req));
+
ReportCostInfo_ = req->operation_params().report_cost_info() == Ydb::FeatureFlag::ENABLED;
ctx.Send(NKqp::MakeKqpProxyID(ctx.SelfID.NodeId()), ev.Release(), 0, 0, Span_.GetTraceId());
@@ -166,6 +178,9 @@ public:
if (from.HasQueryStats()) {
FillQueryStats(*to->mutable_query_stats(), from);
to->mutable_query_stats()->set_query_ast(from.GetQueryAst());
+ if (from.HasQueryDiagnostics()) {
+ to->mutable_query_stats()->set_query_meta(from.GetQueryDiagnostics());
+ }
return;
}
}
diff --git a/ydb/core/grpc_services/rpc_stream_execute_scan_query.cpp b/ydb/core/grpc_services/rpc_stream_execute_scan_query.cpp
index c37dc9b06e..6d2a6713be 100644
--- a/ydb/core/grpc_services/rpc_stream_execute_scan_query.cpp
+++ b/ydb/core/grpc_services/rpc_stream_execute_scan_query.cpp
@@ -93,6 +93,27 @@ bool NeedReportPlan(const Ydb::Table::ExecuteScanQueryRequest& req) {
}
}
+bool NeedCollectDiagnostics(const Ydb::Table::ExecuteScanQueryRequest& req) {
+ switch (req.mode()) {
+ case ExecuteScanQueryRequest_Mode_MODE_EXPLAIN:
+ return true;
+
+ case ExecuteScanQueryRequest_Mode_MODE_EXEC:
+ switch (req.collect_stats()) {
+ case Ydb::Table::QueryStatsCollection::STATS_COLLECTION_FULL:
+ case Ydb::Table::QueryStatsCollection::STATS_COLLECTION_PROFILE:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+
+ default:
+ return false;
+ }
+}
+
bool CheckRequest(const Ydb::Table::ExecuteScanQueryRequest& req, TParseRequestError& error)
{
switch (req.mode()) {
@@ -228,7 +249,7 @@ private:
nullptr
);
- ev->Record.MutableRequest()->SetCollectDiagnostics(req->Getcollect_full_diagnostics());
+ ev->Record.MutableRequest()->SetCollectDiagnostics(NeedCollectDiagnostics(*req));
if (!ctx.Send(NKqp::MakeKqpProxyID(ctx.SelfID.NodeId()), ev.Release())) {
NYql::TIssues issues;
@@ -291,6 +312,7 @@ private:
bool reportStats = NeedReportStats(*Request_->GetProtoRequest());
bool reportPlan = reportStats && NeedReportPlan(*Request_->GetProtoRequest());
+ bool collectDiagnostics = NeedCollectDiagnostics(*Request_->GetProtoRequest());
if (reportStats) {
if (kqpResponse.HasQueryStats()) {
@@ -308,7 +330,9 @@ private:
response.mutable_result()->mutable_query_stats()->set_query_ast(kqpResponse.GetQueryAst());
}
- response.mutable_result()->set_query_full_diagnostics(kqpResponse.GetQueryDiagnostics());
+ if (collectDiagnostics) {
+ response.mutable_result()->mutable_query_stats()->set_query_meta(kqpResponse.GetQueryDiagnostics());
+ }
Y_PROTOBUF_SUPPRESS_NODISCARD response.SerializeToString(&out);
Request_->SendSerializedResult(std::move(out), record.GetYdbStatus());
diff --git a/ydb/core/kqp/common/compilation/events.h b/ydb/core/kqp/common/compilation/events.h
index 9ed2d03e87..2daa210243 100644
--- a/ydb/core/kqp/common/compilation/events.h
+++ b/ydb/core/kqp/common/compilation/events.h
@@ -126,16 +126,14 @@ struct TEvRecompileRequest: public TEventLocal<TEvRecompileRequest, TKqpEvents::
};
struct TEvCompileResponse: public TEventLocal<TEvCompileResponse, TKqpEvents::EvCompileResponse> {
- TEvCompileResponse(const TKqpCompileResult::TConstPtr& compileResult, NLWTrace::TOrbit orbit = {}, const std::optional<TString>& replayMessage = std::nullopt)
+ TEvCompileResponse(const TKqpCompileResult::TConstPtr& compileResult, NLWTrace::TOrbit orbit = {})
: CompileResult(compileResult)
- , ReplayMessage(replayMessage)
, Orbit(std::move(orbit)) {
}
TKqpCompileResult::TConstPtr CompileResult;
TKqpStatsCompile Stats;
std::optional<TString> ReplayMessage;
- std::optional<TString> ReplayMessageUserView;
NLWTrace::TOrbit Orbit;
};
diff --git a/ydb/core/kqp/common/compilation/result.h b/ydb/core/kqp/common/compilation/result.h
index f7206fceb1..a87294c8e8 100644
--- a/ydb/core/kqp/common/compilation/result.h
+++ b/ydb/core/kqp/common/compilation/result.h
@@ -16,7 +16,7 @@ struct TKqpCompileResult {
TKqpCompileResult(const TString& uid, const Ydb::StatusIds::StatusCode& status, const NYql::TIssues& issues,
ETableReadType maxReadType, TMaybe<TKqpQueryId> query = {}, TMaybe<TQueryAst> queryAst = {},
- bool needToSplit = false, const TMaybe<TString>& commandTagName = {})
+ bool needToSplit = false, const TMaybe<TString>& commandTagName = {}, const TMaybe<TString>& replayMessageUserView = {})
: Status(status)
, Issues(issues)
, Query(std::move(query))
@@ -24,13 +24,14 @@ struct TKqpCompileResult {
, MaxReadType(maxReadType)
, QueryAst(std::move(queryAst))
, NeedToSplit(needToSplit)
- , CommandTagName(commandTagName) {}
+ , CommandTagName(commandTagName)
+ , ReplayMessageUserView(replayMessageUserView) {}
static std::shared_ptr<TKqpCompileResult> Make(const TString& uid, const Ydb::StatusIds::StatusCode& status,
const NYql::TIssues& issues, ETableReadType maxReadType, TMaybe<TKqpQueryId> query = {},
- TMaybe<TQueryAst> queryAst = {}, bool needToSplit = false, const TMaybe<TString>& commandTagName = {})
+ TMaybe<TQueryAst> queryAst = {}, bool needToSplit = false, const TMaybe<TString>& commandTagName = {}, const TMaybe<TString>& replayMessageUserView = {})
{
- return std::make_shared<TKqpCompileResult>(uid, status, issues, maxReadType, std::move(query), std::move(queryAst), needToSplit, commandTagName);
+ return std::make_shared<TKqpCompileResult>(uid, status, issues, maxReadType, std::move(query), std::move(queryAst), needToSplit, commandTagName, replayMessageUserView);
}
std::shared_ptr<NYql::TAstParseResult> GetAst() const;
@@ -47,6 +48,8 @@ struct TKqpCompileResult {
bool NeedToSplit = false;
TMaybe<TString> CommandTagName = {};
+ TMaybe<TString> ReplayMessageUserView;
+
std::shared_ptr<const TPreparedQueryHolder> PreparedQuery;
};
diff --git a/ydb/core/kqp/compile_service/kqp_compile_actor.cpp b/ydb/core/kqp/compile_service/kqp_compile_actor.cpp
index 6b18134212..91cc89b8f5 100644
--- a/ydb/core/kqp/compile_service/kqp_compile_actor.cpp
+++ b/ydb/core/kqp/compile_service/kqp_compile_actor.cpp
@@ -353,7 +353,6 @@ private:
replayMessage.InsertValue("query_id", Uid);
replayMessage.InsertValue("version", "1.0");
- replayMessage.InsertValue("query_text", EscapeC(QueryId.Text));
NJson::TJsonValue queryParameterTypes(NJson::JSON_MAP);
if (QueryId.QueryParameterTypes) {
for (const auto& [paramName, paramType] : *QueryId.QueryParameterTypes) {
@@ -365,7 +364,6 @@ private:
replayMessage.InsertValue("query_syntax", ToString(Config->_KqpYqlSyntaxVersion.Get().GetRef()));
replayMessage.InsertValue("query_database", QueryId.Database);
replayMessage.InsertValue("query_cluster", QueryId.Cluster);
- replayMessage.InsertValue("query_plan", queryPlan);
replayMessage.InsertValue("query_type", ToString(QueryId.Settings.QueryType));
if (CollectFullDiagnostics) {
@@ -380,6 +378,8 @@ private:
ReplayMessageUserView = NJson::WriteJson(replayMessage, /*formatOutput*/ false);
}
+ replayMessage.InsertValue("query_plan", queryPlan);
+ replayMessage.InsertValue("query_text", EscapeC(QueryId.Text));
replayMessage.InsertValue("table_metadata", TString(NJson::WriteJson(tablesMeta, false)));
replayMessage.InsertValue("table_meta_serialization_type", EMetaSerializationType::EncodedProto);
@@ -401,10 +401,12 @@ private:
<< ", issues: " << KqpCompileResult->Issues.ToString()
<< ", uid: " << KqpCompileResult->Uid);
+ if (ReplayMessageUserView) {
+ KqpCompileResult->ReplayMessageUserView = std::move(*ReplayMessageUserView);
+ }
auto responseEv = MakeHolder<TEvKqp::TEvCompileResponse>(KqpCompileResult);
responseEv->ReplayMessage = std::move(ReplayMessage);
- responseEv->ReplayMessageUserView = std::move(ReplayMessageUserView);
ReplayMessage = std::nullopt;
ReplayMessageUserView = std::nullopt;
auto& stats = responseEv->Stats;
diff --git a/ydb/core/kqp/compile_service/kqp_compile_service.cpp b/ydb/core/kqp/compile_service/kqp_compile_service.cpp
index 673b5a3909..b16ccd9b7c 100644
--- a/ydb/core/kqp/compile_service/kqp_compile_service.cpp
+++ b/ydb/core/kqp/compile_service/kqp_compile_service.cpp
@@ -610,7 +610,7 @@ private:
if (compileResult->NeedToSplit) {
Reply(compileRequest.Sender, compileResult, compileStats, ctx,
- compileRequest.Cookie, std::move(compileRequest.Orbit), std::move(compileRequest.CompileServiceSpan), (CollectDiagnostics ? ev->Get()->ReplayMessageUserView : std::nullopt));
+ compileRequest.Cookie, std::move(compileRequest.Orbit), std::move(compileRequest.CompileServiceSpan));
ProcessQueue(ctx);
return;
}
@@ -635,7 +635,7 @@ private:
for (auto& request : requests) {
LWTRACK(KqpCompileServiceGetCompilation, request.Orbit, request.Query.UserSid, compileActorId.ToString());
Reply(request.Sender, compileResult, compileStats, ctx,
- request.Cookie, std::move(request.Orbit), std::move(request.CompileServiceSpan), (CollectDiagnostics ? ev->Get()->ReplayMessageUserView : std::nullopt));
+ request.Cookie, std::move(request.Orbit), std::move(request.CompileServiceSpan));
}
} else {
if (!hasTempTablesNameClashes) {
@@ -647,7 +647,7 @@ private:
LWTRACK(KqpCompileServiceGetCompilation, compileRequest.Orbit, compileRequest.Query.UserSid, compileActorId.ToString());
Reply(compileRequest.Sender, compileResult, compileStats, ctx,
- compileRequest.Cookie, std::move(compileRequest.Orbit), std::move(compileRequest.CompileServiceSpan), (CollectDiagnostics ? ev->Get()->ReplayMessageUserView : std::nullopt));
+ compileRequest.Cookie, std::move(compileRequest.Orbit), std::move(compileRequest.CompileServiceSpan));
}
catch (const std::exception& e) {
LogException("TEvCompileResponse", ev->Sender, e, ctx);
@@ -809,7 +809,8 @@ private:
if (compileResult->GetAst() && QueryCache->FindByAst(query, *compileResult->GetAst(), keepInCache)) {
return false;
}
- auto newCompileResult = TKqpCompileResult::Make(CreateGuidAsString(), compileResult->Status, compileResult->Issues, compileResult->MaxReadType, std::move(query), compileResult->QueryAst);
+ auto newCompileResult = TKqpCompileResult::Make(CreateGuidAsString(), compileResult->Status, compileResult->Issues, compileResult->MaxReadType, std::move(query), compileResult->QueryAst,
+ false, {}, compileResult->ReplayMessageUserView);
newCompileResult->AllowCache = compileResult->AllowCache;
newCompileResult->PreparedQuery = compileResult->PreparedQuery;
LOG_DEBUG_S(ctx, NKikimrServices::KQP_COMPILE_SERVICE, "Insert preparing query with params, queryId: " << query.SerializeToString());
@@ -865,7 +866,7 @@ private:
void Reply(const TActorId& sender, const TKqpCompileResult::TConstPtr& compileResult,
const TKqpStatsCompile& compileStats, const TActorContext& ctx, ui64 cookie,
- NLWTrace::TOrbit orbit, NWilson::TSpan span, const std::optional<TString>& replayMessage = std::nullopt)
+ NLWTrace::TOrbit orbit, NWilson::TSpan span)
{
const auto& query = compileResult->Query;
LWTRACK(KqpCompileServiceReply,
@@ -878,7 +879,7 @@ private:
<< ", queryUid: " << compileResult->Uid
<< ", status:" << compileResult->Status);
- auto responseEv = MakeHolder<TEvKqp::TEvCompileResponse>(compileResult, std::move(orbit), replayMessage);
+ auto responseEv = MakeHolder<TEvKqp::TEvCompileResponse>(compileResult, std::move(orbit));
responseEv->Stats = compileStats;
if (span) {
diff --git a/ydb/core/kqp/session_actor/kqp_query_state.cpp b/ydb/core/kqp/session_actor/kqp_query_state.cpp
index 4c02f46b15..eaf20f4f23 100644
--- a/ydb/core/kqp/session_actor/kqp_query_state.cpp
+++ b/ydb/core/kqp/session_actor/kqp_query_state.cpp
@@ -143,9 +143,6 @@ bool TKqpQueryState::SaveAndCheckCompileResult(TEvKqp::TEvCompileResponse* ev) {
return false;
}
Orbit = std::move(ev->Orbit);
- if (ev->ReplayMessage) {
- ReplayMessage = *ev->ReplayMessage;
- }
return true;
}
@@ -160,6 +157,10 @@ bool TKqpQueryState::SaveAndCheckCompileResult(TKqpCompileResult::TConstPtr comp
return false;
}
+ if (compileResult->ReplayMessageUserView && GetCollectDiagnostics()) {
+ ReplayMessage = *compileResult->ReplayMessageUserView;
+ }
+
YQL_ENSURE(CompileResult->PreparedQuery);
const ui32 compiledVersion = CompileResult->PreparedQuery->GetVersion();
YQL_ENSURE(compiledVersion == NKikimrKqp::TPreparedQuery::VERSION_PHYSICAL_V1,
diff --git a/ydb/core/kqp/ut/indexes/kqp_indexes_ut.cpp b/ydb/core/kqp/ut/indexes/kqp_indexes_ut.cpp
index 8a56cf6c3c..f12cff2317 100644
--- a/ydb/core/kqp/ut/indexes/kqp_indexes_ut.cpp
+++ b/ydb/core/kqp/ut/indexes/kqp_indexes_ut.cpp
@@ -2698,7 +2698,7 @@ Y_UNIT_TEST_SUITE(KqpIndexes) {
UNIT_ASSERT_C(value.IsMap(), "Incorrect Diagnostics");
UNIT_ASSERT_C(value.Has("query_id"), "Incorrect Diagnostics");
UNIT_ASSERT_C(value.Has("version"), "Incorrect Diagnostics");
- UNIT_ASSERT_C(value.Has("query_text"), "Incorrect Diagnostics");
+ UNIT_ASSERT_C(!value.Has("query_text"), "Incorrect Diagnostics");
UNIT_ASSERT_C(value.Has("query_parameter_types"), "Incorrect Diagnostics");
UNIT_ASSERT_C(value.Has("table_metadata"), "Incorrect Diagnostics");
UNIT_ASSERT_C(value["table_metadata"].IsArray(), "Incorrect Diagnostics: table_metadata type should be an array");
@@ -2706,7 +2706,7 @@ Y_UNIT_TEST_SUITE(KqpIndexes) {
UNIT_ASSERT_C(value.Has("query_syntax"), "Incorrect Diagnostics");
UNIT_ASSERT_C(value.Has("query_database"), "Incorrect Diagnostics");
UNIT_ASSERT_C(value.Has("query_cluster"), "Incorrect Diagnostics");
- UNIT_ASSERT_C(value.Has("query_plan"), "Incorrect Diagnostics");
+ UNIT_ASSERT_C(!value.Has("query_plan"), "Incorrect Diagnostics");
UNIT_ASSERT_C(value.Has("query_type"), "Incorrect Diagnostics");
}
diff --git a/ydb/core/kqp/ut/olap/helpers/query_executor.cpp b/ydb/core/kqp/ut/olap/helpers/query_executor.cpp
index 7dbf61dd2f..648b5db6b9 100644
--- a/ydb/core/kqp/ut/olap/helpers/query_executor.cpp
+++ b/ydb/core/kqp/ut/olap/helpers/query_executor.cpp
@@ -5,13 +5,13 @@
namespace NKikimr::NKqp {
-TVector<THashMap<TString, NYdb::TValue>> CollectRows(NYdb::NTable::TScanQueryPartIterator& it, NJson::TJsonValue* statInfo /*= nullptr*/, NJson::TJsonValue* diagnostics /*= nullptr*/) {
+TVector<THashMap<TString, NYdb::TValue>> CollectRows(NYdb::NTable::TScanQueryPartIterator& it, NJson::TJsonValue* statInfo /*= nullptr*/, NJson::TJsonValue* meta /*= nullptr*/) {
TVector<THashMap<TString, NYdb::TValue>> rows;
if (statInfo) {
*statInfo = NJson::JSON_NULL;
}
- if (diagnostics) {
- *diagnostics = NJson::JSON_NULL;
+ if (meta) {
+ *meta = NJson::JSON_NULL;
}
for (;;) {
auto streamPart = it.ReadNext().GetValueSync();
@@ -28,12 +28,10 @@ TVector<THashMap<TString, NYdb::TValue>> CollectRows(NYdb::NTable::TScanQueryPar
if (plan && statInfo) {
UNIT_ASSERT(NJson::ReadJsonFastTree(*plan, statInfo));
}
- }
- if (streamPart.HasDiagnostics()) {
- auto diagnosticsString = TString{streamPart.GetDiagnostics()};
- if (!diagnosticsString.empty() && diagnostics) {
- UNIT_ASSERT(NJson::ReadJsonFastTree(diagnosticsString, diagnostics));
+ auto metaString = streamPart.GetQueryStats().GetMeta();
+ if (metaString && !metaString->empty() && meta) {
+ UNIT_ASSERT(NJson::ReadJsonFastTree(*metaString, meta));
}
}
@@ -70,4 +68,4 @@ TVector<THashMap<TString, NYdb::TValue>> ExecuteScanQuery(NYdb::NTable::TTableCl
return rows;
}
-} \ No newline at end of file
+}
diff --git a/ydb/core/kqp/ut/olap/kqp_olap_ut.cpp b/ydb/core/kqp/ut/olap/kqp_olap_ut.cpp
index c7af14d52d..a592340f6e 100644
--- a/ydb/core/kqp/ut/olap/kqp_olap_ut.cpp
+++ b/ydb/core/kqp/ut/olap/kqp_olap_ut.cpp
@@ -221,7 +221,7 @@ Y_UNIT_TEST_SUITE(KqpOlap) {
Y_UNIT_TEST(AlterObjectDisabled) {
auto settings = TKikimrSettings()
.SetWithSampleTables(false);
- TKikimrRunner kikimr(settings);
+ TKikimrRunner kikimr(settings);
TLocalHelper(kikimr).CreateTestOlapTableWithoutStore();
{
@@ -380,7 +380,7 @@ Y_UNIT_TEST_SUITE(KqpOlap) {
}
}
- Y_UNIT_TEST(SimpleQueryOlapDiagnostics) {
+ Y_UNIT_TEST(SimpleQueryOlapMeta) {
auto settings = TKikimrSettings()
.SetWithSampleTables(false);
TKikimrRunner kikimr(settings);
@@ -393,7 +393,7 @@ Y_UNIT_TEST_SUITE(KqpOlap) {
{
TStreamExecScanQuerySettings settings;
- settings.CollectQueryStats(ECollectQueryStatsMode::Full);
+ settings.CollectQueryStats(ECollectQueryStatsMode::Basic);
auto it = client.StreamExecuteScanQuery(R"(
--!syntax_v1
SELECT `resource_id`, `timestamp`
@@ -402,15 +402,15 @@ Y_UNIT_TEST_SUITE(KqpOlap) {
)", settings).GetValueSync();
UNIT_ASSERT_C(it.IsSuccess(), it.GetIssues().ToString());
- NJson::TJsonValue jsonDiagnostics;
- CollectRows(it, nullptr, &jsonDiagnostics);
- UNIT_ASSERT_C(!jsonDiagnostics.IsDefined(), "Query result diagnostics should be empty, but it's not");
+ NJson::TJsonValue jsonMeta;
+ CollectRows(it, nullptr, &jsonMeta);
+ UNIT_ASSERT_C(!jsonMeta.IsDefined(), "Query result meta should be empty, but it's not");
}
{
TStreamExecScanQuerySettings settings;
settings.CollectQueryStats(ECollectQueryStatsMode::Full);
- settings.CollectFullDiagnostics(true);
+
auto it = client.StreamExecuteScanQuery(R"(
--!syntax_v1
SELECT `resource_id`, `timestamp`
@@ -419,22 +419,22 @@ Y_UNIT_TEST_SUITE(KqpOlap) {
)", settings).GetValueSync();
UNIT_ASSERT_C(it.IsSuccess(), it.GetIssues().ToString());
- NJson::TJsonValue jsonDiagnostics;
- CollectRows(it, nullptr, &jsonDiagnostics);
- UNIT_ASSERT(!jsonDiagnostics.IsNull());
-
- UNIT_ASSERT_C(jsonDiagnostics.IsMap(), "Incorrect Diagnostics");
- UNIT_ASSERT_C(jsonDiagnostics.Has("query_id"), "Incorrect Diagnostics");
- UNIT_ASSERT_C(jsonDiagnostics.Has("version"), "Incorrect Diagnostics");
- UNIT_ASSERT_C(jsonDiagnostics.Has("query_text"), "Incorrect Diagnostics");
- UNIT_ASSERT_C(jsonDiagnostics.Has("query_parameter_types"), "Incorrect Diagnostics");
- UNIT_ASSERT_C(jsonDiagnostics.Has("table_metadata"), "Incorrect Diagnostics");
- UNIT_ASSERT_C(jsonDiagnostics.Has("created_at"), "Incorrect Diagnostics");
- UNIT_ASSERT_C(jsonDiagnostics.Has("query_syntax"), "Incorrect Diagnostics");
- UNIT_ASSERT_C(jsonDiagnostics.Has("query_database"), "Incorrect Diagnostics");
- UNIT_ASSERT_C(jsonDiagnostics.Has("query_cluster"), "Incorrect Diagnostics");
- UNIT_ASSERT_C(jsonDiagnostics.Has("query_plan"), "Incorrect Diagnostics");
- UNIT_ASSERT_C(jsonDiagnostics.Has("query_type"), "Incorrect Diagnostics");
+ NJson::TJsonValue jsonMeta;
+ CollectRows(it, nullptr, &jsonMeta);
+ UNIT_ASSERT(!jsonMeta.IsNull());
+
+ UNIT_ASSERT_C(jsonMeta.IsMap(), "Incorrect Meta");
+ UNIT_ASSERT_C(jsonMeta.Has("query_id"), "Incorrect Meta");
+ UNIT_ASSERT_C(jsonMeta.Has("version"), "Incorrect Meta");
+ UNIT_ASSERT_C(!jsonMeta.Has("query_text"), "Incorrect Meta");
+ UNIT_ASSERT_C(jsonMeta.Has("query_parameter_types"), "Incorrect Meta");
+ UNIT_ASSERT_C(jsonMeta.Has("table_metadata"), "Incorrect Meta");
+ UNIT_ASSERT_C(jsonMeta.Has("created_at"), "Incorrect Meta");
+ UNIT_ASSERT_C(jsonMeta.Has("query_syntax"), "Incorrect Meta");
+ UNIT_ASSERT_C(jsonMeta.Has("query_database"), "Incorrect Meta");
+ UNIT_ASSERT_C(jsonMeta.Has("query_cluster"), "Incorrect Meta");
+ UNIT_ASSERT_C(!jsonMeta.Has("query_plan"), "Incorrect Meta");
+ UNIT_ASSERT_C(jsonMeta.Has("query_type"), "Incorrect Meta");
}
}
@@ -2785,7 +2785,7 @@ Y_UNIT_TEST_SUITE(KqpOlap) {
auto alterQuery =
TStringBuilder() <<
R"(ALTER OBJECT `/Root/olapStore` (TYPE TABLESTORE) SET (ACTION=UPSERT_OPTIONS, `COMPACTION_PLANNER.CLASS_NAME`=`lc-buckets`, `COMPACTION_PLANNER.FEATURES`=`
- {"levels" : [{"class_name" : "Zero", "portions_live_duration" : "180s", "expected_blobs_size" : 2048000},
+ {"levels" : [{"class_name" : "Zero", "portions_live_duration" : "180s", "expected_blobs_size" : 2048000},
{"class_name" : "Zero", "expected_blobs_size" : 2048000}, {"class_name" : "Zero"}]}`);
)";
auto session = tableClient.CreateSession().GetValueSync().GetSession();
@@ -2821,7 +2821,7 @@ Y_UNIT_TEST_SUITE(KqpOlap) {
{
auto alterQuery =
R"(ALTER OBJECT `/Root/olapStore` (TYPE TABLESTORE) SET (ACTION=UPSERT_OPTIONS, `COMPACTION_PLANNER.CLASS_NAME`=`lc-buckets`, `COMPACTION_PLANNER.FEATURES`=`
- {"levels" : [{"class_name" : "Zero", "expected_blobs_size" : 1, "portions_count_available" : 3},
+ {"levels" : [{"class_name" : "Zero", "expected_blobs_size" : 1, "portions_count_available" : 3},
{"class_name" : "Zero"}]}`);
)";
auto result = session.ExecuteQuery(alterQuery, NQuery::TTxControl::NoTx()).GetValueSync();
diff --git a/ydb/core/kqp/ut/query/kqp_query_ut.cpp b/ydb/core/kqp/ut/query/kqp_query_ut.cpp
index 88ed1d8600..4549a493ad 100644
--- a/ydb/core/kqp/ut/query/kqp_query_ut.cpp
+++ b/ydb/core/kqp/ut/query/kqp_query_ut.cpp
@@ -179,6 +179,78 @@ Y_UNIT_TEST_SUITE(KqpQuery) {
UNIT_ASSERT_VALUES_EQUAL(counters.RecompileRequestGet()->Val(), 1);
}
+ Y_UNIT_TEST(ExecuteDataQueryCollectMeta) {
+ auto setting = NKikimrKqp::TKqpSetting();
+ auto serverSettings = TKikimrSettings()
+ .SetKqpSettings({setting});
+
+ TKikimrRunner kikimr(serverSettings);
+ auto db = kikimr.GetTableClient();
+ auto session = db.CreateSession().GetValueSync().GetSession();
+
+ {
+ UNIT_ASSERT(session.ExecuteSchemeQuery(R"(
+ CREATE TABLE `/Root/TestTable` (
+ Key Uint64,
+ Value String,
+ PRIMARY KEY (Key)
+ );
+ )").GetValueSync().IsSuccess());
+ }
+
+ {
+ const TString query(Q1_(R"(
+ SELECT * FROM `/Root/TestTable`;
+ )"));
+
+ {
+ auto settings = TExecDataQuerySettings();
+ settings.CollectQueryStats(ECollectQueryStatsMode::Full);
+
+ auto result = session.ExecuteDataQuery(query, TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+
+ UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString().c_str());
+
+ auto stats = result.GetStats();
+ UNIT_ASSERT(stats.has_value());
+
+ UNIT_ASSERT_C(stats->GetMeta().has_value(), "Query result meta is empty");
+
+ TStringStream in;
+ in << stats->GetMeta().value();
+ NJson::TJsonValue value;
+ ReadJsonTree(&in, &value);
+
+ UNIT_ASSERT_C(value.IsMap(), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_id"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("version"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_parameter_types"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("table_metadata"), "Incorrect Meta");
+ UNIT_ASSERT_C(value["table_metadata"].IsArray(), "Incorrect Meta: table_metadata type should be an array");
+ UNIT_ASSERT_C(value.Has("created_at"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_syntax"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_database"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_cluster"), "Incorrect Meta");
+ UNIT_ASSERT_C(!value.Has("query_plan"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_type"), "Incorrect Meta");
+ }
+
+ {
+ auto settings = TExecDataQuerySettings();
+ settings.CollectQueryStats(ECollectQueryStatsMode::Basic);
+
+ auto result = session.ExecuteDataQuery(query, TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+
+ UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString().c_str());
+
+ auto stats = result.GetStats();
+ UNIT_ASSERT(stats.has_value());
+
+ UNIT_ASSERT_C(!stats->GetMeta().has_value(), "Query result meta should be empty, but it's not");
+ }
+ }
+ }
+
Y_UNIT_TEST(QueryCachePermissionsLoss) {
TKikimrRunner kikimr;
auto db = kikimr.GetTableClient();
diff --git a/ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp b/ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp
index b27852b656..7daf90f727 100644
--- a/ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp
+++ b/ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp
@@ -650,6 +650,216 @@ Y_UNIT_TEST_SUITE(KqpQueryService) {
}
}
+ Y_UNIT_TEST(ExecuteCollectMeta) {
+ auto kikimr = DefaultKikimrRunner();
+ auto db = kikimr.GetQueryClient();
+
+ {
+ TExecuteQuerySettings settings;
+ settings.StatsMode(EStatsMode::Full);
+
+ auto result = db.ExecuteQuery(R"(
+ SELECT Key, Value2 FROM TwoShard WHERE Value2 > 0;
+ )", TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+
+ UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
+ auto& stats = NYdb::TProtoAccessor::GetProto(*result.GetStats());
+ UNIT_ASSERT_C(!stats.query_meta().empty(), "Query result meta is empty");
+
+ TStringStream in;
+ in << stats.query_meta();
+ NJson::TJsonValue value;
+ ReadJsonTree(&in, &value);
+
+ UNIT_ASSERT_C(value.IsMap(), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_id"), "Incorrect Meta");
+ UNIT_ASSERT_C(!value.Has("query_text"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("version"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_parameter_types"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("table_metadata"), "Incorrect Meta");
+ UNIT_ASSERT_C(value["table_metadata"].IsArray(), "Incorrect Meta: table_metadata type should be an array");
+ UNIT_ASSERT_C(value.Has("created_at"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_syntax"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_database"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_cluster"), "Incorrect Meta");
+ UNIT_ASSERT_C(!value.Has("query_plan"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_type"), "Incorrect Meta");
+ }
+
+ {
+ TExecuteQuerySettings settings;
+ settings.StatsMode(EStatsMode::Basic);
+
+ auto result = db.ExecuteQuery(R"(
+ SELECT Key, Value2 FROM TwoShard WHERE Value2 > 0;
+ )", TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+
+ UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString().c_str());
+
+ auto& stats = NYdb::TProtoAccessor::GetProto(*result.GetStats());
+ UNIT_ASSERT_C(stats.query_meta().empty(), "Query result Meta should be empty, but it's not");
+ }
+
+ {
+ TExecuteQuerySettings settings;
+ settings.ExecMode(EExecMode::Explain);
+
+ auto result = db.ExecuteQuery(R"(
+ SELECT Key, Value2 FROM TwoShard WHERE Value2 > 0;
+ )", TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
+ UNIT_ASSERT(result.GetResultSets().empty());
+
+ UNIT_ASSERT(result.GetStats().has_value());
+
+ auto& stats = NYdb::TProtoAccessor::GetProto(*result.GetStats());
+ UNIT_ASSERT_C(!stats.query_ast().empty(), "Query result ast is empty");
+ UNIT_ASSERT_C(!stats.query_meta().empty(), "Query result meta is empty");
+
+ TStringStream in;
+ in << stats.query_meta();
+ NJson::TJsonValue value;
+ ReadJsonTree(&in, &value);
+
+ UNIT_ASSERT_C(value.IsMap(), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_id"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("version"), "Incorrect Meta");
+ UNIT_ASSERT_C(!value.Has("query_text"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_parameter_types"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("table_metadata"), "Incorrect Meta");
+ UNIT_ASSERT_C(value["table_metadata"].IsArray(), "Incorrect Meta: table_metadata type should be an array");
+ UNIT_ASSERT_C(value.Has("created_at"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_syntax"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_database"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_cluster"), "Incorrect Meta");
+ UNIT_ASSERT_C(!value.Has("query_plan"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_type"), "Incorrect Meta");
+ }
+ }
+
+ Y_UNIT_TEST(StreamExecuteCollectMeta) {
+ auto kikimr = DefaultKikimrRunner();
+ auto db = kikimr.GetQueryClient();
+
+ {
+ TExecuteQuerySettings settings;
+ settings.StatsMode(EStatsMode::Full);
+
+ auto it = db.StreamExecuteQuery(R"(
+ SELECT Key, Value2 FROM TwoShard WHERE Value2 > 0;
+ )", TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ UNIT_ASSERT_VALUES_EQUAL_C(it.GetStatus(), EStatus::SUCCESS, it.GetIssues().ToString());
+
+ TString statsString;
+ for (;;) {
+ auto streamPart = it.ReadNext().GetValueSync();
+ if (!streamPart.IsSuccess()) {
+ UNIT_ASSERT_C(streamPart.EOS(), streamPart.GetIssues().ToString());
+ break;
+ }
+
+ const auto& execStats = streamPart.GetStats();
+ if (execStats) {
+ auto& stats = NYdb::TProtoAccessor::GetProto(*execStats);
+ statsString = stats.query_meta();
+ }
+ }
+
+ UNIT_ASSERT_C(!statsString.empty(), "Query result meta is empty");
+
+ TStringStream in;
+ in << statsString;
+ NJson::TJsonValue value;
+ ReadJsonTree(&in, &value);
+
+ UNIT_ASSERT_C(value.IsMap(), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_id"), "Incorrect Meta");
+ UNIT_ASSERT_C(!value.Has("query_text"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("version"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_parameter_types"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("table_metadata"), "Incorrect Meta");
+ UNIT_ASSERT_C(value["table_metadata"].IsArray(), "Incorrect Meta: table_metadata type should be an array");
+ UNIT_ASSERT_C(value.Has("created_at"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_syntax"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_database"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_cluster"), "Incorrect Meta");
+ UNIT_ASSERT_C(!value.Has("query_plan"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_type"), "Incorrect Meta");
+ }
+
+ {
+ auto settings = TExecuteQuerySettings().ExecMode(EExecMode::Explain);
+
+ auto it = db.StreamExecuteQuery(R"(
+ SELECT Key, Value2 FROM TwoShard WHERE Value2 > 0;
+ )", TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ UNIT_ASSERT_VALUES_EQUAL_C(it.GetStatus(), EStatus::SUCCESS, it.GetIssues().ToString());
+
+ TString statsString;
+ for (;;) {
+ auto streamPart = it.ReadNext().GetValueSync();
+ if (!streamPart.IsSuccess()) {
+ UNIT_ASSERT_C(streamPart.EOS(), streamPart.GetIssues().ToString());
+ break;
+ }
+
+ const auto& execStats = streamPart.GetStats();
+ if (execStats) {
+ auto& stats = NYdb::TProtoAccessor::GetProto(*execStats);
+ statsString = stats.query_meta();
+ }
+ }
+
+ UNIT_ASSERT_C(!statsString.empty(), "Query result meta is empty");
+
+ TStringStream in;
+ in << statsString;
+ NJson::TJsonValue value;
+ ReadJsonTree(&in, &value);
+
+ UNIT_ASSERT_C(value.IsMap(), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_id"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("version"), "Incorrect Meta");
+ UNIT_ASSERT_C(!value.Has("query_text"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_parameter_types"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("table_metadata"), "Incorrect Meta");
+ UNIT_ASSERT_C(value["table_metadata"].IsArray(), "Incorrect Meta: table_metadata type should be an array");
+ UNIT_ASSERT_C(value.Has("created_at"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_syntax"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_database"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_cluster"), "Incorrect Meta");
+ UNIT_ASSERT_C(!value.Has("query_plan"), "Incorrect Meta");
+ UNIT_ASSERT_C(value.Has("query_type"), "Incorrect Meta");
+ }
+
+ {
+ TExecuteQuerySettings settings;
+ settings.StatsMode(EStatsMode::Basic);
+
+ auto it = db.StreamExecuteQuery(R"(
+ SELECT Key, Value2 FROM TwoShard WHERE Value2 > 0;
+ )", TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ UNIT_ASSERT_VALUES_EQUAL_C(it.GetStatus(), EStatus::SUCCESS, it.GetIssues().ToString());
+
+ TString statsString;
+ for (;;) {
+ auto streamPart = it.ReadNext().GetValueSync();
+ if (!streamPart.IsSuccess()) {
+ UNIT_ASSERT_C(streamPart.EOS(), streamPart.GetIssues().ToString());
+ break;
+ }
+
+ const auto& execStats = streamPart.GetStats();
+ if (execStats) {
+ auto& stats = NYdb::TProtoAccessor::GetProto(*execStats);
+ statsString = stats.query_meta();
+ }
+ }
+
+ UNIT_ASSERT_C(statsString.empty(), "Query result meta should be empty, but it's not");
+ }
+ }
+
void CheckQueryResult(TExecuteQueryResult result) {
UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
UNIT_ASSERT_VALUES_EQUAL(result.GetResultSets().size(), 1);
diff --git a/ydb/public/api/protos/ydb_query_stats.proto b/ydb/public/api/protos/ydb_query_stats.proto
index 300d5d9837..34f4f49bdb 100644
--- a/ydb/public/api/protos/ydb_query_stats.proto
+++ b/ydb/public/api/protos/ydb_query_stats.proto
@@ -43,4 +43,7 @@ message QueryStats {
string query_ast = 5;
uint64 total_duration_us = 6;
uint64 total_cpu_time_us = 7;
+ // will be filled only in MODE_EXPLAIN or in MODE_EXEC with QueryStatsCollection.Mode >= STATS_COLLECTION_FULL,
+ // collects additional meta about query compilation, including table metadata
+ string query_meta = 8;
}
diff --git a/ydb/public/api/protos/ydb_table.proto b/ydb/public/api/protos/ydb_table.proto
index 7a91977050..3d69ae628f 100644
--- a/ydb/public/api/protos/ydb_table.proto
+++ b/ydb/public/api/protos/ydb_table.proto
@@ -1274,7 +1274,7 @@ message ExecuteScanQueryRequest {
QueryStatsCollection.Mode collect_stats = 8;
// works only in mode: MODE_EXPLAIN,
// collects additional diagnostics about query compilation, including query plan and scheme
- bool collect_full_diagnostics = 9;
+ bool collect_full_diagnostics = 9 [deprecated=true];
}
message ExecuteScanQueryPartialResponse {
@@ -1292,7 +1292,7 @@ message ExecuteScanQueryPartialResult {
Ydb.TableStats.QueryStats query_stats = 6;
// works only in mode: MODE_EXPLAIN,
// collects additional diagnostics about query compilation, including query plan and scheme
- string query_full_diagnostics = 7;
+ string query_full_diagnostics = 7 [deprecated = true];
}
// Returns information about an external data source with a given path.
diff --git a/ydb/public/lib/ydb_cli/commands/ydb_service_table.cpp b/ydb/public/lib/ydb_cli/commands/ydb_service_table.cpp
index 08437be17a..7bf7b38233 100644
--- a/ydb/public/lib/ydb_cli/commands/ydb_service_table.cpp
+++ b/ydb/public/lib/ydb_cli/commands/ydb_service_table.cpp
@@ -9,8 +9,11 @@
#include <ydb-cpp-sdk/client/proto/accessor.h>
#include <library/cpp/json/json_prettifier.h>
+#include <library/cpp/json/json_writer.h>
+
#include <google/protobuf/util/json_util.h>
+#include <util/string/escape.h>
#include <util/string/split.h>
#include <util/folder/path.h>
#include <util/folder/dirut.h>
@@ -365,6 +368,8 @@ void TCommandExecuteQuery::Config(TConfig& config) {
config.Opts->AddLongOption('q', "query", "Text of query to execute").RequiredArgument("[String]").StoreResult(&Query);
config.Opts->AddLongOption('f', "file", "Path to file with query text to execute")
.RequiredArgument("PATH").StoreResult(&QueryFile);
+ config.Opts->AddLongOption("diagnostics-file", "Path to file where the diagnostics will be saved.")
+ .RequiredArgument("[String]").StoreResult(&DiagnosticsFile);
AddOutputFormats(config, {
EDataFormat::Pretty,
@@ -507,13 +512,51 @@ void TCommandExecuteQuery::PrintDataQueryResponse(NTable::TDataQueryResult& resu
}
} // TResultSetPrinter destructor should be called before printing stats
+ std::optional<std::string> statsStr;
+ std::optional<std::string> plan;
+ std::optional<std::string> ast;
+ std::optional<std::string> meta;
+
const std::optional<NTable::TQueryStats>& stats = result.GetStats();
if (stats.has_value()) {
- Cout << Endl << "Statistics:" << Endl << stats->ToString();
- PrintFlameGraph(stats->GetPlan());
+ if (stats->GetMeta()) {
+ meta = stats->GetMeta();
+ }
+ if (stats->GetPlan()) {
+ plan = stats->GetPlan();
+ }
+ ast = stats->GetAst();
+ statsStr = stats->ToString();
+ Cout << Endl << "Statistics:" << Endl << statsStr;
+ PrintFlameGraph(plan);
}
- if (FlameGraphPath && !stats.has_value())
- {
+
+ if (!DiagnosticsFile.empty()) {
+ TFileOutput file(DiagnosticsFile);
+
+ NJson::TJsonValue diagnosticsJson(NJson::JSON_MAP);
+
+ if (statsStr) {
+ diagnosticsJson.InsertValue("stats", *statsStr);
+ }
+ if (ast) {
+ diagnosticsJson.InsertValue("ast", *ast);
+ }
+ if (plan) {
+ NJson::TJsonValue planJson;
+ NJson::ReadJsonTree(*plan, &planJson, true);
+ diagnosticsJson.InsertValue("plan", planJson);
+ }
+ if (meta) {
+ NJson::TJsonValue metaJson;
+ NJson::ReadJsonTree(*meta, &metaJson, true);
+ metaJson.InsertValue("query_text", EscapeC(Query));
+ diagnosticsJson.InsertValue("meta", metaJson);
+ }
+ file << NJson::PrettifyJson(NJson::WriteJson(diagnosticsJson, true), false);
+ }
+
+ if (FlameGraphPath && !stats.has_value()) {
Cout << Endl << "Flame graph is available for full or profile stats only" << Endl;
}
}
@@ -635,7 +678,7 @@ namespace {
}
Y_UNREACHABLE();
}
-
+
template <typename TQueryPart>
const NQuery::TExecStats& GetStats(const TQueryPart& part) {
if constexpr (std::is_same_v<TQueryPart, NTable::TScanQueryPart>) {
@@ -730,8 +773,10 @@ int TCommandExecuteQuery::ExecuteQueryImpl(TConfig& config) {
template <typename TIterator>
bool TCommandExecuteQuery::PrintQueryResponse(TIterator& result) {
- TMaybe<TString> stats;
+ std::optional<std::string> stats;
std::optional<std::string> fullStats;
+ std::optional<std::string> meta;
+ std::optional<std::string> ast;
{
TResultSetPrinter printer(OutputFormat, &IsInterrupted);
@@ -748,10 +793,14 @@ bool TCommandExecuteQuery::PrintQueryResponse(TIterator& result) {
if (HasStats(streamPart)) {
const auto& queryStats = GetStats(streamPart);
stats = queryStats.ToString();
+ ast = queryStats.GetAst();
if (queryStats.GetPlan()) {
fullStats = queryStats.GetPlan();
}
+ if (queryStats.GetMeta()) {
+ meta = queryStats.GetMeta();
+ }
}
}
} // TResultSetPrinter destructor should be called before printing stats
@@ -767,6 +816,31 @@ bool TCommandExecuteQuery::PrintQueryResponse(TIterator& result) {
queryPlanPrinter.Print(TString{*fullStats});
}
+ if (!DiagnosticsFile.empty()) {
+ TFileOutput file(DiagnosticsFile);
+
+ NJson::TJsonValue diagnosticsJson(NJson::JSON_MAP);
+
+ if (stats) {
+ diagnosticsJson.InsertValue("stats", *stats);
+ }
+ if (ast) {
+ diagnosticsJson.InsertValue("ast", *ast);
+ }
+ if (fullStats) {
+ NJson::TJsonValue planJson;
+ NJson::ReadJsonTree(*fullStats, &planJson, true);
+ diagnosticsJson.InsertValue("plan", planJson);
+ }
+ if (meta) {
+ NJson::TJsonValue metaJson;
+ NJson::ReadJsonTree(*meta, &metaJson, true);
+ metaJson.InsertValue("query_text", EscapeC(Query));
+ diagnosticsJson.InsertValue("meta", metaJson);
+ }
+ file << NJson::PrettifyJson(NJson::WriteJson(diagnosticsJson, true), false);
+ }
+
PrintFlameGraph(fullStats);
if (IsInterrupted()) {
@@ -1029,7 +1103,7 @@ void TCommandReadTable::Config(TConfig& config) {
.NoArgument().SetFlag(&FromExclusive);
config.Opts->AddLongOption("to-exclusive", "Don't include the right border element into response")
.NoArgument().SetFlag(&ToExclusive);
-
+
AddLegacyJsonInputFormats(config);
AddOutputFormats(config, {
diff --git a/ydb/public/lib/ydb_cli/commands/ydb_service_table.h b/ydb/public/lib/ydb_cli/commands/ydb_service_table.h
index 041543abb3..a1c690708e 100644
--- a/ydb/public/lib/ydb_cli/commands/ydb_service_table.h
+++ b/ydb/public/lib/ydb_cli/commands/ydb_service_table.h
@@ -123,6 +123,7 @@ private:
TString TxMode;
TString QueryType;
bool BasicStats = false;
+ TString DiagnosticsFile;
};
class TCommandExplain : public TTableCommand, public TCommandWithOutput, TCommandQueryBase, TInterruptibleCommand {
diff --git a/ydb/public/lib/ydb_cli/commands/ydb_sql.cpp b/ydb/public/lib/ydb_cli/commands/ydb_sql.cpp
index b11f65a2ef..5ca0e0a7e9 100644
--- a/ydb/public/lib/ydb_cli/commands/ydb_sql.cpp
+++ b/ydb/public/lib/ydb_cli/commands/ydb_sql.cpp
@@ -1,6 +1,8 @@
#include "ydb_sql.h"
#include <library/cpp/json/json_reader.h>
+#include <library/cpp/json/json_writer.h>
+#include <library/cpp/json/json_prettifier.h>
#include <ydb/public/lib/json_value/ydb_json_value.h>
#include <ydb-cpp-sdk/library/operation_id/operation_id.h>
#include <ydb/public/lib/ydb_cli/common/interactive.h>
@@ -10,6 +12,7 @@
#include <ydb/public/lib/ydb_cli/common/waiting_bar.h>
#include <ydb-cpp-sdk/client/proto/accessor.h>
#include <util/generic/queue.h>
+#include <util/string/escape.h>
#include <google/protobuf/text_format.h>
namespace NYdb {
@@ -40,6 +43,8 @@ void TCommandSql::Config(TConfig& config) {
.StoreTrue(&ExplainAnalyzeMode);
config.Opts->AddLongOption("stats", "Execution statistics collection mode [none, basic, full, profile]")
.RequiredArgument("[String]").StoreResult(&CollectStatsMode);
+ config.Opts->AddLongOption("diagnostics-file", "Path to file where the diagnostics will be saved.")
+ .RequiredArgument("[String]").StoreResult(&DiagnosticsFile);
config.Opts->AddLongOption("syntax", "Query syntax [yql, pg]")
.RequiredArgument("[String]").DefaultValue("yql").StoreResult(&Syntax)
.Hidden();
@@ -183,6 +188,7 @@ int TCommandSql::PrintResponse(NQuery::TExecuteQueryIterator& result) {
std::optional<std::string> stats;
std::optional<std::string> plan;
std::optional<std::string> ast;
+ std::optional<std::string> meta;
{
TResultSetPrinter printer(OutputFormat, &IsInterrupted);
@@ -204,13 +210,16 @@ int TCommandSql::PrintResponse(NQuery::TExecuteQueryIterator& result) {
if (queryStats.GetPlan()) {
plan = queryStats.GetPlan();
}
+ if (queryStats.GetMeta()) {
+ meta = queryStats.GetMeta();
+ }
}
}
} // TResultSetPrinter destructor should be called before printing stats
if (ExplainAst) {
Cout << "Query AST:" << Endl << ast << Endl;
-
+
if (IsInterrupted()) {
Cerr << "<INTERRUPTED>" << Endl;
return EXIT_FAILURE;
@@ -235,6 +244,31 @@ int TCommandSql::PrintResponse(NQuery::TExecuteQueryIterator& result) {
queryPlanPrinter.Print(TString{*plan});
}
+ if (!DiagnosticsFile.empty()) {
+ TFileOutput file(DiagnosticsFile);
+
+ NJson::TJsonValue diagnosticsJson(NJson::JSON_MAP);
+
+ if (stats) {
+ diagnosticsJson.InsertValue("stats", *stats);
+ }
+ if (ast) {
+ diagnosticsJson.InsertValue("ast", *ast);
+ }
+ if (plan) {
+ NJson::TJsonValue planJson;
+ NJson::ReadJsonTree(*plan, &planJson, true);
+ diagnosticsJson.InsertValue("plan", planJson);
+ }
+ if (meta) {
+ NJson::TJsonValue metaJson;
+ NJson::ReadJsonTree(*meta, &metaJson, true);
+ metaJson.InsertValue("query_text", EscapeC(Query));
+ diagnosticsJson.InsertValue("meta", metaJson);
+ }
+ file << NJson::PrettifyJson(NJson::WriteJson(diagnosticsJson, true), false);
+ }
+
if (IsInterrupted()) {
Cerr << "<INTERRUPTED>" << Endl;
return EXIT_FAILURE;
diff --git a/ydb/public/lib/ydb_cli/commands/ydb_sql.h b/ydb/public/lib/ydb_cli/commands/ydb_sql.h
index fc86a9dc3b..bfa617ae66 100644
--- a/ydb/public/lib/ydb_cli/commands/ydb_sql.h
+++ b/ydb/public/lib/ydb_cli/commands/ydb_sql.h
@@ -28,6 +28,7 @@ private:
int PrintResponse(NQuery::TExecuteQueryIterator& result);
TString CollectStatsMode;
+ TString DiagnosticsFile;
TString Query;
TString QueryFile;
TString Syntax;
diff --git a/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/query/stats.h b/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/query/stats.h
index 902478b446..0b7ca6cc6d 100644
--- a/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/query/stats.h
+++ b/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/query/stats.h
@@ -29,6 +29,7 @@ public:
std::optional<std::string> GetPlan() const;
std::optional<std::string> GetAst() const;
+ std::optional<std::string> GetMeta() const;
TDuration GetTotalDuration() const;
TDuration GetTotalCpuTime() const;
diff --git a/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/table/query_stats/stats.h b/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/table/query_stats/stats.h
index 38740d2dd1..9eda4620ff 100644
--- a/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/table/query_stats/stats.h
+++ b/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/table/query_stats/stats.h
@@ -30,7 +30,7 @@ namespace NTable {
enum class ECollectQueryStatsMode {
None = 0, // Stats collection is disabled
Basic = 1, // Aggregated stats of reads, updates and deletes per table
- Full = 2, // Add per-stage execution profile and query plan on top of Basic mode
+ Full = 2, // Add per-stage execution profile, query plan and query meta on top of Basic mode
Profile = 3 // Detailed execution stats including stats for individual tasks and channels
};
diff --git a/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/table/table.h b/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/table/table.h
index df5b02d916..e83101f28d 100644
--- a/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/table/table.h
+++ b/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/table/table.h
@@ -1164,6 +1164,7 @@ struct TStreamExecScanQuerySettings : public TRequestSettings<TStreamExecScanQue
// Collect runtime statistics with a given detalization mode
FLUENT_SETTING_DEFAULT(ECollectQueryStatsMode, CollectQueryStats, ECollectQueryStatsMode::None);
+ // Deprecated. Use CollectQueryStats >= ECollectQueryStatsMode::Full to get QueryMeta in QueryStats
// Collect full query compilation diagnostics
FLUENT_SETTING_DEFAULT(bool, CollectFullDiagnostics, false);
};
@@ -2109,6 +2110,7 @@ public:
const TQueryStats& GetQueryStats() const { return *QueryStats_; }
TQueryStats ExtractQueryStats() { return std::move(*QueryStats_); }
+ // Deprecated. Use GetMeta() of TQueryStats
bool HasDiagnostics() const { return Diagnostics_.has_value(); }
const std::string& GetDiagnostics() const { return *Diagnostics_; }
std::string&& ExtractDiagnostics() { return std::move(*Diagnostics_); }
diff --git a/ydb/public/sdk/cpp/src/client/query/stats.cpp b/ydb/public/sdk/cpp/src/client/query/stats.cpp
index e56d5533f6..5106687f23 100644
--- a/ydb/public/sdk/cpp/src/client/query/stats.cpp
+++ b/ydb/public/sdk/cpp/src/client/query/stats.cpp
@@ -31,6 +31,7 @@ std::string TExecStats::ToString(bool withPlan) const {
if (!withPlan) {
proto.clear_query_plan();
proto.clear_query_ast();
+ proto.clear_query_meta();
}
TStringType res;
@@ -58,6 +59,16 @@ std::optional<std::string> TExecStats::GetAst() const {
return proto.query_ast();
}
+std::optional<std::string> TExecStats::GetMeta() const {
+ auto proto = Impl_->Proto;
+
+ if (proto.query_meta().empty()) {
+ return {};
+ }
+
+ return proto.query_meta();
+}
+
TDuration TExecStats::GetTotalDuration() const {
return TDuration::MicroSeconds(Impl_->Proto.total_duration_us());
}