Страница 1 из 1

оптимизация количества запросов ActiveRecord

Добавлено: 2018.05.30, 09:41
an.viktory@gmail.com

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

$model = Model::findOne(3);
$model->time = time();
$model->save();
получается два запроса SELECT и UPDATE
моя задача например обновить только одно поле в записи и не гонять по сети кучу данных.
как это проще и правильнее сделать при помощи ActiveRecord
так будет правильно и оптимально ?
Model::updateAll(['id' => 3], 'time' => time());

Re: оптимизация количества запросов ActiveRecord

Добавлено: 2018.05.30, 10:26
ElisDN
an.viktory@gmail.com писал(а): 2018.05.30, 09:41 моя задача например обновить только одно поле в записи и не гонять по сети кучу данных.
Кучу данных?

Re: оптимизация количества запросов ActiveRecord

Добавлено: 2018.05.30, 10:33
Alexum
an.viktory@gmail.com писал(а): 2018.05.30, 09:41 так будет правильно и оптимально ?
Model::updateAll(['id' => 3], 'time' => time());
Аргументы местами поменять.

Re: оптимизация количества запросов ActiveRecord

Добавлено: 2018.05.30, 10:47
an.viktory@gmail.com
ElisDN писал(а): 2018.05.30, 10:26
an.viktory@gmail.com писал(а): 2018.05.30, 09:41 моя задача например обновить только одно поле в записи и не гонять по сети кучу данных.
Кучу данных?
Да если я делаю foreach кешированного массива данных например 1000 записей на удаленной базе данных получается в два раза больше запросов и на дистанции в два раза больше нагрузка на базу, разве не так ?

Re: оптимизация количества запросов ActiveRecord

Добавлено: 2018.05.30, 10:51
an.viktory@gmail.com
Alexum писал(а): 2018.05.30, 10:33
an.viktory@gmail.com писал(а): 2018.05.30, 09:41 так будет правильно и оптимально ?
Model::updateAll(['id' => 3], 'time' => time());
Аргументы местами поменять.

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

Model::updateAll(['time' => time()], 'id' => 3);
т.е. это будет всего один запрос UPDATE table SET time=3642763742637 WHERE id=3; и все правильно ?

Re: оптимизация количества запросов ActiveRecord

Добавлено: 2018.05.30, 10:59
zelenin
an.viktory@gmail.com писал(а): 2018.05.30, 10:51
Alexum писал(а): 2018.05.30, 10:33
an.viktory@gmail.com писал(а): 2018.05.30, 09:41 так будет правильно и оптимально ?
Model::updateAll(['id' => 3], 'time' => time());
Аргументы местами поменять.

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

Model::updateAll(['time' => time()], 'id' => 3);
т.е. это будет всего один запрос UPDATE table SET time=3642763742637 WHERE id=3; и все правильно ?
дебаг панель что показывает?

Re: оптимизация количества запросов ActiveRecord

Добавлено: 2018.05.30, 12:21
an.viktory@gmail.com
ВАРИАНТ ПЕРВЫЙ 12 секунд 200 запросов 12 Mb памяти

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

$id_category = 3;
               $cashed_items = Synchronization::find()
                ->select('id')
                ->where(['id_category' => $id_category])
                 ->limit(100)
                ->all();
          foreach ($cashed_items as $item) {
            $item->original_date = time();
            $item->save();
 
ВАРИАНТ ВТОРОЙ 7 секунд 8 Mb 100 запросов
$id_category = 3;
$cashed_items = Synchronization::find()
->select('id,id_address, id_in_source, address_line, price,date_of_check,url,date_start,disactive')
->where(['id_category' => $id_category])
->asArray() !!!
->limit(100)
->all();

foreach ($cashed_items as $item) {
Synchronization::updateAll(['original_date' => time()],['id' => $item['id']]);
}


ИТОГО: экономия ВСЕГО в два раза;

Re: оптимизация количества запросов ActiveRecord

Добавлено: 2018.05.30, 12:35
Alexum
Вы видимо не до конца понимаете что и для чего нужно использовать.
1) ActiveRecord в виде объекта это когда нужна валидация, поведения и работа в ООП стиле. В rules модели может быть прописан валидатор проверки связанных данных. Т.е. при сохранении ваша модель может стучаться к таблице категорий и проверять, что там есть категория с id = 3.
2) при updateAll() никакой валидации не осуществляется. События beforeSave и afterSave не вызываются. Грубо говоря из модели берётся название таблицы и строится запрос update.
3) в вашем примере непонятно зачем вообще вытаскивать записи из БД, если можно сделать всего 1 запрос на их обновление.

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

