[rqlrewrite/schema] Avoid parsing computed relations for each query
The RQLRelationRewriter is instanciated for each RQL query, it should
avoid parsing computed relations formula by using a cache, which seems rightly
located on the instance's schema.
This brings a *huge* performance boost to some pages on application with a few
computed relations (x4 observed on a client app).
Kudos to Adrien, David and Sylvain.
Closes #17059828
--- a/cubicweb/rqlrewrite.py Wed Mar 22 13:58:28 2017 +0100
+++ b/cubicweb/rqlrewrite.py Wed Mar 01 18:07:49 2017 +0100
@@ -905,22 +905,18 @@
This class *isn't thread safe*.
"""
- def __init__(self, session):
- super(RQLRelationRewriter, self).__init__(session)
- self.rules = {}
- for rschema in self.schema.iter_computed_relations():
- self.rules[rschema.type] = RRQLExpression(rschema.rule)
def rewrite(self, union, kwargs=None):
self.kwargs = kwargs
self.removing_ambiguity = False
self.existingvars = None
self.pending_keys = None
+ rules = self.schema.rules_rqlexpr_mapping
for relation in union.iget_nodes(n.Relation):
- if relation.r_type in self.rules:
+ if relation.r_type in rules:
self.select = relation.stmt
self.solutions = solutions = self.select.solutions[:]
- self.current_expr = self.rules[relation.r_type]
+ self.current_expr = rules[relation.r_type]
self._insert_scope = relation.scope
self.rewritten = {}
lhs, rhs = relation.get_variable_parts()
--- a/cubicweb/schema.py Wed Mar 22 13:58:28 2017 +0100
+++ b/cubicweb/schema.py Wed Mar 01 18:07:49 2017 +0100
@@ -1008,6 +1008,16 @@
etype_name_re = r'[A-Z][A-Za-z0-9]*[a-z]+[A-Za-z0-9]*$'
+ @cachedproperty
+ def rules_rqlexpr_mapping(self):
+ """Return a dictionary mapping rtype to RRQLExpression for computed
+ relations.
+ """
+ rules = {}
+ for rschema in self.iter_computed_relations():
+ rules[rschema.type] = RRQLExpression(rschema.rule)
+ return rules
+
def add_entity_type(self, edef):
edef.name = str(edef.name)
edef.name = bw_normalize_etype(edef.name)
@@ -1148,6 +1158,8 @@
super(CubicWebSchema, self).rebuild_infered_relations()
self.finalize_computed_attributes()
self.finalize_computed_relations()
+ # remove @cachedproperty cache
+ self.__dict__.pop('rules_rqlexpr_mapping', None)
# additional cw specific constraints ###########################################