ускорение метода count
-
- Сообщения: 34
- Зарегистрирован: 2013.11.19, 16:51
ускорение метода count
когда открывается грид, фрэймворк вызывает метод count в CActiveFinder. Также есть метод createCountCommand в CDbCommandBuilder. Там для подсчета выполняется такой запрос "SELECT COUNT(*) FROM ($sql) sq" где $sql подзапрос из метода search модели.
Если подзапрос достаточно сложный, с джойнами и таблица большая, то он может выполняться неоправданно долго, у меня в одном из модулей, например, полторы секунды. Я решил попробовать изменить выбираемые поля (между select и from) на 1, ведь для каунта нам ничего не нужно. При этом запрос выполнялся менее полусекунды, тоесть в 3 раза быстрее.
Почему в стандартном фрэймворке не парсят подобным образом строку, ведь это существенно ускоряет работу с большими таблицами?
Если подзапрос достаточно сложный, с джойнами и таблица большая, то он может выполняться неоправданно долго, у меня в одном из модулей, например, полторы секунды. Я решил попробовать изменить выбираемые поля (между select и from) на 1, ведь для каунта нам ничего не нужно. При этом запрос выполнялся менее полусекунды, тоесть в 3 раза быстрее.
Почему в стандартном фрэймворке не парсят подобным образом строку, ведь это существенно ускоряет работу с большими таблицами?
-
- Сообщения: 34
- Зарегистрирован: 2013.11.19, 16:51
Re: ускорение метода count
до
после:
Код: Выделить всё
mysql> SELECT COUNT(*)
-> FROM (
-> SELECT `t`.`id` AS `t0_c0`,
-> `t`.`name` AS `t0_c1`,
-> `t`.`job_id` AS `t0_c2`,
-> `t`.`request_id` AS `t0_c3`,
-> `t`.`sender_id` AS `t0_c4`,
-> `t`.`receiver_id` AS `t0_c5`,
-> `t`.`sender_contact_id` AS `t0_c6`,
-> `t`.`receiver_contact_id` AS `t0_c7`,
-> `t`.`sender_address_id` AS `t0_c8`,
-> `t`.`receiver_address_id` AS `t0_c9`,
-> `t`.`pieces` AS `t0_c10`,
-> `t`.`weight` AS `t0_c11`,
-> `t`.`pieces_weight` AS `t0_c12`,
-> `t`.`volume` AS `t0_c13`,
-> `t`.`control_volume` AS `t0_c14`,
-> `t`.`volume_weight` AS `t0_c15`,
-> `t`.`volume_weight_divisor` AS `t0_c16`,
-> `t`.`control_weight` AS `t0_c17`,
-> `t`.`pieces_control_weight` AS `t0_c18`,
-> `t`.`control_volume_weight` AS `t0_c19`,
-> `t`.`size` AS `t0_c20`,
-> `t`.`control_size` AS `t0_c21`,
-> `t`.`date_expected_start` AS `t0_c22`,
-> `t`.`date_expected_end` AS `t0_c23`,
-> `t`.`time_expected_start` AS `t0_c24`,
-> `t`.`time_expected_end` AS `t0_c25`,
-> `t`.`date_received` AS `t0_c26`,
-> `t`.`time_received` AS `t0_c27`,
-> `t`.`receiver_lastname` AS `t0_c28`,
-> `t`.`seal` AS `t0_c29`,
-> `t`.`payer_id` AS `t0_c30`,
-> `t`.`date_collect` AS `t0_c31`,
-> `t`.`time_collect` AS `t0_c32`,
-> `t`.`content_type_id` AS `t0_c33`,
-> `t`.`desc` AS `t0_c34`,
-> `t`.`package_type_ids` AS `t0_c35`,
-> `t`.`fragile` AS `t0_c36`,
-> `t`.`status_id` AS `t0_c37`,
-> `t`.`status_address_id` AS `t0_c38`,
-> `t`.`add_status_id` AS `t0_c39`,
-> `t`.`document_id` AS `t0_c40`,
-> `t`.`control` AS `t0_c41`,
-> `t`.`close` AS `t0_c42`,
-> `t`.`cdate` AS `t0_c43`,
-> `t`.`mdate` AS `t0_c44`,
-> `t`.`creator_id` AS `t0_c45`,
-> `t`.`score_weight` AS `t0_c46`,
-> `t`.`pod_comment_id` AS `t0_c47`,
-> `t`.`temp` AS `t0_c48`,
-> `manifests`.`id` AS `t1_c0`,
-> `job`.`id` AS `t2_c0`,
-> `job`.`name` AS `t2_c1`,
-> `job`.`city_from_id` AS `t2_c2`,
-> `job`.`city_to_id` AS `t2_c3`,
-> `job`.`customer_id` AS `t2_c4`,
-> `job`.`service_id` AS `t2_c5`,
-> `job`.`tariff_name_id` AS `t2_c6`,
-> `job`.`delivery_type_id` AS `t2_c7`,
-> `job`.`add_service_ids` AS `t2_c8`,
-> `job`.`filial_id` AS `t2_c9`,
-> `job`.`desc` AS `t2_c10`,
-> `job`.`cdate` AS `t2_c11`,
-> `job`.`mdate` AS `t2_c12`,
-> `job`.`creator_id` AS `t2_c13`
-> FROM `bill` `t`
-> LEFT OUTER JOIN `rel_bill_manifest` `manifests_manifests` ON (`t`.`id`=`manifests_manifests`.`bill_id`)
-> LEFT OUTER JOIN `manifest` `manifests` ON (`manifests`.`id`=`manifests_manifests`.`manifest_id`)
-> LEFT OUTER JOIN `job` `job` ON (`t`.`job_id`=`job`.`id`) GROUP BY t.id
-> ) sq;
+----------+
| COUNT(*) |
+----------+
| 88472 |
+----------+
1 row in set (1,44 sec)
Код: Выделить всё
mysql> SELECT COUNT(*)
-> FROM (
-> SELECT 1
-> FROM `bill` `t`
-> LEFT OUTER JOIN `rel_bill_manifest` `manifests_manifests` ON (`t`.`id`=`manifests_manifests`.`bill_id`)
-> LEFT OUTER JOIN `manifest` `manifests` ON (`manifests`.`id`=`manifests_manifests`.`manifest_id`)
-> LEFT OUTER JOIN `job` `job` ON (`t`.`job_id`=`job`.`id`) GROUP BY t.id
-> ) sq;
+----------+
| COUNT(*) |
+----------+
| 88472 |
+----------+
1 row in set (0,46 sec)
Re: ускорение метода count
там могут быть having, и после этого запрос будет не рабочий
ну и вообще в 1й версии фреймверка со сложными запросами в AR беда
ну и вообще в 1й версии фреймверка со сложными запросами в AR беда
Последний раз редактировалось rak 2016.12.13, 21:41, всего редактировалось 1 раз.
-
- Сообщения: 34
- Зарегистрирован: 2013.11.19, 16:51
Re: ускорение метода count
ну можно же чекать на хэвинг и тд.
Re: ускорение метода count
maxtorchel писал(а):Почему в стандартном фрэймворке не парсят подобным образом строку, ведь это существенно ускоряет работу с большими таблицами?
щас еще накидают пяток примеров, на которые нужно чекать, а фреймворк должен быть максимально простым и понятным, без хаков.maxtorchel писал(а):ну можно же чекать на хэвинг и тд.
-
- Сообщения: 34
- Зарегистрирован: 2013.11.19, 16:51
Re: ускорение метода count
Переопределил метод, прирост производительности в реальных гридах до 30%. Например, в одном модуле грузилось 5 сек, после обновления 3.5. Я считаю это более чем оправдано.
ps лично у меня нет запросов с хэвингом и тому подобным, однако кидайте примеры что еще исключить, может кому-то пригодится.
ps лично у меня нет запросов с хэвингом и тому подобным, однако кидайте примеры что еще исключить, может кому-то пригодится.
Код: Выделить всё
private function parseCountSql($sql)
{
if(!strpos($sql, 'HAVING')){
$selectIdx = strpos($sql, 'SELECT');
$fromIdx = strpos($sql, 'FROM');
$sql = substr_replace($sql, ' 1 ', $selectIdx+6, $fromIdx-$selectIdx-6);
}
return $sql;
}
Re: ускорение метода count
в yii2 например ты сам назначаешь totalItemCount, и это правильно. В yii1 кстати тоже. И не надо фреймворк хачить.
-
- Сообщения: 34
- Зарегистрирован: 2013.11.19, 16:51
Re: ускорение метода count
да, так лучше, спасибо. вынес в отдельный метод
Код: Выделить всё
protected function getDataProviderTotalItemCount($criteria)
{
$countCriteria = new CDbCriteria($criteria->toArray());
$countCriteria->select = 't.id';
$countCriteria->order = '';
$countCriteria->together = true;
array_walk($countCriteria->with, function (&$params,$relation){
$params['select'] = $relation.'.id';
});
return static::model()->count($countCriteria);
}