Skip to content

Commit eb35b13

Browse files
authored
Perf: improve __hash__ performance (#7706)
1 parent dcd70a2 commit eb35b13

1 file changed

Lines changed: 18 additions & 9 deletions

File tree

sqlglot/expressions/core.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -837,26 +837,35 @@ def __ne__(self, other: object) -> bool:
837837
def __hash__(self) -> int:
838838
if self._hash is None:
839839
nodes: list[Expr] = []
840-
queue: deque[Expr] = deque()
841-
queue.append(self)
840+
stack: list[Expr] = [self]
842841

843-
while queue:
844-
node = queue.popleft()
842+
# Collect nodes, finding child expressions inline instead of via the
843+
# iter_expressions generator (whose per-node generator object dominates the
844+
# hash's cost). reversed(nodes) is a valid post-order regardless of DFS/BFS.
845+
while stack:
846+
node = stack.pop()
845847
nodes.append(node)
846848

847-
for child in node.iter_expressions():
848-
if child._hash is None:
849-
queue.append(child)
849+
for v in node.args.values():
850+
if isinstance(v, Expr):
851+
if v._hash is None:
852+
stack.append(v)
853+
elif type(v) is list:
854+
for x in v:
855+
if isinstance(x, Expr) and x._hash is None:
856+
stack.append(x)
850857

851858
for node in reversed(nodes):
852859
hash_ = hash(node.key)
853860

854861
if node._hash_raw_args:
855-
for k, v in sorted(node.args.items()):
862+
for k in sorted(node.args):
863+
v = node.args[k]
856864
if v:
857865
hash_ = hash((hash_, k, v))
858866
else:
859-
for k, v in sorted(node.args.items()):
867+
for k in sorted(node.args):
868+
v = node.args[k]
860869
vt = type(v)
861870

862871
if vt is list:

0 commit comments

Comments
 (0)