chore: Optimize Loads on Queries (#4220)

Co-authored-by: Hayden <64056131+hay-kot@users.noreply.github.com>
This commit is contained in:
Michael Genson 2024-09-19 23:10:10 -05:00 committed by GitHub
parent e971efd809
commit ba363da251
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 41 additions and 15 deletions

View File

@ -7,7 +7,7 @@ import sqlalchemy as sa
from pydantic import UUID4 from pydantic import UUID4
from slugify import slugify from slugify import slugify
from sqlalchemy.exc import IntegrityError from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import InstrumentedAttribute, joinedload from sqlalchemy.orm import InstrumentedAttribute
from typing_extensions import Self from typing_extensions import Self
from mealie.db.models.recipe.category import Category from mealie.db.models.recipe.category import Category
@ -165,15 +165,6 @@ class RepositoryRecipes(HouseholdRepositoryGeneric[Recipe, RecipeModel]):
pagination_result = pagination.model_copy() pagination_result = pagination.model_copy()
q = sa.select(self.model) q = sa.select(self.model)
args = [
joinedload(RecipeModel.recipe_category),
joinedload(RecipeModel.tags),
joinedload(RecipeModel.tools),
joinedload(RecipeModel.user),
]
q = q.options(*args)
fltr = self._filter_builder() fltr = self._filter_builder()
q = q.filter_by(**fltr) q = q.filter_by(**fltr)
@ -212,6 +203,8 @@ class RepositoryRecipes(HouseholdRepositoryGeneric[Recipe, RecipeModel]):
q, count, total_pages = self.add_pagination_to_query(q, pagination_result) q, count, total_pages = self.add_pagination_to_query(q, pagination_result)
# Apply options late, so they do not get used for counting
q = q.options(*RecipeSummary.loader_options())
try: try:
data = self.session.execute(q).scalars().unique().all() data = self.session.execute(q).scalars().unique().all()
except Exception as e: except Exception as e:

View File

@ -14,6 +14,7 @@ from mealie.db.models.household import (
ShoppingListRecipeReference, ShoppingListRecipeReference,
) )
from mealie.db.models.recipe import IngredientFoodModel, RecipeModel from mealie.db.models.recipe import IngredientFoodModel, RecipeModel
from mealie.db.models.users.users import User
from mealie.schema._mealie import MealieModel from mealie.schema._mealie import MealieModel
from mealie.schema._mealie.mealie_model import UpdatedAtField from mealie.schema._mealie.mealie_model import UpdatedAtField
from mealie.schema._mealie.types import NoneFloat from mealie.schema._mealie.types import NoneFloat
@ -137,7 +138,9 @@ class ShoppingListItemOut(ShoppingListItemBase):
joinedload(ShoppingListItem.label), joinedload(ShoppingListItem.label),
joinedload(ShoppingListItem.unit), joinedload(ShoppingListItem.unit),
selectinload(ShoppingListItem.recipe_references), selectinload(ShoppingListItem.recipe_references),
joinedload(ShoppingListItem.shopping_list).joinedload(ShoppingList.user), joinedload(ShoppingListItem.shopping_list)
.joinedload(ShoppingList.user)
.load_only(User.household_id, User.group_id),
] ]
@ -232,7 +235,7 @@ class ShoppingListSummary(ShoppingListSave):
.joinedload(ShoppingListRecipeReference.recipe) .joinedload(ShoppingListRecipeReference.recipe)
.joinedload(RecipeModel.tools), .joinedload(RecipeModel.tools),
selectinload(ShoppingList.label_settings).joinedload(ShoppingListMultiPurposeLabel.label), selectinload(ShoppingList.label_settings).joinedload(ShoppingListMultiPurposeLabel.label),
joinedload(ShoppingList.user), joinedload(ShoppingList.user).load_only(User.household_id, User.group_id),
] ]
@ -279,7 +282,7 @@ class ShoppingListOut(ShoppingListUpdate):
.joinedload(ShoppingListRecipeReference.recipe) .joinedload(ShoppingListRecipeReference.recipe)
.joinedload(RecipeModel.tools), .joinedload(RecipeModel.tools),
selectinload(ShoppingList.label_settings).joinedload(ShoppingListMultiPurposeLabel.label), selectinload(ShoppingList.label_settings).joinedload(ShoppingListMultiPurposeLabel.label),
joinedload(ShoppingList.user), joinedload(ShoppingList.user).load_only(User.household_id, User.group_id),
] ]

View File

@ -1,5 +1,9 @@
from pydantic import UUID4, ConfigDict from pydantic import UUID4, ConfigDict
from sqlalchemy.orm import joinedload
from sqlalchemy.orm.interfaces import LoaderOption
from mealie.db.models.household.household import Household
from mealie.db.models.household.preferences import HouseholdPreferencesModel
from mealie.schema._mealie import MealieModel from mealie.schema._mealie import MealieModel
@ -27,3 +31,9 @@ class SaveHouseholdPreferences(UpdateHouseholdPreferences):
class ReadHouseholdPreferences(CreateHouseholdPreferences): class ReadHouseholdPreferences(CreateHouseholdPreferences):
id: UUID4 id: UUID4
model_config = ConfigDict(from_attributes=True) model_config = ConfigDict(from_attributes=True)
@classmethod
def loader_options(cls) -> list[LoaderOption]:
return [
joinedload(HouseholdPreferencesModel.household).load_only(Household.group_id),
]

