【要約】【SQLAlchemy 2.x】リレーションとN+1問題を理解して`selectinload()`を使いこなす [Zenn_Python] | Summary by TechDistill
> Source: Zenn_Python
Execute Primary Source
// Problem
開発者がSQLAlchemyを用いてリレーションを持つモデルを操作する際、パフォーマンス低下を招くN+1問題に直面する。具体的には以下の課題が生じる。
- ・デフォルトのLazy Loadingにより、関連データへのアクセスごとにSQLが追加発行される。
- ・AsyncSession環境では、暗黙的なI/Oが発生するLazy Loadingが実行時エラーの原因となる。
- ・大量のデータを扱う際、SQL発行回数の増大がシステム全体のレイテンシを悪化させる。
// Approach
開発者は、クエリ実行時にロード戦略を明示的に指定するEager Loadingを採用することで、この問題を解決する。以下の手法を状況に応じて使い分ける。
- ・
selectinload(): コレクション(One-to-Many等)に対し、IN句を用いて一括取得する。 - ・
joinedload(): 単一の関連先(Many-to-One等)に対し、JOINを用いて一括取得する。 - ・
unique():joinedload()でコレクションを取得する際の重複行を排除する。
// Result
適切なロード戦略を選択することで、データベースへのクエリ発行回数を最小限に抑えられる。これにより以下の成果が得られる。
- ・One-to-Many/Many-to-Manyでは
selectinload()により効率的な取得を実現する。 - ・Many-to-One/One-to-Oneでは
joinedload()により単一取得を行う。 - ・N+1問題を解消し、アプリケーションの応答性能とスケーラビリティを向上させる。
Senior Engineer Insight
> 非同期環境での開発において、ロード戦略の理解は不可欠である。Lazy Loadingによる暗黙的なI/Oは、実行時エラーや予期せぬレイテンシ増大を招く。高負荷なシステムでは、クエリレベルで「何を、いつ、どのように」ロードするかを厳格に制御すべきだ。特にコレクションの取得には
selectinload()を優先する判断が、運用コストの低減に直結する。