Skip to content

Commit 32ed149

Browse files
authored
perf(optimizer): skip redundant hash invalidation in simplify's pointer-reset loop (#7725)
_simplify's post-order pass re-anchors every child's parent/arg_key/index pointers via set(), which also clears cached structural hashes up the ancestor chain. The loop never changes values (it rewrites args[k] with itself), and actual mutations already invalidate at mutation time through set/replace/pop, so the only effect of the extra invalidation was forcing while_changing to rehash entire condition subtrees after every (mostly no-op) pass to detect the fix point. Fix pointers directly with _set_parent, preserving set(k, None)'s arg-removal semantics. Simplify step ~5-12% faster across condition and TPC fixtures; output is byte-identical.
1 parent 9e4b3d1 commit 32ed149

1 file changed

Lines changed: 9 additions & 2 deletions

File tree

sqlglot/optimizer/simplify.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -699,9 +699,16 @@ def _simplify(
699699
root = original is expression
700700

701701
# Resets parent, arg_key, index pointers– this is needed because some of the
702-
# previous transformations mutate the AST, leading to an inconsistent state
702+
# previous transformations mutate the AST, leading to an inconsistent state.
703+
# We only fix pointers instead of calling `set` because the values are unchanged:
704+
# actual mutations go through `set`/`replace`, which already invalidate cached
705+
# hashes, so clearing them again here would force `while_changing` to rehash
706+
# entire subtrees after every (mostly no-op) pass.
703707
for k, v in tuple(original.args.items()):
704-
original.set(k, v)
708+
if v is None:
709+
original.args.pop(k)
710+
else:
711+
original._set_parent(k, v)
705712

706713
# Post-order transformations
707714
node = self.simplify_not(original)

0 commit comments

Comments
 (0)