Php Laravel或where()/MySQL或查询耗时较长
我使用的是Laravel4.2,我的应用程序用于跟踪多个地点的库存 数据库由库存项目表、库存位置表和它们之间的数据透视表组成,其中包含数量值,同时引用记录所属的库存项目和位置 我的查询是查找任何位置数量值大于或等于0的库存项目。在Laravel中,我使用了一个子查询,或者类似于: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) ->
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();