yujun777 opened a new pull request, #68646:
URL: https://github.com/apache/doris/pull/68646
### What problem does this PR solve?
Issue Number: N/A
Related PR: #68390
Problem Summary:
A column change on a base table (`DROP COLUMN` / `RENAME COLUMN`) puts every
materialized view that reads the table into `SCHEMA_CHANGE`, whether or not the
column is one the view's query names. That state is what a strict `REFRESH ...
INCREMENTAL` on an IVM MV reads -- the refresh is escalated to a whole-MV
`COMPLETE` for a column the MV never read -- and it is what stops the
transparent rewrite serving a plain MV until a refresh has run. Neither is work
the change owes.
The judgement such a change needs is the view's own query, per view: a
column that is dropped or renamed either is named by that query -- and then the
query no longer analyses, which is the state the view has to be left in -- or
it is not named, and the rows the view holds are the ones they should be.
`MTMVRelationManager` already re-analyses the query for such a change, but only
to pick a more specific reason for a record it writes either way. This PR makes
that answer the criterion, for both kinds of MV:
* Each operation says whether the query decides it
(`AlterOp#needQueryUsabilityCheck`). `DROP COLUMN` and `RENAME COLUMN` do. A
type change does not: the query keeps analysing while the meaning of the rows
computed under the old type changes, so re-analysis says nothing for a column
the query only filters or joins on. A rename of the table itself is not asked
about either, for the reason it never was: the view's query spells the old
name, so it is unanalysable by construction, and the query check could only
attribute the invalidation to the wrong reason. `REPLACE TABLE`, a dropped
table and a base view change were never asked about, and they still invalidate
every view that reads them.
* A change that has not reached the table is not asked about
(`AlterOp#hasReachedTheTable`). A schema change that is not a light one is
applied by a job, and the MV hook runs where that job may not have run yet: the
table still holds the column the change takes away, every query still analyses
against it, and an invalidation decided on that answer would be about the table
from before the change -- while the ABA that a dropped and re-added column
leaves behind is exactly what the invalidation exists for. What is asked is
whether the change has reached the table, which is the same fact the
re-analysis reads, so the two answers cannot disagree; a change that has not
been seen that way keeps invalidating, as it did before the queries were asked
at all.
Alongside it, two things the same code owed:
* `MTMV.processBaseViewChange` applied an invalidation in a second copy of
what `MTMV.alterStatus` does (state, version bump, snapshot drop). It goes
through `alterStatus` now, so an invalidation is one place to read whatever
carried it. The view path keeps applying without a record of its own, and that
is now written down where it happens: the change to the view is what is
journaled and a replay runs this hook along with it, so a record here would
apply the same invalidation twice on a follower -- including a version bump the
leader moved once.
* `MTMVState.SCHEMA_CHANGE` now says what it means, which is more than its
name: the state is "this MV needs a whole rebuild", and the comment names the
changes that set it -- for a plain MV as well as an IVM one, and for an IVM MV
alone -- and why the constant is not renamed (its name is what is written to
disk, and a constant Gson does not know reads back as null, dropping the state
of every MV loaded from such an image instead of failing).
An entire-table `TRUNCATE TABLE` is deliberately left as it is. The design
asked for it to be recorded as a whole-MV change; the per-partition requirement
already expresses that scope (every MV partition that reads the table is
named), and the whole-MV record would send every partition of the MV to a
rebuild and reset the streams for a change the per-partition requirement
carries -- where a stream does need that reconcile, the refresh falls back to a
`COMPLETE` on its own. Both truncate scopes are pinned by tests now.
Behaviour changed: Yes
* A base table `DROP COLUMN` / `RENAME COLUMN` no longer invalidates a
materialized view whose query does not name the column. The view keeps its rows
and stays a rewrite candidate, and a strict `REFRESH ... INCREMENTAL` on an IVM
MV is no longer escalated to a whole-MV `COMPLETE` because of it. A column the
query does name invalidates the view as before, and so does every other base
table change.
### Release note
Dropping or renaming a base table column no longer invalidates a
materialized view whose query does not use that column: the view keeps its
rows, keeps being used by the transparent rewrite, and a strict `REFRESH ...
INCREMENTAL` on an incremental materialized view no longer runs as a whole-view
`COMPLETE` refresh because of it. A column the view's query does use
invalidates the view exactly as before.
### Check List (For Author)
- Test: Unit Test / Regression test
- FE unit tests: `IvmBaselineRebuildTest` (42 -> 47),
`MTMVRelationManagerTest` (6 -> 7), `MTMVSchemaChangeTest`, `MTMVTest`,
`MTMVTaskTest`, `CreateMTMVCommandTest` -- 275 tests, all pass. Every new case
was checked to fail when the change it covers is reverted: the unreferenced
column leaves the MV in `SCHEMA_CHANGE` without the criterion, the flag is not
consulted without the hook change, the three effects of a view invalidation
stop moving together without the convergence, and an entire-table truncate
recorded as a whole-MV change fails the two truncate cases.
- Regression: `test_drop_unreferenced_column_mtmv` (new: an MV whose
partitions follow the base table's, and one on a table whose drops a job
rewrites), `test_base_drop_col_multi_level_mtmv` and
`test_base_rename_col_multi_level_mtmv` (one golden row each: the MV whose
query does not name the column is no longer invalidated, and the plan chooses
it where it previously was not a candidate),
`test_base_alter_col_type_multi_level_mtmv`, `test_base_recreate_col_mtmv`,
`test_create_mtmv_with_view`, `test_create_mtmv_with_view_alter`,
`test_create_view_mtmv`, `test_create_mtmv_with_view_pct`,
`test_ivm_drop_referenced_column_baseline_rebuild` (the unreferenced column no
longer escalates the refresh, the referenced one still does and its ABA case is
still rebuilt), `test_ivm_drop_column_fallback_reason`,
`test_ivm_row_binlog_schema_validation`, `test_ivm_baseline_marker_scope`,
`test_ivm_partition_epoch_rebuild`, `test_ivm_partition_baseline_rebuild`,
`test_ivm_unconsumed_dimension_i
s_not_current` -- all pass; the two goldens that changed were regenerated and
reviewed line by line.
- Behavior changed: Yes (see above)
- Does this need documentation: Yes, in a follow-up (no doc PR yet): the
user-facing page's list of situations that leave a materialized view behind is
tracked in the design document-change list, which records the exact locations
and wording for this and for the notes the previous PR in the series owes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]