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
from sqlalchemy.orm.attributes import InstrumentedAttribute
from sqlalchemy.orm import subqueryload
from sqlalchemy.sql.expression import desc
from sqlalchemy import or_, Column
from sqlalchemy import or_, Column, func
from flask import flash
......@@ -573,6 +573,12 @@ class ModelView(BaseModelView):
"""
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):
"""
Return models from the database.
......@@ -595,6 +601,7 @@ class ModelView(BaseModelView):
joins = set()
query = self.get_query()
count_query = self.get_count_query()
# Apply search criteria
if self._search_supported and search:
......@@ -602,6 +609,7 @@ class ModelView(BaseModelView):
if self._search_joins:
for jn in self._search_joins.values():
query = query.join(jn)
count_query = count_query.join(jn)
joins = set(self._search_joins.keys())
......@@ -615,6 +623,7 @@ class ModelView(BaseModelView):
stmt = tools.parse_like_term(term)
filter_stmt = [c.ilike(stmt) for c in self._search_fields]
query = query.filter(or_(*filter_stmt))
count_query = count_query.filter(or_(*filter_stmt))
# Apply filters
if filters and self._filters:
......@@ -629,13 +638,15 @@ class ModelView(BaseModelView):
for table in join_tables:
if table.name not in joins:
query = query.join(table)
count_query = count_query.join(table)
joins.add(table.name)
# Apply filter
query = flt.apply(query, value)
count_query = flt.apply(count_query, value)
# Calculate number of rows
count = query.count()
count = count_query.scalar()
# Auto join
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