aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVitalii Gridnev <gridnevvvit@gmail.com>2025-01-21 23:53:22 +0300
committerGitHub <noreply@github.com>2025-01-21 23:53:22 +0300
commitcaa23328d636860e580cd9523e82a57df709968a (patch)
treeb4b6154fb899877c229f976eaf3549e7590d4e50
parent61d9766acd7c9eedb2b5ea4391c62e4d2b1f78fa (diff)
downloadydb-caa23328d636860e580cd9523e82a57df709968a.tar.gz
don't update indexes when all input columns are specified for indexes but values are not changed (#12940)
-rw-r--r--ydb/core/kqp/opt/physical/effects/kqp_opt_phy_upsert_index.cpp12
-rw-r--r--ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp164
2 files changed, 164 insertions, 12 deletions
diff --git a/ydb/core/kqp/opt/physical/effects/kqp_opt_phy_upsert_index.cpp b/ydb/core/kqp/opt/physical/effects/kqp_opt_phy_upsert_index.cpp
index d5bd02b7fb..04a6176dff 100644
--- a/ydb/core/kqp/opt/physical/effects/kqp_opt_phy_upsert_index.cpp
+++ b/ydb/core/kqp/opt/physical/effects/kqp_opt_phy_upsert_index.cpp
@@ -153,18 +153,6 @@ TExprBase MakeUpsertIndexRows(TKqpPhyUpsertIndexMode mode, const TDqPhyPrecomput
const TVector<TStringBuf>& indexColumns, const TKikimrTableDescription& table, TPositionHandle pos,
TExprContext& ctx, bool opt)
{
- // Check if we can update index table from just input data
- bool allColumnFromInput = true; // - indicate all data from input
- for (const auto& column : indexColumns) {
- allColumnFromInput = allColumnFromInput && inputColumns.contains(column);
- }
-
- if (allColumnFromInput) {
- return mode == TKqpPhyUpsertIndexMode::UpdateOn
- ? MakeNonexistingRowsFilter(inputRows, lookupDict, table.Metadata->KeyColumnNames, pos, ctx)
- : TExprBase(inputRows);
- }
-
auto inputRowsArg = TCoArgument(ctx.NewArgument(pos, "input_rows"));
auto inputRowArg = TCoArgument(ctx.NewArgument(pos, "input_row"));
auto lookupDictArg = TCoArgument(ctx.NewArgument(pos, "lookup_dict"));
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 74c6a13d3a..0c5c0dd171 100644
--- a/ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp
+++ b/ydb/core/kqp/ut/service/kqp_qs_queries_ut.cpp
@@ -413,6 +413,170 @@ Y_UNIT_TEST_SUITE(KqpQueryService) {
UNIT_ASSERT_VALUES_EQUAL(count, 1);
}
+ Y_UNIT_TEST(ExecuteQueryUpsertDoesntChangeIndexedValuesIfNotChanged) {
+ auto kikimr = DefaultKikimrRunner();
+ auto db = kikimr.GetQueryClient();
+
+ auto settings = TExecuteQuerySettings()
+ .StatsMode(EStatsMode::Full);
+
+ {
+ auto result = db.ExecuteQuery(R"(
+ create table test (
+ id1 Uint64,
+ id2 Uint64,
+ value Utf8,
+ PRIMARY KEY(id1, id2),
+ INDEX Id2Idx GLOBAL ON (id2),
+ INDEX ValueIdx GLOBAL ON (value)
+ );
+
+ )", TTxControl::NoTx()).ExtractValueSync();
+ UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
+ }
+
+ {
+ auto result = db.ExecuteQuery(R"(
+ UPSERT INTO test (id1, id2, value) VALUES (2, 2, "c"u), (3, 3, null), (4, 4, null);
+ )", TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
+ auto stats = NYdb::TProtoAccessor::GetProto(*result.GetStats());
+ AssertTableStats(stats, "/Root/test", {.ExpectedUpdates = 3});
+ AssertTableStats(stats, "/Root/test/Id2Idx/indexImplTable", {.ExpectedUpdates = 3});
+ AssertTableStats(stats, "/Root/test/ValueIdx/indexImplTable", {.ExpectedUpdates = 3});
+ }
+
+ // value not changed, no updates to indexes
+ {
+ auto result = db.ExecuteQuery(R"(
+ UPSERT INTO test (id1, id2) VALUES (2, 2);
+ )", TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
+ auto stats = NYdb::TProtoAccessor::GetProto(*result.GetStats());
+ AssertTableStats(stats, "/Root/test", {.ExpectedUpdates = 1});
+ AssertTableStats(stats, "/Root/test/Id2Idx/indexImplTable", {.ExpectedUpdates = 0});
+ AssertTableStats(stats, "/Root/test/ValueIdx/indexImplTable", {.ExpectedUpdates = 0});
+ }
+
+ // value not changed, no updates to indexes
+ {
+ auto result = db.ExecuteQuery(R"(
+ UPSERT INTO test (id1, id2, value) VALUES (2, 2, "c"u);
+ )", TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
+ auto stats = NYdb::TProtoAccessor::GetProto(*result.GetStats());
+ AssertTableStats(stats, "/Root/test", {.ExpectedUpdates = 1});
+ AssertTableStats(stats, "/Root/test/Id2Idx/indexImplTable", {.ExpectedUpdates = 0});
+ AssertTableStats(stats, "/Root/test/ValueIdx/indexImplTable", {.ExpectedUpdates = 0});
+ }
+
+ // value IS changed, updates to index by VALUE
+ {
+ auto result = db.ExecuteQuery(R"(
+ UPSERT INTO test (id1, id2, value) VALUES (2, 2, "Q"u);
+ )", TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
+ auto stats = NYdb::TProtoAccessor::GetProto(*result.GetStats());
+ AssertTableStats(stats, "/Root/test", {.ExpectedUpdates = 1});
+ AssertTableStats(stats, "/Root/test/Id2Idx/indexImplTable", {.ExpectedUpdates = 0});
+ AssertTableStats(stats, "/Root/test/ValueIdx/indexImplTable", {.ExpectedUpdates = 1});
+ const TString query = "SELECT id1, id2, value FROM test VIEW ValueIdx WHERE value = \"Q\"u";
+ auto selectResult = db.ExecuteQuery(query, TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ CompareYson(R"([[[2u];[2u];["Q"]]])", FormatResultSetYson(selectResult.GetResultSet(0)));
+ }
+
+ // value IS NOT changed
+ {
+ auto result = db.ExecuteQuery(R"(
+ UPDATE test ON SELECT 2 as id1, 2 as id2, "Q"u as value;
+ )", TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
+ auto stats = NYdb::TProtoAccessor::GetProto(*result.GetStats());
+ AssertTableStats(stats, "/Root/test", {.ExpectedUpdates = 1});
+ AssertTableStats(stats, "/Root/test/Id2Idx/indexImplTable", {.ExpectedUpdates = 0});
+ AssertTableStats(stats, "/Root/test/ValueIdx/indexImplTable", {.ExpectedUpdates = 0});
+ const TString query = "SELECT id1, id2, value FROM test VIEW ValueIdx WHERE value = \"Q\"u";
+ auto selectResult = db.ExecuteQuery(query, TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ CompareYson(R"([[[2u];[2u];["Q"]]])", FormatResultSetYson(selectResult.GetResultSet(0)));
+ }
+
+
+ // value IS NOT changed
+ {
+ auto result = db.ExecuteQuery(R"(
+ UPDATE test ON SELECT 2 as id1, 2 as id2, "R"u as value;
+ )", TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
+ auto stats = NYdb::TProtoAccessor::GetProto(*result.GetStats());
+ AssertTableStats(stats, "/Root/test", {.ExpectedUpdates = 1});
+ AssertTableStats(stats, "/Root/test/Id2Idx/indexImplTable", {.ExpectedUpdates = 0});
+ AssertTableStats(stats, "/Root/test/ValueIdx/indexImplTable", {.ExpectedUpdates = 1});
+ const TString query = "SELECT id1, id2, value FROM test VIEW ValueIdx WHERE value = \"R\"u";
+ auto selectResult = db.ExecuteQuery(query, TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ CompareYson(R"([[[2u];[2u];["R"]]])", FormatResultSetYson(selectResult.GetResultSet(0)));
+ }
+
+ // value (null) IS NOT changed
+ {
+ auto result = db.ExecuteQuery(R"(
+ UPSERT INTO test (id1, id2, value) VALUES (3, 3, null);
+ )", TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
+ auto stats = NYdb::TProtoAccessor::GetProto(*result.GetStats());
+ AssertTableStats(stats, "/Root/test", {.ExpectedUpdates = 1});
+ AssertTableStats(stats, "/Root/test/Id2Idx/indexImplTable", {.ExpectedUpdates = 0});
+ AssertTableStats(stats, "/Root/test/ValueIdx/indexImplTable", {.ExpectedUpdates = 0});
+ const TString query = "SELECT id1, id2, value FROM test VIEW ValueIdx WHERE value is null";
+ auto selectResult = db.ExecuteQuery(query, TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ CompareYson(R"([[[3u];[3u];#];[[4u];[4u];#]])", FormatResultSetYson(selectResult.GetResultSet(0)));
+ }
+
+ // value (null) IS NOT changed
+ {
+ auto result = db.ExecuteQuery(R"(
+ UPDATE test ON SELECT 3 as id1, 3 as id2, null as value;
+ )", TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
+ auto stats = NYdb::TProtoAccessor::GetProto(*result.GetStats());
+ AssertTableStats(stats, "/Root/test", {.ExpectedUpdates = 1});
+ AssertTableStats(stats, "/Root/test/Id2Idx/indexImplTable", {.ExpectedUpdates = 0});
+ AssertTableStats(stats, "/Root/test/ValueIdx/indexImplTable", {.ExpectedUpdates = 0});
+ const TString query = "SELECT id1, id2, value FROM test VIEW ValueIdx WHERE value is null";
+ auto selectResult = db.ExecuteQuery(query, TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ CompareYson(R"([[[3u];[3u];#];[[4u];[4u];#]])", FormatResultSetYson(selectResult.GetResultSet(0)));
+ }
+
+ // value (null) IS changed
+ {
+ auto result = db.ExecuteQuery(R"(
+ UPSERT INTO test (id1, id2, value) VALUES (3, 3, "T"u);
+ )", TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
+ auto stats = NYdb::TProtoAccessor::GetProto(*result.GetStats());
+ AssertTableStats(stats, "/Root/test", {.ExpectedUpdates = 1});
+ AssertTableStats(stats, "/Root/test/Id2Idx/indexImplTable", {.ExpectedUpdates = 0});
+ AssertTableStats(stats, "/Root/test/ValueIdx/indexImplTable", {.ExpectedUpdates = 1});
+ const TString query = "SELECT id1, id2, value FROM test VIEW ValueIdx WHERE value = \"T\"u";
+ auto selectResult = db.ExecuteQuery(query, TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ CompareYson(R"([[[3u];[3u];["T"]]])", FormatResultSetYson(selectResult.GetResultSet(0)));
+ }
+
+ // value (null) IS changed
+ {
+ auto result = db.ExecuteQuery(R"(
+ UPDATE test ON SELECT 4 as id1, 4 as id2, "L"u as value;
+ )", TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
+ auto stats = NYdb::TProtoAccessor::GetProto(*result.GetStats());
+ AssertTableStats(stats, "/Root/test", {.ExpectedUpdates = 1});
+ AssertTableStats(stats, "/Root/test/Id2Idx/indexImplTable", {.ExpectedUpdates = 0});
+ AssertTableStats(stats, "/Root/test/ValueIdx/indexImplTable", {.ExpectedUpdates = 1});
+ const TString query = "SELECT id1, id2, value FROM test VIEW ValueIdx WHERE value = \"L\"u";
+ auto selectResult = db.ExecuteQuery(query, TTxControl::BeginTx().CommitTx(), settings).ExtractValueSync();
+ CompareYson(R"([[[4u];[4u];["L"]]])", FormatResultSetYson(selectResult.GetResultSet(0)));
+ }
+ }
+
Y_UNIT_TEST(ExecuteQueryPure) {
auto kikimr = DefaultKikimrRunner();
auto db = kikimr.GetQueryClient();