Answer the question
In order to leave comments, you need to log in
What is the best way to optimize aggregate queries to the database in Yii2?
It is necessary to display a list of users with the number of purchased goods and the amount of these goods.
The code has been truncated.
use yii\db\ActiveRecord;
use Yii;
use yii\db\Query;
/**
* @property int $id
* @property string $name
* @property Order[] $orders
* @property int $totalOrders
* @property double $totalOrdersPrice
*/
class User extends ActiveRecord
{
public function getOrders()
{
return $this->hasMany(Order::className(), ['user_id' => 'id']);
}
public function getTotalOrders()
{
return $this->hasOne(Order::className(), ['user_id' => 'id'])->count();
}
public function getTotalOrdersPrice()
{
return $this->hasOne(Order::className(), ['user_id' => 'id'])->sum('price');
}
}
/**
* @property int $id
* @property string $date_add
* @property double $price
* @property int $user_id
* @property User $user
*/
class Order extends ActiveRecord
{
public function getUser()
{
return $this->hasOne(User::className(), ['id' => 'user_id']);
}
}
$users = User::find()->with(['orders'])->all();
foreach ($users as $User) {
echo $User->name;
echo $User->totalOrders;
echo $User->totalOrdersPrice;
}
// Например если я вывожу 100 юзеров на страницу, то количество запросов к БД будет = 1 + 1 + 100 + 100 = 202!!
'SELECT * FROM users'; // x 1
'SELECT * FROM orders WHERE user_id IN ( ... )'; // x 1
'SELECT COUNT(*) FROM orders WHERE user_id = ?'; // x 100
'SELECT SUM(price) FROM orders WHERE user_id = ?'; // x 100
$users = User::find()->with(['orders'])->all();
$ids = array_map(function ($User) { return $User->id; }, $users);
$stat = (new Query())
->select(['COUNT(*)', 'SUM(price)'])
->from(Order::tableName())
->where(['in', 'user_id', $ids])
->groupBy(['user_id'])
->all();
// Надо объединить $stat и $users.
// Рефакторить это дело очень плохо!
/**
* @property int $total
* @property double $price
* @property int $user_id
* @property User $user
*/
class Stat
{
/**
* @param User[] $users
* @return Stat[]
*/
public static function fill($users)
{
// ...
'SELECT COUNT(*) as total, SUM(price) as price, user_id FROM orders WHERE user_id IN( ... ) GROUP BY user_id';
// $pdoStatement->fetchAll(PDO::FETCH_CLASS, 'Stat');
// Цепляем юзеров к екзеплярам Stat
// ...
}
}
$stats = Stat::fill(User::find()->with(['orders'])->all());
foreach ($stats as $Stat) {
echo $Stat->user->id;
echo $Stat->total;
}
Answer the question
In order to leave comments, you need to log in
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question