2016-03-30 9 views
0

今日まで私はLaravelの関係に頼っていましたが、私がmysqlログを開いてからとても失望しました。Laravelがモデルクエリを自動的に最適化しないのはなぜですか?

私はコード

Company::with(['users', 'machines'])->get() 

mysql.logはこのよう

select * from `company` where `company`.`id` = '48' limit 1 
select * from `user` where `user`.`company_id` in ('48') 
select * from `machine` where `machine`.`company_id` in ('48') 

Laravelは使用しないのはなぜ熱心なフェッチのために参加するように見える実行?また、パフォーマンスを向上させ、まだLaravelモデルを使用する方法はありますか?

私はDoctrine ORM eager loadingがjoinsを使ってかなりうまく動作することを知っています。


ありがとうございました。

+0

複数の ' - > with()'節は必要ありません。配列の構文を使用してください: ' - > with([" users "、" machines "])'および 'dot.notation'連鎖: ' - > with([" users "、" users.other "])'など –

+0

@TimLewisありがとうございました。 –

+0

問題はありません:)私はそれがパフォーマンスに何らかの影響を与えるとは思っていませんが、コードを読んだり保守したりするのがちょっといいです。また、良い質問です。私は実際にそのようなログをチェックすることは決してありませんでしたが、私はアイデアを持っています*なぜこのようにしていますが、これが最も最適化されているかどうかは考えられません。 –

答えて

2

Eloquentの計算されたクエリの代わりに結合を実際に使用する場合は、流暢なクエリビルダ(Laravelに付属しているDBファサード)を使用し、そのコードをモデルのメソッドすべて素敵なSRPを保つ。例えば

class Company extends Model { 
    public function sqlWithJoin() { 
     $users = DB::table('company') 
     ->leftJoin('user', 'company.id', '=', 'user.company_id') 
     ->get(); 

     return $users; 
    } 
} 

これはあなたのための適切な結合問合せが生成されます。

なぜそうしたいのですか。両方のオプションをベンチマークして、どのデータが特定のデータに対して最高のパフォーマンスを発揮するかを確認する必要があります。私は一般的に、一方のオプションは常に他のオプションよりも良い/悪いパフォーマンスを持っているとは思っていません。

+1

それはまた、ますます多くのデータにロック・テーブルの可能性が広がり、サイトの他のユーザーのパフォーマンスが低下する可能性があります。各テーブルに対して複数の選択クエリを実行することは、ほとんどのActiveRecord実装がどのように機能するかです。 – Dwight

+0

@Dwightこのような重要な説明をいただきありがとうございます。今私は調査の出発点があります。 –

1

コメントに記載されているように、これが推奨される理由はわかりませんが、使いやすさから、モデルの関係にアクセスできるということは、別のプロパティとしてjoin、特にmany-to-oneの関係の場合には、

->with()->leftJoin()の両方の方法を使用して上記の例を比較しましょう。

->with()を使用する場合、すべての関係は、$company->usersによってアクセスされるCompanyのプロパティとして定義されます。 foreach($company->users AS $user)ループを実行してusername,emailなどの出力情報を簡単に実行できます。Companyにはusersが含まれていないと、空の値を表示することを心配する必要はありません(特にチェーンモデルでは重要です)。 users.user_detailsなどの表記)。

今、leftJoin()を見てください。各モデルとそのサブモデルに複数のleftJoins()を連鎖しようとすると、期待している結果が得られない可能性があります。本質的には、leftJoin()は、個々のクエリと同様にNULLレコードも処理しません。 Eloquentがまったくうまく重複のプロパティを処理しないように、これは問題になる

foreach($company AS $row){ 
    echo $row->username; 
    echo $row->email; 
    // etc etc 
} 

次に、同社のユーザーの出力にリストは、次のようなループを実行する必要があります。たとえば、会社にemailフィールドとユーザーがある場合、実際に表示されるのは誰の推測でもあります。 selectRaw("companies.email AS email, users.email AS user_email)"を実行しない限り、1つのemailプロパティのみが返されます。これは、idのような列にも適用されます。ここでは、複数の列はleftJoin()を使用してフェッチされますが、実際にアクセス可能な列は1つだけです。

かいつまんで、重複した情報は、null情報など->with()方法を使用して複数のクエリを実行しているのパフォーマンスはないかもしれないが可能性を持つ複数のテーブルを結合しようとしたときleftJoin()は、問題の多くの潜在的な付属しています最高ですが、情報の検索と表示に使いやすくなります。

+0

このような詳細な回答ありがとうございます!言い換えれば、 'user.email'と' companies.email'の両方にアクセスする場合は、クエリービルダーで ' - > select( 'company.email as company_email')'と書くことができます。私は、LaravelがQBをそのような方法で実装する理由がいくつかあると考えています。なぜなら、join stilを使用すると、クエリを使用するのと同じことをすることができるからです。 Docrine ORMを見てください。これは、Eloquent ORMよりもはるかに強力で、結合を使用しています。 –

関連する問題