2016-12-30 184 views
1

我使用的是Laravel 4.2,我的應用程序用於跟蹤跨多個位置的庫存。Laravel orWhere()/ MySQL或查詢需要很長時間

該數據庫建立與inventory_items表,inventory_locations表和他們inventory_items_inventory_location之間的樞轉表,其中包含同時參照兩個庫存物品和位置的數量的值的記錄所屬的。

我的查詢是要找到具有任何位置量值爲0。Laravel大於或等於我使用子查詢和orWhere像這樣的庫存物品:

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

這給下面的SQL:

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 

的問題是,與or陳述(由#slow標代碼)查詢時間長達與續集專業直接1S,超過通過我的Laravel應用程序(或通過工匠鼓搗)5秒。如果沒有這些'或'檢查(即只檢查一種數量類型,例如'保留'),則在Sequel Pro上的查詢是< 100ms,而在應用/修補程序上則是類似的。

我不確定爲什麼添加這些額外的'或'檢查會爲查詢增加太多時間。任何想法如何使一個更高性能的查詢?

+1

您是否在表格的'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('reserved', '>=', 0) 
    ->orWhere('available', '>=', 0) # slow 
    ->orWhere('inbound', '>=', 0) # slow 
    ->orWhere('total', '>=', 0); # slow 
})->toSql(); 

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

退房MySQL的EXPLAIN命令,可以讓你分析如何查詢將被執行,多少行會被質疑 - http://dev.mysql.com/doc/refman/5.7/en/explain.html

+0

完美 - 現在可以對它進行子查詢瞭解更多關於它是如何工作的。將在未來調查解釋這類問題。謝謝 –