SELECT c.count FROM ( ... ) as с - есл и в запросе есть group by

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
Wizard
Сообщения: 162
Зарегистрирован: 2018.02.05, 13:41
Контактная информация:

SELECT c.count FROM ( ... ) as с - есл и в запросе есть group by

Сообщение Wizard » 2018.07.05, 12:20

Столкнулся с таким вопросом

формирую запрос

Код: Выделить всё

        $query = $this->store->getProducts()
            ->with(['images'])
            ->alias('p')
            ->isPubliched('p')
            ->category($category, 'p');

Код: Выделить всё

    public function isPubliched($alias = null)
    {
        return $this
            ->active($alias)
            ->hasPrice($alias)
            ->hasImages($alias);
            ->groupBy(($alias ? $alias . '.' : '') .'id');
    }

Код: Выделить всё

    public function hasImages()
    {
        return $this->joinWith('images', true , 'INNER JOIN');
    }
получается
SELECT c.count FROM (
SELECT p.* FROM `product` p ... INNER JOIN product_image ... GROUP BY p.id
) as c
Проблема в том что запрос оборачивается в SELECT c.count FROM () что работает существенно дольше на относительно небольшой базе в 200к записей по сравнению с запросом такого вида
SELECT COUNT(distinct p.id) FROM `product` ...
Можно ли решить вопрос без костылей так что бы count не оборачивал запрос при использовании ActiveDataProvider?

Wizard
Сообщения: 162
Зарегистрирован: 2018.02.05, 13:41
Контактная информация:

Re: SELECT c.count FROM ( ... ) as с - есл и в запросе есть group by

Сообщение Wizard » 2018.07.05, 13:12

на данный момент решил так

переопределил метод prepareTotalCount в ActiveDataProvider

Код: Выделить всё

class ActiveDataProvider extends \yii\data\ActiveDataProvider
{
    public $queryCount;

    protected function prepareTotalCount()
    {
        if (!$this->query instanceof QueryInterface) {
            throw new InvalidConfigException('The "query" property must be an instance of a class that implements the QueryInterface e.g. yii\db\Query or its subclasses.');
        }

        $query = clone $this->query;

        if( is_callable($this->queryCount) ) {
            return call_user_func($this->queryCount, $query);
        }
        
        return (int) $query->limit(-1)->offset(-1)->orderBy([])->count('*', $this->db);
    }
}
при создании ActiveDataProvider

Код: Выделить всё

        return new \storeBase\providers\ActiveDataProvider([
            'query' => $query,
            'queryCount' => function($query) {
                return (int) $query
                    ->limit(-1)
                    ->offset(-1)
                    ->orderBy([])
                    ->groupBy([])
                    ->count('distinct p.id');
            },
            'pagination' => [
                'pageSize' => 24,
            ],
            'sort' => [
            	...
на выходе получил нормальный запрос

andku83
Сообщения: 988
Зарегистрирован: 2016.07.01, 10:24
Откуда: Харьков

Re: SELECT c.count FROM ( ... ) as с - есл и в запросе есть group by

Сообщение andku83 » 2018.07.05, 14:02

В вашем случае не нужно ничего переопределять, можете просто получить удобным способом ваше значение и передать его в:

Код: Выделить всё

        $dataProvider->totalCount = {ваше значение};

Wizard
Сообщения: 162
Зарегистрирован: 2018.02.05, 13:41
Контактная информация:

Re: SELECT c.count FROM ( ... ) as с - есл и в запросе есть group by

Сообщение Wizard » 2018.07.05, 14:53

andku83 писал(а):
2018.07.05, 14:02
В вашем случае не нужно ничего переопределять, можете просто получить удобным способом ваше значение и передать его в:

Код: Выделить всё

        $dataProvider->totalCount = {ваше значение};
действительно, списибо

Ответить