Joaquín Antonio De Vicente López created IMPALA-15536:
---------------------------------------------------------

             Summary: UPDATE row count no longer distinguishes "no match" from 
"no-op" after IMPALA-12588
                 Key: IMPALA-15536
                 URL: https://issues.apache.org/jira/browse/IMPALA-15536
             Project: IMPALA
          Issue Type: Improvement
          Components: Backend, Frontend
    Affects Versions: Impala 5.0.0
            Reporter: Joaquín Antonio De Vicente López


IMPALA-12588 ("Don't UPDATE rows that already have the desired value") makes 
Impala add implicit predicates to UPDATE statements on Kudu and Iceberg tables, 
so rows that already hold the target values are skipped. This avoids useless 
writes, but it also changes what the reported affected-row count means: 
Modified 0 row(s) (and NumModifiedRows: 0 in the profile) is now returned both 
when no row matches the WHERE clause and when the matching rows already hold 
the target values.

Clients that use the affected-row count to detect whether a record exists 
(reconciliation, idempotency checks, upsert-like logic built on UPDATE) will 
break silently when they upgrade to 5.0.0.

The meaning of the counter is also inconsistent within the same release. The 
optimization is skipped when the SET list has more than 
SKIP_UNNEEDED_UPDATES_COL_LIMIT assignments (default 10) or when any assignment 
contains a UDF. So depending on how the UPDATE is written, the same client gets 
either "rows matched" or "rows actually changed".
h1. Steps to reproduce

CREATE TABLE test_update (id INT PRIMARY KEY, val STRING)
PARTITION BY HASH(id) PARTITIONS 2 STORED AS KUDU;

INSERT INTO test_update VALUES (1, 'INITIAL');

UPDATE test_update SET val = 'VALUE_1' WHERE id = 1;   – case 1
UPDATE test_update SET val = 'VALUE_2' WHERE id = 1;   – case 2
UPDATE test_update SET val = 'VALUE_2' WHERE id = 1;   – case 3 (no-op)
UPDATE test_update SET val = 'VALUE_2' WHERE id = 999; – case 4 (no match)
h1. Results
|Case|Row matched|Value changed|Impala 4.5.3 (verified)|Impala 5.0.0 / master 
(with IMPALA-12588)|
|—|—|—|—|—|
|INITIAL → VALUE_1|Yes|Yes|Modified 1 row(s)|Modified 1 row(s)|
|VALUE_1 → VALUE_2|Yes|Yes|Modified 1 row(s)|Modified 1 row(s)|
|VALUE_2 → VALUE_2|Yes|No|Modified 1 row(s)|*Modified 0 row(s)*|
|id = 999|No|No|Modified 0 row(s)|Modified 0 row(s)|

The 4.5.3 column was obtained by running the script above against Impala 
4.5.3-RELEASE (build b3e78704d824) with Kudu 1.18.1.

The master column follows from the tests added by IMPALA-12588 in 
testdata/workloads/functional-query/queries/QueryTest/kudu_update.test:
 - update tdata set vali=43 where id = 40 on a row that already has vali = 43 
now expects NumModifiedRows: 0.
 - update tdata set valb=false where name LIKE '%he' matches two rows, but the 
expected value changed from NumModifiedRows: 2 to NumModifiedRows: 1 because 
one row already had valb = false.

EXPLAIN on master shows the extra predicate on the scan, for example:

UPDATE KUDU [default.test_update]
 
00:SCAN KUDU [default.test_update]
   predicates: val IS DISTINCT FROM 'VALUE_2'
   kudu predicates: id = 1

In 4.5.3 the same EXPLAIN shows only kudu predicates: id = 1.

The same rewrite applies to Iceberg UPDATE statements, so Iceberg tables are 
affected in the same way.
h1. Existing workaround

IMPALA-12588 already added the query option SKIP_UNNEEDED_UPDATES_COL_LIMIT 
(advanced, default `10`). Setting it to a non-positive value turns the 
optimization off and restores the previous semantics:

SET SKIP_UNNEEDED_UPDATES_COL_LIMIT=0;

However, this option is not documented: there is no mention of it under `docs/` 
on master. Users upgrading have no way to find out that the row-count semantics 
changed, or that this option exists.
h1. Proposal

1. *Document the behavior change and the query option.* Call out the new 
meaning of the affected-row count as a behavior change in the Impala 5.0.0 
release notes, and add `SKIP_UNNEEDED_UPDATES_COL_LIMIT` to the query options 
documentation, including that `0` disables the optimization.


2. *Report matched rows separately* from modified rows, in both the client 
output and the query profile, for example:

Modified 0 row(s), Found 1 row(s)

This keeps the performance benefit of IMPALA-12588 and gives clients back the 
information they lost. Note that today the extra predicate is evaluated in the 
scan (or in the join), so skipped rows never reach the table sink. Counting 
matched rows would require counting them before that predicate is applied, for 
example with a separate counter at the point where the predicate is evaluated.


3. *Optional:* consider making the optimization opt-in (default 
`SKIP_UNNEEDED_UPDATES_COL_LIMIT=0`), or at least making the reported count 
consistent regardless of the number of `SET` assignments or the presence of 
UDFs.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to