Open2

CQRSについて

marcy-momarcy-mo

概要

コマンドクエリ責務分離パターン
2010年にGregYoungが考案

コマンド
CRUDのCreate, Update, Deleteを担当
返り値は持たない(void)

クエリ
CRUDのReadを担当

メリット
Readを分離することでデータ取得時の処理を最適化することができる。最適化によるアプリケーションの性能をあげることができる

CとQを分離させなかった時の問題

・リポジトリのクエリにfindBy~やgetBy~のような微妙にWhere句の違うクエリが作成される。
・N+1クエリが発生しやすい
→データ表示用のモデル(ここではDTO, Readモデルと呼ばれる)を作成する時に発生しやすい
→ホテル予約情報を取得する時に、ホテルの名前、顧客情報、を取ってくるとか
・ドメイン情報からフロントにデータを渡す時に不要なデータが多かったりして効率が悪かったりする

marcy-momarcy-mo

N+1問題復習

例)
usersテーブルとarticleテーブルが1:多の関係で存在する時
articleの一覧表示をする時、記事を書いたユーザー名を取得したい状況を考える。

$articles = Article::all();
foreach($articles as $article) {
    $user = User::where('article_id', '=', $article->id);
}

のようなコードを書くと、
記事取得クエリ+記事の数(N)だけユーザーを取得するクエリが発生する
つまりN+1回クエリが流れることになる。

解決策としては
・joinしたクエリを作成する
select * from article inner join user on user.article_id = article.id;
・whereInを使ったクエリを作成する
select * from article;
select * from users where in article_id in (...);

N+1対策をするには、そのイベント?アクション?に対して最適化されたクエリを発行する必要がある。これを全てのパターンで最適なクエリを作成していくと、リポジトリがfindBy~のようなメソッドで溢れかえって大変なことになる。