aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraidarsamer <aidarsamer@ydb.tech>2023-04-18 19:35:33 +0300
committeraidarsamer <aidarsamer@ydb.tech>2023-04-18 19:35:33 +0300
commitb0dc1a49941be300fa164dcb9ae79235e5def21f (patch)
tree0a318ea0022bd085d3d127cf8c52fe40424bc059
parent2a82c4821062c12e48bc7241f02ea8d72f19f8e8 (diff)
downloadydb-b0dc1a49941be300fa164dcb9ae79235e5def21f.tar.gz
Add limit pushdown to OLAP tables if TopSort by PK columns
-rw-r--r--ydb/core/kqp/opt/physical/kqp_opt_phy.cpp7
-rw-r--r--ydb/core/kqp/opt/physical/kqp_opt_phy_helpers.cpp70
-rw-r--r--ydb/core/kqp/opt/physical/kqp_opt_phy_impl.h20
-rw-r--r--ydb/core/kqp/opt/physical/kqp_opt_phy_limit.cpp99
-rw-r--r--ydb/core/kqp/opt/physical/kqp_opt_phy_rules.h3
-rw-r--r--ydb/core/kqp/opt/physical/kqp_opt_phy_sort.cpp86
-rw-r--r--ydb/core/kqp/ut/olap/kqp_olap_ut.cpp6
-rw-r--r--ydb/tests/functional/clickbench/canondata/test.test_plans_column_/queries-original-plan-column-235
-rw-r--r--ydb/tests/functional/clickbench/canondata/test.test_plans_column_/queries-original-plan-column-245
-rw-r--r--ydb/tests/functional/clickbench/canondata/test.test_run_determentistic_column_/queries-deterministic-results-244
-rw-r--r--ydb/tests/functional/clickbench/canondata/test.test_run_determentistic_row_/queries-deterministic-results-244
-rw-r--r--ydb/tests/functional/clickbench/data/queries-deterministic.sql2
12 files changed, 228 insertions, 83 deletions
diff --git a/ydb/core/kqp/opt/physical/kqp_opt_phy.cpp b/ydb/core/kqp/opt/physical/kqp_opt_phy.cpp
index 2cc8d54b9d0..bea79d22d2b 100644
--- a/ydb/core/kqp/opt/physical/kqp_opt_phy.cpp
+++ b/ydb/core/kqp/opt/physical/kqp_opt_phy.cpp
@@ -36,6 +36,7 @@ public:
AddHandler(0, &TKqlStreamLookupTable::Match, HNDL(BuildStreamLookupTableStages));
AddHandler(0, [](auto) { return true; }, HNDL(RemoveRedundantSortByPk));
AddHandler(0, &TCoTake::Match, HNDL(ApplyLimitToReadTable));
+ AddHandler(0, &TCoTopSort::Match, HNDL(ApplyLimitToOlapReadTable));
AddHandler(0, &TCoFlatMap::Match, HNDL(PushOlapFilter));
AddHandler(0, &TCoAggregateCombine::Match, HNDL(PushAggregateCombineToStage));
AddHandler(0, &TCoAggregateCombine::Match, HNDL(PushOlapAggregate));
@@ -163,6 +164,12 @@ protected:
return output;
}
+ TMaybeNode<TExprBase> ApplyLimitToOlapReadTable(TExprBase node, TExprContext& ctx) {
+ TExprBase output = KqpApplyLimitToOlapReadTable(node, ctx, KqpCtx);
+ DumpAppliedRule("ApplyLimitToOlapReadTable", node.Ptr(), output.Ptr(), ctx);
+ return output;
+ }
+
TMaybeNode<TExprBase> PushOlapFilter(TExprBase node, TExprContext& ctx) {
TExprBase output = KqpPushOlapFilter(node, ctx, KqpCtx, TypesCtx);
DumpAppliedRule("PushOlapFilter", node.Ptr(), output.Ptr(), ctx);
diff --git a/ydb/core/kqp/opt/physical/kqp_opt_phy_helpers.cpp b/ydb/core/kqp/opt/physical/kqp_opt_phy_helpers.cpp
index 61eafa6e489..ca85448ed3b 100644
--- a/ydb/core/kqp/opt/physical/kqp_opt_phy_helpers.cpp
+++ b/ydb/core/kqp/opt/physical/kqp_opt_phy_helpers.cpp
@@ -1,4 +1,7 @@
+#include "kqp_opt_phy_impl.h"
+
#include <ydb/core/kqp/common/kqp_yql.h>
+#include <ydb/core/kqp/provider/yql_kikimr_provider.h>
namespace NKikimr::NKqp::NOpt {
@@ -167,4 +170,71 @@ NYql::NNodes::TDqStage ReplaceTableSourceSettings(NYql::NNodes::TDqStage stage,
.Done();
}
+bool IsSortKeyPrimary(const NYql::NNodes::TCoLambda& keySelector, const NYql::TKikimrTableDescription& tableDesc,
+ const TMaybe<THashSet<TStringBuf>>& passthroughFields)
+{
+ auto checkKey = [keySelector, &tableDesc, &passthroughFields] (NYql::NNodes::TExprBase key, ui32 index) {
+ if (!key.Maybe<TCoMember>()) {
+ return false;
+ }
+
+ auto member = key.Cast<TCoMember>();
+ if (member.Struct().Raw() != keySelector.Args().Arg(0).Raw()) {
+ return false;
+ }
+
+ auto column = TString(member.Name().Value());
+ auto columnIndex = tableDesc.GetKeyColumnIndex(column);
+ if (!columnIndex || *columnIndex != index) {
+ return false;
+ }
+
+ if (passthroughFields && !passthroughFields->contains(column)) {
+ return false;
+ }
+
+ return true;
+ };
+
+ auto lambdaBody = keySelector.Body();
+ if (auto maybeTuple = lambdaBody.Maybe<TExprList>()) {
+ auto tuple = maybeTuple.Cast();
+ for (size_t i = 0; i < tuple.Size(); ++i) {
+ if (!checkKey(tuple.Item(i), i)) {
+ return false;
+ }
+ }
+ } else {
+ if (!checkKey(lambdaBody, 0)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+ESortDirection GetSortDirection(const NYql::NNodes::TExprBase& sortDirections) {
+ auto getDirection = [] (TExprBase expr) -> ESortDirection {
+ if (!expr.Maybe<TCoBool>()) {
+ return ESortDirection::Unknown;
+ }
+
+ if (!FromString<bool>(expr.Cast<TCoBool>().Literal().Value())) {
+ return ESortDirection::Reverse;
+ }
+
+ return ESortDirection::Forward;
+ };
+
+ auto direction = ESortDirection::None;
+ if (auto maybeList = sortDirections.Maybe<TExprList>()) {
+ for (const auto& expr : maybeList.Cast()) {
+ direction |= getDirection(expr);
+ }
+ } else {
+ direction |= getDirection(sortDirections);
+ }
+ return direction;
+};
+
} // namespace NKikimr::NKqp::NOpt
diff --git a/ydb/core/kqp/opt/physical/kqp_opt_phy_impl.h b/ydb/core/kqp/opt/physical/kqp_opt_phy_impl.h
index 87fe7377226..d71bdb58022 100644
--- a/ydb/core/kqp/opt/physical/kqp_opt_phy_impl.h
+++ b/ydb/core/kqp/opt/physical/kqp_opt_phy_impl.h
@@ -28,6 +28,26 @@ NYql::NNodes::TDqStage ReplaceStageArg(NYql::NNodes::TDqStage stage, size_t inpu
NYql::NNodes::TDqStage ReplaceTableSourceSettings(NYql::NNodes::TDqStage stage, size_t inputIndex,
NYql::NNodes::TKqpReadRangesSourceSettings settings, NYql::TExprContext& ctx);
+bool IsSortKeyPrimary(const NYql::NNodes::TCoLambda& keySelector, const NYql::TKikimrTableDescription& tableDesc,
+ const TMaybe<THashSet<TStringBuf>>& passthroughFields = {});
+
+enum ESortDirection : ui32 {
+ None = 0,
+ Forward = 1,
+ Reverse = 2,
+ Unknown = 4,
+};
+
+using ESortDirectionRaw = std::underlying_type<ESortDirection>::type;
+
+inline ESortDirection operator|(ESortDirection a, ESortDirection b) {
+ return ESortDirection(static_cast<ESortDirectionRaw>(a) | static_cast<ESortDirectionRaw>(b));
+}
+
+inline ESortDirection operator|=(ESortDirection& a, ESortDirection b) { return (a = a | b); }
+
+ESortDirection GetSortDirection(const NYql::NNodes::TExprBase& sortDirections);
+
} // NKikimr::NKqp::NOpt
diff --git a/ydb/core/kqp/opt/physical/kqp_opt_phy_limit.cpp b/ydb/core/kqp/opt/physical/kqp_opt_phy_limit.cpp
index e538b09367f..59863118c78 100644
--- a/ydb/core/kqp/opt/physical/kqp_opt_phy_limit.cpp
+++ b/ydb/core/kqp/opt/physical/kqp_opt_phy_limit.cpp
@@ -87,5 +87,104 @@ TExprBase KqpApplyLimitToReadTable(TExprBase node, TExprContext& ctx, const TKqp
.Done();
}
+TExprBase KqpApplyLimitToOlapReadTable(TExprBase node, TExprContext& ctx, const TKqpOptimizeContext& kqpCtx) {
+ if (!node.Maybe<TCoTopSort>()) {
+ return node;
+ }
+ auto topSort = node.Cast<TCoTopSort>();
+
+ // Column Shards always return result sorted by PK in ASC order
+ ESortDirection direction = GetSortDirection(topSort.SortDirections());
+ if (direction != ESortDirection::Forward && direction != ESortDirection::Reverse) {
+ return node;
+ }
+
+ auto maybeSkip = topSort.Input().Maybe<TCoSkip>();
+ auto input = maybeSkip ? maybeSkip.Cast().Input() : topSort.Input();
+
+ bool isReadTable = input.Maybe<TKqpReadOlapTableRanges>().IsValid();
+
+ if (!isReadTable) {
+ return node;
+ }
+
+ if (!kqpCtx.IsScanQuery()) {
+ return node;
+ }
+
+ const bool isReadTableRanges = true;
+ auto& tableDesc = kqpCtx.Tables->ExistingTable(kqpCtx.Cluster, GetReadTablePath(input, isReadTableRanges));
+
+ if (tableDesc.Metadata->Kind != EKikimrTableKind::Olap) {
+ return node;
+ }
+
+ auto settings = GetReadTableSettings(input, isReadTableRanges);
+ if (settings.ItemsLimit) {
+ return node; // already set
+ }
+ if (direction == ESortDirection::Reverse) {
+ settings.SetReverse();
+ }
+
+ auto keySelector = topSort.KeySelectorLambda();
+ if (!IsSortKeyPrimary(keySelector, tableDesc)) {
+ // Column shards return data sorted by PK
+ // So we can pushdown limit only if query has sort by PK
+ return node;
+ }
+
+ TMaybeNode<TExprBase> limitValue;
+ auto maybeTopSortCount = topSort.Count().Maybe<TCoUint64>();
+ auto maybeSkipCount = maybeSkip.Count().Maybe<TCoUint64>();
+
+ if (maybeTopSortCount && (!maybeSkip || maybeSkipCount)) {
+ ui64 totalLimit = FromString<ui64>(maybeTopSortCount.Cast().Literal().Value());
+
+ if (maybeSkipCount) {
+ totalLimit += FromString<ui64>(maybeSkipCount.Cast().Literal().Value());
+ }
+
+ limitValue = Build<TCoUint64>(ctx, node.Pos())
+ .Literal<TCoAtom>()
+ .Value(ToString(totalLimit)).Build()
+ .Done();
+ } else {
+ limitValue = topSort.Count();
+ if (maybeSkip) {
+ limitValue = Build<TCoPlus>(ctx, node.Pos())
+ .Left(limitValue.Cast())
+ .Right(maybeSkip.Cast().Count())
+ .Done();
+ }
+ }
+
+ YQL_CLOG(TRACE, ProviderKqp) << "-- set limit items value to " << limitValue.Cast().Ref().Dump();
+
+ if (limitValue.Maybe<TCoUint64>()) {
+ settings.SetItemsLimit(limitValue.Cast().Ptr());
+ } else {
+ settings.SetItemsLimit(Build<TDqPrecompute>(ctx, node.Pos())
+ .Input(limitValue.Cast())
+ .Done().Ptr());
+ }
+
+ input = BuildReadNode(node.Pos(), ctx, input, settings);
+
+ if (maybeSkip) {
+ input = Build<TCoSkip>(ctx, node.Pos())
+ .Input(input)
+ .Count(maybeSkip.Cast().Count())
+ .Done();
+ }
+
+ return Build<TCoTopSort>(ctx, topSort.Pos())
+ .Input(input)
+ .Count(topSort.Count())
+ .SortDirections(topSort.SortDirections())
+ .KeySelectorLambda(topSort.KeySelectorLambda())
+ .Done();
+}
+
} // namespace NKikimr::NKqp::NOpt
diff --git a/ydb/core/kqp/opt/physical/kqp_opt_phy_rules.h b/ydb/core/kqp/opt/physical/kqp_opt_phy_rules.h
index 98fb1e57324..2c7e86912e5 100644
--- a/ydb/core/kqp/opt/physical/kqp_opt_phy_rules.h
+++ b/ydb/core/kqp/opt/physical/kqp_opt_phy_rules.h
@@ -29,6 +29,9 @@ NYql::NNodes::TExprBase KqpRemoveRedundantSortByPk(NYql::NNodes::TExprBase node,
NYql::NNodes::TExprBase KqpApplyLimitToReadTable(NYql::NNodes::TExprBase node, NYql::TExprContext& ctx,
const TKqpOptimizeContext& kqpCtx);
+NYql::NNodes::TExprBase KqpApplyLimitToOlapReadTable(NYql::NNodes::TExprBase node, NYql::TExprContext& ctx,
+ const TKqpOptimizeContext& kqpCtx);
+
NYql::NNodes::TExprBase KqpPushOlapFilter(NYql::NNodes::TExprBase node, NYql::TExprContext& ctx,
const TKqpOptimizeContext& kqpCtx, NYql::TTypeAnnotationContext& typesCtx);
diff --git a/ydb/core/kqp/opt/physical/kqp_opt_phy_sort.cpp b/ydb/core/kqp/opt/physical/kqp_opt_phy_sort.cpp
index f0e11f37c20..7d39948193f 100644
--- a/ydb/core/kqp/opt/physical/kqp_opt_phy_sort.cpp
+++ b/ydb/core/kqp/opt/physical/kqp_opt_phy_sort.cpp
@@ -41,39 +41,9 @@ TExprBase KqpRemoveRedundantSortByPk(TExprBase node, TExprContext& ctx, const TK
input = flatmap.Input();
}
- enum : ui32 {
- SortDirectionNone = 0,
- SortDirectionForward = 1,
- SortDirectionReverse = 2,
- SortDirectionUnknown = 4,
- };
-
- auto getDirection = [] (TExprBase expr) -> ui32 {
- if (!expr.Maybe<TCoBool>()) {
- return SortDirectionUnknown;
- }
-
- if (!FromString<bool>(expr.Cast<TCoBool>().Literal().Value())) {
- return SortDirectionReverse;
- }
-
- return SortDirectionForward;
- };
-
- ui32 direction = SortDirectionNone;
-
- if (auto maybeList = sortDirections.Maybe<TExprList>()) {
- for (const auto& expr : maybeList.Cast()) {
- direction |= getDirection(expr);
- if (direction != SortDirectionForward && direction != SortDirectionReverse) {
- return node;
- }
- }
- } else {
- direction |= getDirection(sortDirections);
- if (direction != SortDirectionForward && direction != SortDirectionReverse) {
- return node;
- }
+ auto direction = GetSortDirection(sortDirections);
+ if (direction != ESortDirection::Forward && direction != ESortDirection::Reverse) {
+ return node;
}
bool isReadTable = input.Maybe<TKqpReadTable>().IsValid();
@@ -82,48 +52,20 @@ TExprBase KqpRemoveRedundantSortByPk(TExprBase node, TExprContext& ctx, const TK
return node;
}
auto& tableDesc = kqpCtx.Tables->ExistingTable(kqpCtx.Cluster, GetReadTablePath(input, isReadTableRanges));
- auto settings = GetReadTableSettings(input, isReadTableRanges);
-
- auto checkKey = [keySelector, &tableDesc, &passthroughFields] (TExprBase key, ui32 index) {
- if (!key.Maybe<TCoMember>()) {
- return false;
- }
- auto member = key.Cast<TCoMember>();
- if (member.Struct().Raw() != keySelector.Args().Arg(0).Raw()) {
- return false;
- }
-
- auto column = TString(member.Name().Value());
- auto columnIndex = tableDesc.GetKeyColumnIndex(column);
- if (!columnIndex || *columnIndex != index) {
- return false;
- }
-
- if (passthroughFields && !passthroughFields->contains(column)) {
- return false;
- }
+ if(tableDesc.Metadata->Kind == EKikimrTableKind::Olap) {
+ // OLAP tables are read in parallel, so we need to keep the out sort.
+ return node;
+ }
- return true;
- };
+ auto settings = GetReadTableSettings(input, isReadTableRanges);
- auto lambdaBody = keySelector.Body();
- if (auto maybeTuple = lambdaBody.Maybe<TExprList>()) {
- auto tuple = maybeTuple.Cast();
- for (size_t i = 0; i < tuple.Size(); ++i) {
- if (!checkKey(tuple.Item(i), i)) {
- return node;
- }
- }
- } else {
- if (!checkKey(lambdaBody, 0)) {
- return node;
- }
+ if (!IsSortKeyPrimary(keySelector, tableDesc, passthroughFields)) {
+ return node;
}
- bool olapTable = tableDesc.Metadata->Kind == EKikimrTableKind::Olap;
- if (direction == SortDirectionReverse) {
- if (!UseSource(kqpCtx, tableDesc) && !olapTable && kqpCtx.IsScanQuery()) {
+ if (direction == ESortDirection::Reverse) {
+ if (!UseSource(kqpCtx, tableDesc) && kqpCtx.IsScanQuery()) {
return node;
}
@@ -135,8 +77,8 @@ TExprBase KqpRemoveRedundantSortByPk(TExprBase node, TExprContext& ctx, const TK
settings.SetSorted();
input = BuildReadNode(input.Pos(), ctx, input, settings);
- } else if (direction == SortDirectionForward) {
- if (olapTable || UseSource(kqpCtx, tableDesc)) {
+ } else if (direction == ESortDirection::Forward) {
+ if (UseSource(kqpCtx, tableDesc)) {
settings.SetSorted();
input = BuildReadNode(input.Pos(), ctx, input, settings);
}
diff --git a/ydb/core/kqp/ut/olap/kqp_olap_ut.cpp b/ydb/core/kqp/ut/olap/kqp_olap_ut.cpp
index 94a30a2c3d7..b84fd91dfa5 100644
--- a/ydb/core/kqp/ut/olap/kqp_olap_ut.cpp
+++ b/ydb/core/kqp/ut/olap/kqp_olap_ut.cpp
@@ -1134,12 +1134,14 @@ Y_UNIT_TEST_SUITE(KqpOlap) {
Cerr << result.QueryStats->query_plan() << Endl;
Cerr << result.QueryStats->query_ast() << Endl;
- node = FindPlanNodeByKv(plan, "Node Type", "Limit-TableFullScan");
+ node = FindPlanNodeByKv(plan, "Node Type", "TopSort-TableFullScan");
UNIT_ASSERT(node.IsDefined());
reverse = FindPlanNodeByKv(node, "Reverse", "false");
UNIT_ASSERT(!reverse.IsDefined());
pushedLimit = FindPlanNodeByKv(node, "ReadLimit", "4");
UNIT_ASSERT(pushedLimit.IsDefined());
+ limit = FindPlanNodeByKv(node, "Limit", "4");
+ UNIT_ASSERT(limit.IsDefined());
// Check that Reverse flag is set in query plan
it = tableClient.StreamExecuteScanQuery(selectQueryWithSort, scanSettings).GetValueSync();
@@ -1151,7 +1153,7 @@ Y_UNIT_TEST_SUITE(KqpOlap) {
Cerr << result.QueryStats->query_plan() << Endl;
Cerr << result.QueryStats->query_ast() << Endl;
- node = FindPlanNodeByKv(plan, "Node Type", "Limit-TableFullScan");
+ node = FindPlanNodeByKv(plan, "Node Type", "TopSort-TableFullScan");
UNIT_ASSERT(node.IsDefined());
reverse = FindPlanNodeByKv(node, "Reverse", "true");
UNIT_ASSERT(reverse.IsDefined());
diff --git a/ydb/tests/functional/clickbench/canondata/test.test_plans_column_/queries-original-plan-column-23 b/ydb/tests/functional/clickbench/canondata/test.test_plans_column_/queries-original-plan-column-23
index 2658d48f60e..b02e30f559a 100644
--- a/ydb/tests/functional/clickbench/canondata/test.test_plans_column_/queries-original-plan-column-23
+++ b/ydb/tests/functional/clickbench/canondata/test.test_plans_column_/queries-original-plan-column-23
@@ -30,11 +30,12 @@
"PlanNodeType": "Connection",
"Plans": [
{
- "Node Type": "Limit-TableFullScan",
+ "Node Type": "TopSort-TableFullScan",
"Operators": [
{
"Limit": "10",
- "Name": "Limit"
+ "Name": "TopSort",
+ "TopSortBy": "$4.EventTime"
},
{
"Name": "TableFullScan",
diff --git a/ydb/tests/functional/clickbench/canondata/test.test_plans_column_/queries-original-plan-column-24 b/ydb/tests/functional/clickbench/canondata/test.test_plans_column_/queries-original-plan-column-24
index 25e3bde2e7f..ae0d62718f4 100644
--- a/ydb/tests/functional/clickbench/canondata/test.test_plans_column_/queries-original-plan-column-24
+++ b/ydb/tests/functional/clickbench/canondata/test.test_plans_column_/queries-original-plan-column-24
@@ -30,11 +30,12 @@
"PlanNodeType": "Connection",
"Plans": [
{
- "Node Type": "Limit-TableFullScan",
+ "Node Type": "TopSort-TableFullScan",
"Operators": [
{
"Limit": "10",
- "Name": "Limit"
+ "Name": "TopSort",
+ "TopSortBy": "$4.EventTime"
},
{
"Name": "TableFullScan",
diff --git a/ydb/tests/functional/clickbench/canondata/test.test_run_determentistic_column_/queries-deterministic-results-24 b/ydb/tests/functional/clickbench/canondata/test.test_run_determentistic_column_/queries-deterministic-results-24
index bb222137018..0543ecb5022 100644
--- a/ydb/tests/functional/clickbench/canondata/test.test_run_determentistic_column_/queries-deterministic-results-24
+++ b/ydb/tests/functional/clickbench/canondata/test.test_run_determentistic_column_/queries-deterministic-results-24
@@ -29,7 +29,7 @@
},
{
"EventTime": 1373832036000000,
- "SearchPhrase": "\u0432\u0435\u0434\u043e\u043c\u043e\u0441\u043a\u0432\u044b \u0441 \u043b\u044f\u0439\u0441\u0430\u043d \u0431\u0430\u043b\u043b\u044b"
+ "SearchPhrase": "\u0430\u0440\u043c\u044f\u043d\u0441\u043a"
},
{
"EventTime": 1373832036000000,
@@ -37,6 +37,6 @@
},
{
"EventTime": 1373832036000000,
- "SearchPhrase": "\u0430\u0440\u043c\u044f\u043d\u0441\u043a"
+ "SearchPhrase": "\u0432\u0435\u0434\u043e\u043c\u043e\u0441\u043a\u0432\u044b \u0441 \u043b\u044f\u0439\u0441\u0430\u043d \u0431\u0430\u043b\u043b\u044b"
}
] \ No newline at end of file
diff --git a/ydb/tests/functional/clickbench/canondata/test.test_run_determentistic_row_/queries-deterministic-results-24 b/ydb/tests/functional/clickbench/canondata/test.test_run_determentistic_row_/queries-deterministic-results-24
index bb222137018..0543ecb5022 100644
--- a/ydb/tests/functional/clickbench/canondata/test.test_run_determentistic_row_/queries-deterministic-results-24
+++ b/ydb/tests/functional/clickbench/canondata/test.test_run_determentistic_row_/queries-deterministic-results-24
@@ -29,7 +29,7 @@
},
{
"EventTime": 1373832036000000,
- "SearchPhrase": "\u0432\u0435\u0434\u043e\u043c\u043e\u0441\u043a\u0432\u044b \u0441 \u043b\u044f\u0439\u0441\u0430\u043d \u0431\u0430\u043b\u043b\u044b"
+ "SearchPhrase": "\u0430\u0440\u043c\u044f\u043d\u0441\u043a"
},
{
"EventTime": 1373832036000000,
@@ -37,6 +37,6 @@
},
{
"EventTime": 1373832036000000,
- "SearchPhrase": "\u0430\u0440\u043c\u044f\u043d\u0441\u043a"
+ "SearchPhrase": "\u0432\u0435\u0434\u043e\u043c\u043e\u0441\u043a\u0432\u044b \u0441 \u043b\u044f\u0439\u0441\u0430\u043d \u0431\u0430\u043b\u043b\u044b"
}
] \ No newline at end of file
diff --git a/ydb/tests/functional/clickbench/data/queries-deterministic.sql b/ydb/tests/functional/clickbench/data/queries-deterministic.sql
index bf87ac6b459..635c2486ec9 100644
--- a/ydb/tests/functional/clickbench/data/queries-deterministic.sql
+++ b/ydb/tests/functional/clickbench/data/queries-deterministic.sql
@@ -22,7 +22,7 @@
/*21*/ SELECT SearchPhrase, MIN(URL), COUNT(*) AS c FROM $data WHERE URL LIKE '%google%' AND SearchPhrase <> '' GROUP BY SearchPhrase ORDER BY c DESC LIMIT 10;
/*22*/ SELECT SearchPhrase, MIN(URL), MIN(Title), COUNT(*) AS c, COUNT(DISTINCT UserID) FROM $data WHERE Title LIKE '%Google%' AND URL NOT LIKE '%.google.%' AND SearchPhrase <> '' GROUP BY SearchPhrase ORDER BY c DESC, SearchPhrase, column1, column2 LIMIT 10;
/*23*/ SELECT * FROM $data WHERE URL LIKE '%google%' ORDER BY EventTime LIMIT 10;
-/*24*/ SELECT SearchPhrase, EventTime FROM $data WHERE SearchPhrase <> '' ORDER BY EventTime LIMIT 10;
+/*24*/ SELECT SearchPhrase, EventTime FROM $data WHERE SearchPhrase <> '' ORDER BY EventTime, SearchPhrase LIMIT 10;
/*25*/ SELECT SearchPhrase FROM $data WHERE SearchPhrase <> '' ORDER BY SearchPhrase LIMIT 10;
/*26*/ SELECT SearchPhrase, EventTime FROM $data WHERE SearchPhrase <> '' ORDER BY EventTime, SearchPhrase LIMIT 10;
/*27*/ SELECT CounterID, AVG(length(URL)) AS l, COUNT(*) AS c FROM $data WHERE URL <> '' GROUP BY CounterID HAVING COUNT(*) > 100000 ORDER BY l DESC LIMIT 25;