2016-12-30 11 views
1

私はLaravel 4.2を使用しています。私のアプリケーションは、複数の場所にまたがる在庫を追跡するために使用されています。Laravel orWhere()/ MySQLまたはクエリが長時間かかる

データベースは、inventory_itemsテーブルで設定それらinventory_items_inventory_locationinventory_locationsテーブルとピボットテーブル、レコードが属する在庫アイテムと場所の両方を参照しながら量の値を含むされます。次のSQLを与える

InventoryItem::whereHas('inventoryLocations', function($q) { 
    $q->where('reserved', '>=', 0) 
    ->orWhere('available', '>=', 0) # slow 
    ->orWhere('inbound', '>=', 0) # slow 
    ->orWhere('total', '>=', 0); # slow 
})->toSql(); 

私のクエリは、私はサブクエリとorWhereので、などを使用していLaravelは0より以上の等しい任意の場所の数量値を持つインベントリ項目を見つけることです。

select * from `inventory_items` 
where `inventory_items`.`deleted_at` is null 
and (
    select count(*) from `inventory_locations` 
    inner join `inventory_item_inventory_location` 
    on `inventory_locations`.`id` = `inventory_item_inventory_location`.`inventory_location_id` 
    where `inventory_item_inventory_location`.`inventory_item_id` = `inventory_items`.`id` 
    and `reserved` >= ? 
    or `available` >= ? # slow 
    or `inbound` >= ? # slow 
    or `total` >= ? # slow 
) >= 1 

問題は(#slowによってコードでマーク)or文でクエリ時間が私のLaravelアプリから(または職人いじくり経由)続編Proは、より多くの5Sと直接1Sまでであるということです。これらの 'または'小切手がない場合(つまり、1つの数量タイプ、たとえば '予約済み'のチェックのみ)、クエリはSequel Proの< 100msであり、アプリ/ティッカーでも同様です。

これらの余分な 'または'チェックを追加すると、なぜクエリに時間がかかるのかわかりません。どのようによりパフォーマンスの高いクエリを作成するためのアイデア?

+1

haveテーブルの 'reserved'、' available'、 'inbound'、' total'フィールドにインデックスを追加しましたか? – num8er

+0

一般的に「または」条件では、クエリ実行の可能性があります。また、これらのタイプの動的条件を使用すると、データベースエンジンは決して静的パスを作成しません。だから、準備されたパスよりも多くの時間がかかるかもしれない –

+0

@ num8erはい、私はそれぞれのインデックスを持っていますし、複数のインデックスを試しても(そのための適切な用語がわからない) –

答えて

3

結果クエリとそのWHERE条件を参照してください。私はあなたが必要なものを推測するとあなたは間違いなく、そこにいくつかのブラケットを逃すそれは、行の高量を持つテーブルに対してひどく遅いです全表スキャンになり

where `inventory_item_inventory_location`.`inventory_item_id` = `inventory_items`.`id` 
and (
    `reserved` >= ? 
    or `available` >= ? # 
    or `inbound` >= ? 
    or `total` >= ? 
) 

代わりの

where `inventory_item_inventory_location`.`inventory_item_id` = `inventory_items`.`id` 
and `reserved` >= ? 
or `available` >= ? # slow 
or `inbound` >= ? # slow 
or `total` >= ? 

です。それを固定するために

InventoryItem::whereHas('inventoryLocations', function($q) { 
    $q->where(function($subquery) { 
    $subquery->where('reserved', '>=', 0) 
    ->orWhere('available', '>=', 0) 
    ->orWhere('inbound', '>=', 0) 
    ->orWhere('total', '>=', 0); 
    }); 
})->toSql(); 

InventoryItem::whereHas('inventoryLocations', function($q) { 
    $q->where('reserved', '>=', 0) 
    ->orWhere('available', '>=', 0) # slow 
    ->orWhere('inbound', '>=', 0) # slow 
    ->orWhere('total', '>=', 0); # slow 
})->toSql(); 

を交換MySQLのをチェックしてくださいあなたは、クエリが実行され、どのように多くの行が照会されますどのように分析することができます EXPLAINコマンドを - http://dev.mysql.com/doc/refman/5.7/en/explain.html

+0

パーフェクト - それをサブクエリするのは意味があります。この種の問題をデバッグする方法については、将来的に説明します。ありがとう –

関連する問題