This is an automated email from the ASF dual-hosted git repository.
johnbodley pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new b3e699b perf: Refactor Dashboard.datasets_trimmed_for_slices (#15648)
b3e699b is described below
commit b3e699b76705185ac9db29d9ee0c4478f02231cc
Author: John Bodley <[email protected]>
AuthorDate: Tue Jul 13 20:00:57 2021 -0700
perf: Refactor Dashboard.datasets_trimmed_for_slices (#15648)
Co-authored-by: John Bodley <[email protected]>
---
superset/models/dashboard.py | 47 ++++++++++++++++++++++++++++++++++----------
1 file changed, 37 insertions(+), 10 deletions(-)
diff --git a/superset/models/dashboard.py b/superset/models/dashboard.py
index a4a715c..4b5a294 100644
--- a/superset/models/dashboard.py
+++ b/superset/models/dashboard.py
@@ -18,8 +18,9 @@ from __future__ import annotations
import json
import logging
+from collections import defaultdict
from functools import partial
-from typing import Any, Callable, Dict, List, Set, Union
+from typing import Any, Callable, Dict, List, Set, Tuple, Type, Union
import sqlalchemy as sqla
from flask_appbuilder import Model
@@ -171,8 +172,21 @@ class Dashboard( # pylint:
disable=too-many-instance-attributes
@property
def datasources(self) -> Set[BaseDatasource]:
- # pylint: disable=using-constant-test
- return {slc.datasource for slc in self.slices if slc.datasource}
+ # Verbose but efficient database enumeration of dashboard datasources.
+ datasources_by_cls_model: Dict[Type["BaseDatasource"], Set[int]] =
defaultdict(
+ set
+ )
+
+ for slc in self.slices:
+ datasources_by_cls_model[slc.cls_model].add(slc.datasource_id)
+
+ return {
+ datasource
+ for cls_model, datasource_ids in datasources_by_cls_model.items()
+ for datasource in db.session.query(cls_model)
+ .filter(cls_model.id.in_(datasource_ids))
+ .all()
+ }
@property
def charts(self) -> List[BaseDatasource]:
@@ -246,13 +260,26 @@ class Dashboard( # pylint:
disable=too-many-instance-attributes
unless=lambda: not is_feature_enabled("DASHBOARD_CACHE"),
)
def datasets_trimmed_for_slices(self) -> List[Dict[str, Any]]:
- datasource_slices = utils.indexed(self.slices, "datasource")
- return [
- # Filter out unneeded fields from the datasource payload
- datasource.data_for_slices(slices)
- for datasource, slices in datasource_slices.items()
- if datasource
- ]
+ # Verbose but efficient database enumeration of dashboard datasources.
+ slices_by_datasource: Dict[
+ Tuple[Type["BaseDatasource"], int], Set[Slice]
+ ] = defaultdict(set)
+
+ for slc in self.slices:
+ slices_by_datasource[(slc.cls_model, slc.datasource_id)].add(slc)
+
+ result: List[Dict[str, Any]] = []
+
+ for (cls_model, datasource_id), slices in slices_by_datasource.items():
+ datasource = (
+
db.session.query(cls_model).filter_by(id=datasource_id).one_or_none()
+ )
+
+ if datasource:
+ # Filter out unneeded fields from the datasource payload
+ result.append(datasource.data_for_slices(slices))
+
+ return result
@property # type: ignore
def params(self) -> str: # type: ignore