Commit 45a27235 authored by Bruno Azzinnari's avatar Bruno Azzinnari

Fix for a performance issue when getting the total row count when implementing...

Fix for a performance issue when getting the total row count when implementing paging. When dealing with about 250.000 rows, it was taking about 30 secs to show one page on the first load. With this modifications it executes almost instantly.

The problem was that the query applying .count() to the current query generated the SQL:

SELECT count(*) AS count_1
FROM ( SELECT ModelView-columns FROM ModelView-table WHERE conditions ) as anon_1;

which made it actually get all the data in the inner query for then counting the rows and returning the amount. With this modification, the generated query is:

SELECT count(*) AS count_1
FROM ModelView-table
WHERE conditions;

that executes instantly.
parent 2fd4880a
...@@ -3,7 +3,7 @@ import logging ...@@ -3,7 +3,7 @@ import logging
from sqlalchemy.orm.attributes import InstrumentedAttribute from sqlalchemy.orm.attributes import InstrumentedAttribute
from sqlalchemy.orm import subqueryload from sqlalchemy.orm import subqueryload
from sqlalchemy.sql.expression import desc from sqlalchemy.sql.expression import desc
from sqlalchemy import or_, Column from sqlalchemy import or_, Column, func
from flask import flash from flask import flash
...@@ -573,6 +573,12 @@ class ModelView(BaseModelView): ...@@ -573,6 +573,12 @@ class ModelView(BaseModelView):
""" """
return self.session.query(self.model) return self.session.query(self.model)
def get_count_query(self):
"""
Return a the count query for the model type
"""
return self.session.query( func.count('*') ).select_from(self.model)
def get_list(self, page, sort_column, sort_desc, search, filters, execute=True): def get_list(self, page, sort_column, sort_desc, search, filters, execute=True):
""" """
Return models from the database. Return models from the database.
...@@ -595,6 +601,7 @@ class ModelView(BaseModelView): ...@@ -595,6 +601,7 @@ class ModelView(BaseModelView):
joins = set() joins = set()
query = self.get_query() query = self.get_query()
count_query = self.get_count_query()
# Apply search criteria # Apply search criteria
if self._search_supported and search: if self._search_supported and search:
...@@ -602,6 +609,7 @@ class ModelView(BaseModelView): ...@@ -602,6 +609,7 @@ class ModelView(BaseModelView):
if self._search_joins: if self._search_joins:
for jn in self._search_joins.values(): for jn in self._search_joins.values():
query = query.join(jn) query = query.join(jn)
count_query = count_query.join(jn)
joins = set(self._search_joins.keys()) joins = set(self._search_joins.keys())
...@@ -615,6 +623,7 @@ class ModelView(BaseModelView): ...@@ -615,6 +623,7 @@ class ModelView(BaseModelView):
stmt = tools.parse_like_term(term) stmt = tools.parse_like_term(term)
filter_stmt = [c.ilike(stmt) for c in self._search_fields] filter_stmt = [c.ilike(stmt) for c in self._search_fields]
query = query.filter(or_(*filter_stmt)) query = query.filter(or_(*filter_stmt))
count_query = count_query.filter(or_(*filter_stmt))
# Apply filters # Apply filters
if filters and self._filters: if filters and self._filters:
...@@ -629,13 +638,15 @@ class ModelView(BaseModelView): ...@@ -629,13 +638,15 @@ class ModelView(BaseModelView):
for table in join_tables: for table in join_tables:
if table.name not in joins: if table.name not in joins:
query = query.join(table) query = query.join(table)
count_query = count_query.join(table)
joins.add(table.name) joins.add(table.name)
# Apply filter # Apply filter
query = flt.apply(query, value) query = flt.apply(query, value)
count_query = flt.apply(count_query, value)
# Calculate number of rows # Calculate number of rows
count = query.count() count = count_query.scalar()
# Auto join # Auto join
for j in self._auto_joins: for j in self._auto_joins:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment