summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorKeryn Knight <keryn@kerynknight.com>2021-07-20 07:10:52 +0200
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2021-07-20 07:19:28 +0200
commitff661dbd506efbdf51cc8da89cb98731c8a62f49 (patch)
treed825d121c7b2349f4c2674d7ef584db7ae05a691 /django
parentfb35e0a2feb36e60b93a12dd43eb9eed2015adda (diff)
Refs #32940 -- Removed unnecessary branch in Node.add().
The "data in self.children" branch was causing data.__eq__ to be called for each entries in "self.children" which resulted in a huge slowdown during queryset construction. It's purpose was to prevent queries of the form Model.objects.filter(foo='bar').filter(foo='bar') from resulting in WHERE foo='bar' AND foo='bar' but it's not covered by the suite and has arguable performance benefits since it's not very common and SQL engines are usually very good at folding/optimizing these. See also #32632 for prior discussion around comparing data to the Node's children. Co-authored-by: Nick Pope <nick@nickpope.me.uk>
Diffstat (limited to 'django')
-rw-r--r--django/utils/tree.py41
1 files changed, 19 insertions, 22 deletions
diff --git a/django/utils/tree.py b/django/utils/tree.py
index d13883a00e..a56442c32d 100644
--- a/django/utils/tree.py
+++ b/django/utils/tree.py
@@ -88,31 +88,28 @@ class Node:
Return a node which can be used in place of data regardless if the
node other got squashed or not.
"""
- if self.connector == conn_type and data in self.children:
- return data
- if self.connector == conn_type:
- # We can reuse self.children to append or squash the node other.
- if (isinstance(data, Node) and not data.negated and
- (data.connector == conn_type or len(data) == 1)):
- # We can squash the other node's children directly into this
- # node. We are just doing (AB)(CD) == (ABCD) here, with the
- # addition that if the length of the other node is 1 the
- # connector doesn't matter. However, for the len(self) == 1
- # case we don't want to do the squashing, as it would alter
- # self.connector.
- self.children.extend(data.children)
- return self
- else:
- # We could use perhaps additional logic here to see if some
- # children could be used for pushdown here.
- self.children.append(data)
- return data
- else:
- obj = self._new_instance(self.children, self.connector,
- self.negated)
+ if self.connector != conn_type:
+ obj = self._new_instance(self.children, self.connector, self.negated)
self.connector = conn_type
self.children = [obj, data]
return data
+ elif (
+ isinstance(data, Node) and
+ not data.negated and
+ (data.connector == conn_type or len(data) == 1)
+ ):
+ # We can squash the other node's children directly into this node.
+ # We are just doing (AB)(CD) == (ABCD) here, with the addition that
+ # if the length of the other node is 1 the connector doesn't
+ # matter. However, for the len(self) == 1 case we don't want to do
+ # the squashing, as it would alter self.connector.
+ self.children.extend(data.children)
+ return self
+ else:
+ # We could use perhaps additional logic here to see if some
+ # children could be used for pushdown here.
+ self.children.append(data)
+ return data
def negate(self):
"""Negate the sense of the root connector."""