Laravel orWhere() / MySQL 或查询耗时较长
Laravel orWhere() / MySQL or query taking a long time
我正在使用 Laravel 4.2 并且我的应用程序用于跨多个位置跟踪库存。
数据库设置有 inventory_items
table、inventory_locations
table 和它们之间的枢轴 table 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
)查询时间直接用Sequel Pro最多1s,通过我的超过5s Laravel 应用程序(或通过 artisan tinker)。如果没有这些 'or' 检查(即只检查一种数量类型,例如 'reserved'),查询在 Sequel Pro 上小于 100 毫秒,在 app/tinker.
上类似
我不确定为什么添加这些额外的 'or' 检查会增加查询的时间。有什么想法可以提高查询的性能吗?
查看生成的查询及其 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` >= ?
它会导致完整的 table 扫描,这对于 table 秒的大量行来说非常慢。
为了解决这个问题,更换
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
我正在使用 Laravel 4.2 并且我的应用程序用于跨多个位置跟踪库存。
数据库设置有 inventory_items
table、inventory_locations
table 和它们之间的枢轴 table 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
)查询时间直接用Sequel Pro最多1s,通过我的超过5s Laravel 应用程序(或通过 artisan tinker)。如果没有这些 'or' 检查(即只检查一种数量类型,例如 'reserved'),查询在 Sequel Pro 上小于 100 毫秒,在 app/tinker.
我不确定为什么添加这些额外的 'or' 检查会增加查询的时间。有什么想法可以提高查询的性能吗?
查看生成的查询及其 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` >= ?
它会导致完整的 table 扫描,这对于 table 秒的大量行来说非常慢。
为了解决这个问题,更换
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