【发布时间】:2015-01-28 02:48:19
【问题描述】:
我无法弄清楚我的 Laravel 脚本发生了什么。我只是选择一个对象,并在其上调用一个运行其他查询的方法,但我看到的行为非常不一致。代码如下:
$product = Product::find(1);
echo $product->numberOfOrders('2014-05-22', '2015-01-27');
这是numberOfOrders 方法的代码:
public function numberOfOrders($startDate = NULL, $endDate = NULL)
{
if(is_null($startDate)) $startDate = '0000-00-00 00:00:00';
if(is_null($endDate)) $endDate = date("Y-m-d");
return Order::whereHas('orderProducts', function($query)
{
$query->where('product_id', $this->id);
})->whereHas('status', function($query)
{
$query->where('sales_data', 1);
})->where('ext_created_at', '>=', $startDate)->where('ext_created_at', '<=', $endDate.' 23:59:59')->distinct()->count();
}
当这段代码运行时,它会挂起大约 10 秒,然后返回整数结果。然后,如果我再次运行相同的代码,它会立即返回结果,并且每次运行时都会继续这样做。如果我更改$startDate,并再次运行代码,它会挂起 10 秒,然后返回结果。然后,重新运行代码将再次立即返回结果。
其他时候,当代码挂起时,我没有返回结果,而是收到一条错误消息:
PHP Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000]: General error: 2027 Malformed packet' in /var/www/html/app/vendor/laravel/framework/src/Illuminate/Database/Connection.php:299
出现错误信息后,如果我再次运行代码,结果会立即返回。
对于导致我的代码出现这种不一致的原因,我感到非常困惑。我没有对缓存做任何事情。
我注意到whereHas 方法实际上将子查询添加到查询中,而不是使用连接,我觉得这很奇怪。使用 Datamapper ORM 在 CodeIgniter 中编写类似的代码会将连接添加到查询而不是子查询,从而产生更好的性能。子查询会导致问题吗?如果是这样,我仍然不确定为什么事情会表现得如此不一致。
我已经捕获了一些数据,显示问题正在发生。这是DB::getQueryLog() 第一次的输出:
[3] => Array
(
[query] => select count(*) as aggregate from `orders` where `orders`.`deleted_at` is null and (select count(*) from `order_products` where `order_products`.`order_id` = `orders`.`id` and `product_id` = ? and `order_products`.`deleted_at` is null) >= 1 and (select count(*) from `order_statuses` where `orders`.`order_status_id` = `order_statuses`.`id` and `sales_data` = ? and `order_statuses`.`deleted_at` is null) >= 1 and `ext_created_at` >= ? and `ext_created_at` <= ?
[bindings] => Array
(
[0] => 1
[1] => 1
[2] => 2014-07-29
[3] => 2015-01-27 23:59:59
)
[time] => 22391.73
)
如您所见,运行需要很长时间。完成后,我再次运行相同的操作,输出如下:
[3] => Array
(
[query] => select count(*) as aggregate from `orders` where `orders`.`deleted_at` is null and (select count(*) from `order_products` where `order_products`.`order_id` = `orders`.`id` and `product_id` = ? and `order_products`.`deleted_at` is null) >= 1 and (select count(*) from `order_statuses` where `orders`.`order_status_id` = `order_statuses`.`id` and `sales_data` = ? and `order_statuses`.`deleted_at` is null) >= 1 and `ext_created_at` >= ? and `ext_created_at` <= ?
[bindings] => Array
(
[0] => 1
[1] => 1
[2] => 2014-07-29
[3] => 2015-01-27 23:59:59
)
[time] => 22391.73
)
[4] => Array
(
[query] => select count(*) as aggregate from `orders` where `orders`.`deleted_at` is null and (select count(*) from `order_products` where `order_products`.`order_id` = `orders`.`id` and `product_id` = ? and `order_products`.`deleted_at` is null) >= 1 and (select count(*) from `order_statuses` where `orders`.`order_status_id` = `order_statuses`.`id` and `sales_data` = ? and `order_statuses`.`deleted_at` is null) >= 1 and `ext_created_at` >= ? and `ext_created_at` <= ?
[bindings] => Array
(
[0] => 1
[1] => 1
[2] => 2014-07-29
[3] => 2015-01-27 23:59:59
)
[time] => 1.81
)
如您所见,查询完全相同,但速度要快得多。为什么会有这样的差异?结果是否缓存在某处?
如果有帮助,我将使用 php artisan tinker 运行所有这些代码。
编辑 经过更多研究,我了解到这可能是mysql query cache 的行为。
【问题讨论】:
标签: php mysql laravel laravel-4 eloquent