View File

@ -10,6 +10,7 @@ from sqlalchemy.orm.interfaces import LoaderOption
from mealie.db.models.household import GroupMealPlan from mealie.db.models.household import GroupMealPlan
from mealie.db.models.recipe import RecipeModel from mealie.db.models.recipe import RecipeModel
from mealie.db.models.users.users import User
from mealie.schema._mealie import MealieModel from mealie.schema._mealie import MealieModel
from mealie.schema.recipe.recipe import RecipeSummary from mealie.schema.recipe.recipe import RecipeSummary
from mealie.schema.response.pagination import PaginationBase from mealie.schema.response.pagination import PaginationBase
@ -66,7 +67,7 @@ class ReadPlanEntry(UpdatePlanEntry):
selectinload(GroupMealPlan.recipe).joinedload(RecipeModel.recipe_category), selectinload(GroupMealPlan.recipe).joinedload(RecipeModel.recipe_category),
selectinload(GroupMealPlan.recipe).joinedload(RecipeModel.tags), selectinload(GroupMealPlan.recipe).joinedload(RecipeModel.tags),
selectinload(GroupMealPlan.recipe).joinedload(RecipeModel.tools), selectinload(GroupMealPlan.recipe).joinedload(RecipeModel.tools),
selectinload(GroupMealPlan.user), selectinload(GroupMealPlan.user).load_only(User.household_id),
] ]

View File

@ -14,6 +14,7 @@ from sqlalchemy.orm import Session, joinedload, selectinload
from sqlalchemy.orm.interfaces import LoaderOption from sqlalchemy.orm.interfaces import LoaderOption
from mealie.core.config import get_app_dirs from mealie.core.config import get_app_dirs
from mealie.db.models.users.users import User
from mealie.schema._mealie import MealieModel, SearchType from mealie.schema._mealie import MealieModel, SearchType
from mealie.schema._mealie.mealie_model import UpdatedAtField from mealie.schema._mealie.mealie_model import UpdatedAtField
from mealie.schema.response.pagination import PaginationBase from mealie.schema.response.pagination import PaginationBase
@ -121,6 +122,15 @@ class RecipeSummary(MealieModel):
return val return val
@classmethod
def loader_options(cls) -> list[LoaderOption]:
return [
joinedload(RecipeModel.recipe_category),
joinedload(RecipeModel.tags),
joinedload(RecipeModel.tools),
joinedload(RecipeModel.user).load_only(User.household_id),
]
class RecipePagination(PaginationBase): class RecipePagination(PaginationBase):
items: list[RecipeSummary] items: list[RecipeSummary]

View File

@ -9,6 +9,7 @@ from sqlalchemy.orm.interfaces import LoaderOption
from mealie.core.config import get_app_dirs from mealie.core.config import get_app_dirs
from mealie.db.models.recipe.recipe_timeline import RecipeTimelineEvent from mealie.db.models.recipe.recipe_timeline import RecipeTimelineEvent
from mealie.db.models.users.users import User
from mealie.schema._mealie import MealieModel from mealie.schema._mealie import MealieModel
from mealie.schema._mealie.mealie_model import UpdatedAtField from mealie.schema._mealie.mealie_model import UpdatedAtField
from mealie.schema.recipe.recipe import Recipe from mealie.schema.recipe.recipe import Recipe
@ -67,7 +68,7 @@ class RecipeTimelineEventOut(RecipeTimelineEventCreate):
def loader_options(cls) -> list[LoaderOption]: def loader_options(cls) -> list[LoaderOption]:
return [ return [
joinedload(RecipeTimelineEvent.recipe), joinedload(RecipeTimelineEvent.recipe),
joinedload(RecipeTimelineEvent.user), joinedload(RecipeTimelineEvent.user).load_only(User.household_id, User.group_id),
] ]
@classmethod @classmethod

View File

@ -8,7 +8,9 @@ from sqlalchemy.orm import joinedload, selectinload
from sqlalchemy.orm.interfaces import LoaderOption from sqlalchemy.orm.interfaces import LoaderOption
from mealie.core.config import get_app_dirs, get_app_settings from mealie.core.config import get_app_dirs, get_app_settings
from mealie.db.models.recipe.recipe import RecipeModel
from mealie.db.models.users import User from mealie.db.models.users import User
from mealie.db.models.users.user_to_recipe import UserToRecipe
from mealie.db.models.users.users import AuthMethod, LongLiveToken from mealie.db.models.users.users import AuthMethod, LongLiveToken
from mealie.schema._mealie import MealieModel from mealie.schema._mealie import MealieModel
from mealie.schema.group.group_preferences import ReadGroupPreferences from mealie.schema.group.group_preferences import ReadGroupPreferences
@ -88,6 +90,12 @@ class UserRatingUpdate(MealieModel):
class UserRatingOut(UserRatingCreate): class UserRatingOut(UserRatingCreate):
id: UUID4 id: UUID4
@classmethod
def loader_options(cls) -> list[LoaderOption]:
return [
joinedload(UserToRecipe.recipe).joinedload(RecipeModel.user).load_only(User.household_id, User.group_id)
]
class UserRatings(BaseModel, Generic[DataT]): class UserRatings(BaseModel, Generic[DataT]):
ratings: list[DataT] ratings: list[DataT]