fix(view): refresh a skipped view's metadata only when it is stale - #847
Open
axellpadilla wants to merge 1 commit into
Open
axellpadilla wants to merge 1 commit into
axellpadilla wants to merge 1 commit into
Conversation
The skip path ran sp_refreshview on every unchanged view. That advances sys.objects.modify_date exactly as an ALTER does, so every unchanged view in a project churned that column on every run, and it could no longer tell a skipped run from a rebuild. The skip decision now reads the view's cached column shape alongside the stored definition it already fetched, compares it against what the body resolves to via sys.dm_exec_describe_first_result_set, and refreshes only where the two disagree. Same round trip as before, one compile of the body, and a view whose sources have not moved is left untouched. The check is a new macro rather than a second column on get_view_definition_sql, whose one-column contract a project override may depend on. Both sysname comparisons are pinned with COLLATE DATABASE_DEFAULT - without it every view model fails outright wherever the catalog and database collations differ. The sys.columns read carries information_schema_hints() like every other catalog read: it runs for every view on every run, so it must not wait indefinitely on another writer's catalog locks, and a torn read costs only one needless refresh or one run's delay. Verified against SQL Server 2022: an added column and a retyped column each reach a skipped view, and the quiet runs either side leave modify_date unmoved. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
axellpadilla
force-pushed
the
fix/838-conditional-view-metadata-refresh
branch
from
September 19, 2026 23:46
570061e to
2750ee9
Compare
This was referenced Sep 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Improves the #838 fix. That fix ran
sp_refreshviewon every skipped view, which advancessys.objects.modify_dateexactly as anALTERdoes — so every unchanged view in a project churned that column on every run, and it could no longer tell a skipped run from a rebuild. Anything watching the catalog for drift saw noise, and the test that used to assert "no rebuild" had to give up its signal.What changed
The skip decision already fetched the stored definition. It now gets the view's cached column shape in the same query, compares it against what the body resolves to (
sys.dm_exec_describe_first_result_set, which compiles the body without executing it), and runssp_refreshviewonly where the two disagree.modify_dateworks as a signal again.The check is a new macro,
get_view_skip_check_sql, rather than a second column onget_view_definition_sql— a project overriding that macro would otherwise silently lose a column the materialization then indexes, on the path that runs for every unchanged view.The text comparison is unchanged and still the gate. A shape check cannot replace it:
where amount > 100→> 200resolves to an identical column list, so a probe-only skip test would skip a real edit — the failure mode #807 fixed.Notes
sysnamecomparisons are pinned withCOLLATE DATABASE_DEFAULT. Without it every view model fails with Cannot resolve the collation conflict wherever the catalog and database collations differ — caught by the functional suite, not by review.is_nullableis deliberately not compared: describe's inference over expressions can disagree with whatCREATE VIEWrecorded, which would refresh that view on every run forever.sys.columnsis left unhinted, per the existing policy for catalog reads that act as correctness guards.Testing
Three test classes collapse into one —
TestSkippedViewTracksItsSourceShape, one project, one method walking a single view's life: build → quiet run → added column → retyped column → quiet run. It pins both directions, including that a repaired view goes quiet again.TestViewMaterializationNoOpgets itsmodify_dateassertion back.Verified against SQL Server 2022: 646 passed, 5 skipped.
Targets the 1.12.0rc4 release being prepared in #841. The 1.11 backport branch (
backport/1.11-838-view-refreshview) carries the samesp_refreshviewbehaviour and will need this separately.🤖 Generated with Claude Code