Php Laravel或where()/MySQL或查询耗时较长

Php Laravel或where()/MySQL或查询耗时较长,php,mysql,laravel,laravel-4,eloquent,Php,Mysql,Laravel,Laravel 4,Eloquent,我使用的是Laravel4.2,我的应用程序用于跟踪多个地点的库存 数据库由库存项目表、库存位置表和它们之间的数据透视表组成,其中包含数量值,同时引用记录所属的库存项目和位置 我的查询是查找任何位置数量值大于或等于0的库存项目。在Laravel中,我使用了一个子查询,或者类似于: InventoryItem::whereHas('inventoryLocations', function($q) { $q->where('reserved', '>=', 0) ->

我使用的是Laravel4.2,我的应用程序用于跟踪多个地点的库存

数据库由库存项目表、库存位置表和它们之间的数据透视表组成,其中包含数量值,同时引用记录所属的库存项目和位置

我的查询是查找任何位置数量值大于或等于0的库存项目。在Laravel中,我使用了一个子查询,或者类似于:

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

问题在于,使用Sequel Pro直接在代码中以slow标记的or语句,查询时间最多为1s,而通过my Laravel应用程序或artisan tinker,查询时间超过5s。如果没有这些“或”检查,即仅检查一种数量类型,例如“保留”,则查询为查看结果查询及其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();


查看MySQL的EXPLAIN命令,该命令允许您分析如何执行查询以及将查询多少行-

您是否在表的保留字段、可用字段、入站字段和总计字段上添加了索引?通常情况下,或在条件允许的情况下,可以执行查询。而且,当您使用这些类型的动态条件时,数据库引擎从不生成静态路径。因此,它可能需要比每个路径更多的时间。表中有多少行?另外,我假设您的可用值、入站值和总计值可以为负值,对吗?@Mr Office,通常情况下,类将进行逐级筛选。但在哪里没有什么不同。无论是否使用上一个过滤器,过滤过程都将完全改变。因此,每次使用orWhere时,它都会动态地更改其流。所以可能会有明显的时间延迟。@ Office,EX.考虑,学生名单。姓名|姓氏|电子邮件共100条记录。查询:从姓氏为“%john%”或电子邮件为“%sales%”的学生中选择*;这里,它产生3种可能的概率,1。姓氏如“%john%”,2。类似“%sales%”的电子邮件,3。LastName(如“%john%”或电子邮件(如“%sales%”),这三个将动态触发!完美-有意义的子查询现在我知道了一点关于它是如何工作的。将来将研究解释如何调试此类问题。谢谢
InventoryItem::whereHas('inventoryLocations', function($q) {
  $q->where(function($subquery) {
    $subquery->where('reserved', '>=', 0)
     ->orWhere('available', '>=', 0)
     ->orWhere('inbound', '>=', 0)
     ->orWhere('total', '>=', 0);
  });
})->toSql();