Skip to content

Commit

Permalink
[BACKPORT 2024.2][#18822] YSQL: Gate update optimizations behind prev…
Browse files Browse the repository at this point in the history
…iew flag

Summary:
D34040 introduced a framework to skip redundant secondary index updates and foreign key checks.
This revision adds a PG preview flag `ysql_yb_update_optimization_infra` that keeps the feature turned OFF by default.
Additionally, this revision restricts lookup to this flag to the following locations:.
 - Once, during query rewriting to determine to set the wholerow junk attribute
 - Once, at planning time to determine if optimization metadata needs to be computed
 - Once, at the beginning of query execution (`ExecInitModifyTable`) to determine if we should go ahead with the optimization. This has three possibilities:
    - The feature was enabled at planning time and disabled now (during query execution). In this case optimization is not performed.
    - The feature was disabled at planning time and enabled now. In this case, there is no metadata to perform the optimization and so the optimization is skipped.
    - The features was enabled at planning time and enabled now. In this case, metadata is available and the optimization is performed.

To turn on the update optimization feature, do the following:
 - Append `ysql_yb_update_optimization_infra` to the list of flags in `allowed_preview_flags_csv`
 - Set the tserver gflag `ysql_yb_update_optimization_infra` to true.
Jira: DB-7701

Original commit: 8c8adc0 / D37746

Test Plan:
Run the following tests:
```
./yb_build.sh --java-test 'org.yb.pgsql.TestPgRegressUpdateOptimized#schedule'
```

Reviewers: amartsinchyk

Reviewed By: amartsinchyk

Subscribers: yql, smishra, ybase

Tags: #jenkins-ready

Differential Revision: https://phorge.dev.yugabyte.com/D38289
  • Loading branch information
karthik-ramanathan-3006 committed Sep 27, 2024
1 parent f216887 commit d3ad9f1
Show file tree
Hide file tree
Showing 17 changed files with 69 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ public int getTestMethodTimeoutSec() {
@Override
protected Map<String, String> getTServerFlags() {
Map<String, String> flagMap = super.getTServerFlags();
flagMap.put("ysql_skip_row_lock_for_update", "false");
flagMap.put("allowed_preview_flags_csv", "ysql_yb_update_optimization_infra");
flagMap.put("ysql_yb_update_optimization_infra", "true");
return flagMap;
}

Expand Down
22 changes: 18 additions & 4 deletions src/postgres/src/backend/executor/nodeModifyTable.c
Original file line number Diff line number Diff line change
Expand Up @@ -1506,7 +1506,7 @@ ExecUpdate(ModifyTableState *mtstate,
if (!estate->yb_es_is_single_row_modify_txn)
{
YbComputeModifiedColumnsAndSkippableEntities(
plan, estate, oldtuple, tuple, &cols_marked_for_update,
mtstate, estate, oldtuple, tuple, &cols_marked_for_update,
beforeRowUpdateTriggerFired);
}

Expand Down Expand Up @@ -2486,9 +2486,10 @@ tupconv_map_for_subplan(ModifyTableState *mtstate, int whichplan)
* needed for inserting the tuple is supplied in the query.
*/
static bool
YBCHasWholeRowJunkAttr(ResultRelInfo *resultRelInfo, CmdType operation)
YBCHasWholeRowJunkAttr(ModifyTableState *mtstate, ResultRelInfo *resultRelInfo)
{
if (operation == CMD_UPDATE && YbIsUpdateOptimizationEnabled())
CmdType operation = mtstate->operation;
if (operation == CMD_UPDATE && mtstate->yb_is_update_optimization_enabled)
return true;

if (operation == CMD_UPDATE || operation == CMD_DELETE)
Expand Down Expand Up @@ -2677,7 +2678,7 @@ ExecModifyTable(PlanState *pstate)
* trigger execution.
*/
if (IsYBRelation(resultRelInfo->ri_RelationDesc) &&
YBCHasWholeRowJunkAttr(resultRelInfo, operation))
YBCHasWholeRowJunkAttr(node, resultRelInfo))
{
resno = ExecFindJunkAttribute(junkfilter, "wholerow");
datum = ExecGetJunkAttribute(slot, resno, &isNull);
Expand Down Expand Up @@ -2876,6 +2877,19 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
mtstate->resultRelInfo = estate->es_result_relations + node->resultRelIndex;
mtstate->yb_fetch_target_tuple = !YbCanSkipFetchingTargetTupleForModifyTable(node);

/*
* Check if the planner has passed down any optimization info for UPDATEs.
* There are two scenarios where this may be NULL:
* - There is nothing to optimize.
* - Optimization(s) have been disabled.
* Additionally, lookup the relevant GUCs. The GUCs may have been disabled
* after the query plan was generated (prepared statements for example).
* It is be safe to ignore the planned optimization in such cases.
*/
mtstate->yb_is_update_optimization_enabled =
(node->yb_update_affected_entities != NULL &&
operation == CMD_UPDATE && YbIsUpdateOptimizationEnabled());

/* If modifying a partitioned table, initialize the root table info */
if (node->rootResultRelIndex >= 0)
mtstate->rootResultRelInfo = estate->es_root_result_relations +
Expand Down
16 changes: 11 additions & 5 deletions src/postgres/src/backend/executor/ybOptimizeModifyTable.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ static void
YBComputeExtraUpdatedCols(Relation rel, HeapTuple oldtuple, HeapTuple newtuple,
Bitmapset *updated_cols, Bitmapset **modified_cols,
Bitmapset **unmodified_cols,
bool is_update_optimization_enabled,
bool is_onconflict_update)
{
Bitmapset *trig_cond_cols = NULL;
Expand All @@ -253,7 +254,7 @@ YBComputeExtraUpdatedCols(Relation rel, HeapTuple oldtuple, HeapTuple newtuple,
* If the optimization is not enabled, we only need to compare the
* columns that are not in the targetlist of the query.
*/
if (YbIsUpdateOptimizationEnabled())
if (is_update_optimization_enabled)
{
/*
* If the optimization is enabled, we have already compared all the
Expand Down Expand Up @@ -472,9 +473,12 @@ YbComputeModifiedEntities(ResultRelInfo *resultRelInfo, HeapTuple oldtuple,
* ----------------------------------------------------------------
*/
void
YbComputeModifiedColumnsAndSkippableEntities(
ModifyTable *plan, EState *estate, HeapTuple oldtuple, HeapTuple newtuple,
Bitmapset **updated_cols, bool beforeRowUpdateTriggerFired)
YbComputeModifiedColumnsAndSkippableEntities(ModifyTableState *mtstate,
EState *estate,
HeapTuple oldtuple,
HeapTuple newtuple,
Bitmapset **updated_cols,
bool beforeRowUpdateTriggerFired)
{
/*
* InvalidAttrNumber indicates that the whole row is to be changed. This
Expand Down Expand Up @@ -516,7 +520,8 @@ YbComputeModifiedColumnsAndSkippableEntities(
Bitmapset *unmodified_cols = NULL;
Bitmapset *modified_cols = NULL;

if (YbIsUpdateOptimizationEnabled())
ModifyTable *plan = (ModifyTable *) mtstate->ps.plan;
if (mtstate->yb_is_update_optimization_enabled)
{
YbComputeModifiedEntities(resultRelInfo, oldtuple, newtuple,
&modified_cols, &unmodified_cols,
Expand All @@ -528,6 +533,7 @@ YbComputeModifiedColumnsAndSkippableEntities(
{
YBComputeExtraUpdatedCols(rel, oldtuple, newtuple, *updated_cols,
&modified_cols, &unmodified_cols,
mtstate->yb_is_update_optimization_enabled,
(plan->operation == CMD_INSERT &&
plan->onConflictAction == ONCONFLICT_UPDATE));
}
Expand Down
3 changes: 0 additions & 3 deletions src/postgres/src/backend/optimizer/util/ybcplan.c
Original file line number Diff line number Diff line change
Expand Up @@ -712,9 +712,6 @@ YbComputeAffectedEntitiesForRelation(ModifyTable *modifyTable,
const Relation rel,
Bitmapset *update_attrs)
{
if (!YbIsUpdateOptimizationEnabled())
return NULL;

/* Fetch a list of candidate entities that may be impacted by the update. */
List *fkeylist = copyObject(RelationGetFKeyList(rel));
List *fkeyreflist = YbRelationGetFKeyReferencedByList(rel);
Expand Down
15 changes: 14 additions & 1 deletion src/postgres/src/backend/utils/misc/guc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2639,6 +2639,19 @@ static struct config_bool ConfigureNamesBool[] =
yb_enable_ash_check_hook, NULL, NULL
},

{
{"yb_update_optimization_infra", PGC_SIGHUP, QUERY_TUNING_OTHER,
gettext_noop("Enables optimizations of YSQL UPDATE queries. This includes "
"(but not limited to) skipping redundant secondary index updates "
"and redundant constraint checks."),
NULL,
GUC_NOT_IN_SAMPLE
},
&yb_update_optimization_options.is_enabled,
false,
NULL, NULL, NULL
},

/* End-of-list marker */
{
{NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL, NULL
Expand Down Expand Up @@ -4124,7 +4137,7 @@ static struct config_int ConfigureNamesInt[] =
NULL
},
&yb_update_optimization_options.num_cols_to_compare,
0, 0, INT_MAX,
50, 0, INT_MAX,
NULL, NULL, NULL
},

Expand Down
5 changes: 3 additions & 2 deletions src/postgres/src/backend/utils/misc/pg_yb_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -1389,6 +1389,7 @@ int yb_toast_catcache_threshold = -1;
int yb_parallel_range_size = 1024 * 1024;

YBUpdateOptimizationOptions yb_update_optimization_options = {
.is_enabled = false,
.num_cols_to_compare = 50,
.max_cols_size_to_compare = 10 * 1024
};
Expand Down Expand Up @@ -4918,8 +4919,8 @@ YbGetRedactedQueryString(const char* query, int query_len,
bool
YbIsUpdateOptimizationEnabled()
{
/* TODO(kramanathan): Placeholder until a flag strategy is agreed upon */
return yb_update_optimization_options.num_cols_to_compare > 0 &&
return yb_update_optimization_options.is_enabled &&
yb_update_optimization_options.num_cols_to_compare > 0 &&
yb_update_optimization_options.max_cols_size_to_compare > 0;
}

Expand Down
2 changes: 1 addition & 1 deletion src/postgres/src/include/executor/ybOptimizeModifyTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
#include "nodes/plannodes.h"

extern void YbComputeModifiedColumnsAndSkippableEntities(
ModifyTable *plan, EState *estate, HeapTuple oldtuple,
ModifyTableState *mtstate, EState *estate, HeapTuple oldtuple,
HeapTuple newtuple, Bitmapset **updatedCols,
bool beforeRowUpdateTriggerFired);

Expand Down
5 changes: 5 additions & 0 deletions src/postgres/src/include/nodes/execnodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1157,6 +1157,11 @@ typedef struct ModifyTableState
/* YB specific attributes. */
bool yb_fetch_target_tuple; /* Perform initial scan to populate
* the ybctid. */
/*
* If enabled, execution seeks to optimize secondary index updates,
* constraint checks etc. This field is set to false for single row txns.
*/
bool yb_is_update_optimization_enabled;
} ModifyTableState;

/* ----------------
Expand Down
3 changes: 1 addition & 2 deletions src/postgres/src/include/pg_yb_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -542,8 +542,6 @@ extern bool yb_prefer_bnl;
*/
extern bool yb_explain_hide_non_deterministic_fields;

extern int yb_update_num_cols_to_compare;
extern int yb_update_max_cols_size_to_compare;
/*
* Enables scalar array operation pushdown.
* If true, planner sends supported expressions to DocDB for evaluation
Expand Down Expand Up @@ -660,6 +658,7 @@ extern bool yb_use_hash_splitting_by_default;

typedef struct YBUpdateOptimizationOptions
{
bool is_enabled;
int num_cols_to_compare;
int max_cols_size_to_compare;
} YBUpdateOptimizationOptions;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ SET yb_fetch_row_limit TO 1024;
SET yb_explain_hide_non_deterministic_fields TO true;
SET yb_update_num_cols_to_compare TO 50;
SET yb_update_max_cols_size_to_compare TO 10240;
-- This test requires the t-server gflag 'ysql_skip_row_lock_for_update' to be set to false.
-- This test requires the t-server preview/auto flag 'ysql_yb_update_optimizations_infra' to be enabled.
-- CREATE functions that can be triggered upon update to modify various columns
CREATE OR REPLACE FUNCTION no_update() RETURNS TRIGGER
LANGUAGE PLPGSQL AS $$
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1593,12 +1593,11 @@ EXPLAIN (ANALYZE, DIST, COSTS OFF) UPDATE t_simple SET v3 = v4, v4 = v3 WHERE k1
Storage Table Read Requests: 1
Storage Table Rows Scanned: 1
Storage Table Write Requests: 1
Storage Index Write Requests: 2
Storage Read Requests: 1
Storage Rows Scanned: 1
Storage Write Requests: 3
Storage Write Requests: 1
Storage Flush Requests: 1
(11 rows)
(10 rows)

EXPLAIN (ANALYZE, DIST, COSTS OFF) UPDATE t_simple SET v4 = v2 + 1 WHERE k1 = 6;
QUERY PLAN
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ SET yb_fetch_row_limit TO 1024;
SET yb_explain_hide_non_deterministic_fields TO true;
SET yb_update_num_cols_to_compare TO 50;
SET yb_update_max_cols_size_to_compare TO 10240;
-- This test requires the t-server gflag 'ysql_skip_row_lock_for_update' to be set to false.
-- This test requires the t-server preview/auto flag 'ysql_yb_update_optimizations_infra' to be enabled.
-- CREATE a table with a primary key and no secondary indexes
DROP TABLE IF EXISTS pkey_only_table;
NOTICE: table "pkey_only_table" does not exist, skipping
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ SET yb_fetch_row_limit TO 1024;
SET yb_explain_hide_non_deterministic_fields TO true;
SET yb_update_num_cols_to_compare TO 50;
SET yb_update_max_cols_size_to_compare TO 10240;
-- This test requires the t-server gflag 'ysql_skip_row_lock_for_update' to be set to false.
-- This test requires the t-server preview/auto flag 'ysql_yb_update_optimizations_infra' to be enabled.
CREATE OR REPLACE FUNCTION musical_chair() RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
-- Increment a specifc column based on the modulo of the row supplied
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ SET yb_explain_hide_non_deterministic_fields TO true;
SET yb_update_num_cols_to_compare TO 50;
SET yb_update_max_cols_size_to_compare TO 10240;

-- This test requires the t-server gflag 'ysql_skip_row_lock_for_update' to be set to false.
-- This test requires the t-server preview/auto flag 'ysql_yb_update_optimizations_infra' to be enabled.

-- CREATE functions that can be triggered upon update to modify various columns
CREATE OR REPLACE FUNCTION no_update() RETURNS TRIGGER
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ SET yb_explain_hide_non_deterministic_fields TO true;
SET yb_update_num_cols_to_compare TO 50;
SET yb_update_max_cols_size_to_compare TO 10240;

-- This test requires the t-server gflag 'ysql_skip_row_lock_for_update' to be set to false.
-- This test requires the t-server preview/auto flag 'ysql_yb_update_optimizations_infra' to be enabled.

-- CREATE a table with a primary key and no secondary indexes
DROP TABLE IF EXISTS pkey_only_table;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ SET yb_explain_hide_non_deterministic_fields TO true;
SET yb_update_num_cols_to_compare TO 50;
SET yb_update_max_cols_size_to_compare TO 10240;

-- This test requires the t-server gflag 'ysql_skip_row_lock_for_update' to be set to false.
-- This test requires the t-server preview/auto flag 'ysql_yb_update_optimizations_infra' to be enabled.

CREATE OR REPLACE FUNCTION musical_chair() RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
Expand Down
6 changes: 6 additions & 0 deletions src/yb/common/common_flags.cc
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,12 @@ DEFINE_RUNTIME_AUTO_bool(cdcsdk_enable_dynamic_table_addition_with_table_cleanup
"stream.");
TAG_FLAG(cdcsdk_enable_dynamic_table_addition_with_table_cleanup, advanced);

DEFINE_RUNTIME_PG_PREVIEW_FLAG(bool, yb_update_optimization_infra, false,
"Enables optimizations of YSQL UPDATE queries. This includes "
"(but not limited to) skipping redundant secondary index updates "
"and redundant constraint checks.");
TAG_FLAG(ysql_yb_update_optimization_infra, advanced);

namespace yb {

void InitCommonFlags() {
Expand Down

0 comments on commit d3ad9f1

Please sign in to comment.