Laravel orWhere()/ MySQL或查询需要很长时间

问题描述:

我使用的是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是的,我有每个索引,并尝试过多个指数(不知道这是适当的术语) –

查看结果查询及其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

完美 - 现在可以对它进行子查询了解更多关于它是如何工作的。将在未来调查解释这类问题。谢谢 –