Synchronization::updateAll(['original_date' => time()],['id_category' => $id_category]);

Re: оптимизация количества запросов ActiveRecord

Добавлено: 2018.05.30, 13:01
an.viktory@gmail.com
нет в все понимаю ... когда в базе данных около 100000 записей и нужно их сверить по 10 параметрам и за пару часов то тут возникает излишная нагрузка на сервер данный способ мне позволил съкономить время и ресурсы. Т.е. мне наличие всех преимуществ AR как раз и замедляло работу с базой, но писать самому ЧИСТЫЕ SQL запросы не удобно. Данное решение позволило иметь преимущевтва AR без лишних проверок экономя ресурсы.

Re: оптимизация количества запросов ActiveRecord

Добавлено: 2018.05.30, 13:04
an.viktory@gmail.com
Alexum писал(а): 2018.05.30, 12:35
3) в вашем примере непонятно зачем вообще вытаскивать записи из БД, если можно сделать всего 1 запрос на их обновление.

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

Synchronization::updateAll(['original_date' => time()],['id_category' => $id_category]);
Здесь ну указано тело foreach там куча проверок, обновления будут разные в зависимости от данных.

Re: оптимизация количества запросов ActiveRecord

Добавлено: 2018.05.30, 13:10
andku83
an.viktory@gmail.com писал(а): 2018.05.30, 13:04 Здесь ну указано тело foreach там куча проверок, обновления будут разные в зависимости от данных.
чем меньше вы расскажите подробностей, тем больше неподходящих решений вам предложат

Re: оптимизация количества запросов ActiveRecord

Добавлено: 2018.05.30, 13:17
mkramer
Если обновления разные в зависимости от данных, то по одним запросом и не получится, скорее всего. Разве что мутить уже на SQL с if-ами сложный запрос UPDATE руками.

Re: оптимизация количества запросов ActiveRecord

Добавлено: 2018.05.30, 13:32
andku83

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

INSERT INTO mytable (id, a, b, c)
VALUES (1, 'a1', 'b1', 'c1'),
...
ON DUPLICATE KEY UPDATE id=VALUES(id),
...

Re: оптимизация количества запросов ActiveRecord

Добавлено: 2018.06.13, 17:31
skynin
an.viktory@gmail.com писал(а): 2018.05.30, 13:01 когда в базе данных около 100000 записей и нужно их сверить по 10 параметрам и за пару часов
то любые ORMы будут гонять лишние данные. ActiveRecord еще няшка в сравнении с Hibernate/Doctrine
an.viktory@gmail.com писал(а): 2018.05.30, 13:01писать самому ЧИСТЫЕ SQL запросы не удобно
тогда гоняйте данные :)

писать SQL еще не самый нижний уровень.
в сценариях работы "100000 записей и нужно их сверить по 10 параметрам" чтобы не молотило часами пишутся хранимые процедуры, для элементарых действий, с которых и набирается SQL код конкретного алгоритма сверки по 10ти параметрам.
мне наличие всех преимуществ AR как раз и замедляло работу с базой
для пакетных операций над данными - преимуществ у AR перед SQL и хранимыми процедурами мне сложно придумать :)
потому что для пакетных операций над данным не нужны - поведение и работа в ООП стиле
а если нужно ООП... то думаю что-то странное в дизайне приложения.
например частая операция - "изменить цены товаров ... согласно формуле 1 если ..., формуле 2 если
стоит просто трансформироваться в отдельные запросы -
применяем формулу 1 для группы товаров если ...
применяем формулу 2 для группы товаров если ...

Ускорить же работу AR конечно можно.
Во-первых проектирвать схему БД до написания первой AR модели. проектировать с учетом тех самых выборок, сверок, пакетных операций. если надо ради этого - то и денормализовать.
А потом уж писать модели.
Во-вторых заглядывать в план запроса. т.е. читать SQL и понимать что он делает :)

а если читаете и понимаете - то может и переписать SQL для таких, тяжелых в обработке случаев?
и Yii::$app->db->createCommand может и на порядок быть эффективней во время выполнения