Sql при Model::findOne()

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
yujin1st
Сообщения: 192
Зарегистрирован: 2012.03.26, 12:03

Sql при Model::findOne()

Сообщение yujin1st »

Здравствуйте! Заметил, что при вызове Model::findOne([]) или Model::find()->one() записывается запрос "select * from my_table" без limit'a. И лишь потом в коде (\yii\db\Command::queryOne()) из запроса возвращается первая строка. Разве не получается, что база данных будет пытаться просмотреть и получиться все возможные записи, а не остановиться при первой? Можете объяснить, в чем я ошибаюсь?
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Sql при Model::findOne()

Сообщение samdark »

Так и получается... не ошибаетесь.
yujin1st
Сообщения: 192
Зарегистрирован: 2012.03.26, 12:03

Re: Sql при Model::findOne()

Сообщение yujin1st »

Александр, а этот момент специально упустили для того, чтобы была поддержка разных баз данных?
Стоит ли заморачиваться сейчас ставя вручную limit или же что-то будет меняться, например в yii\db\mysql\QueryBuilder?
Я понимаю, что при маленьком количестве записей такая оптимизация не имеет особого смысла, но при больших таблицах она же ощутима, верно?
ps: И при этом вся прелесть короткой записи Model::findOne($id) теряется при превращении в Model::find()->where['id'=>$id]->limit(1)->one();
ps2: А ведь помимо же основных запросов, есть еще has_one связи...
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Sql при Model::findOne()

Сообщение ElisDN »

Здесь же по первичному уникальному ключу ищется. СУБД это знает и дальше не идёт.
yujin1st
Сообщения: 192
Зарегистрирован: 2012.03.26, 12:03

Re: Sql при Model::findOne()

Сообщение yujin1st »

Так есть ситуации, когда не по первичному ключу ищется, а по параметрам: чтобы далеко не ходить - таблица с пользователями {id,username, password}
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Sql при Model::findOne()

Сообщение samdark »

Выборки типа ->one() без where() очень редкая штука.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Sql при Model::findOne()

Сообщение zelenin »

Sam Dark писал(а):Выборки типа ->one() без where() очень редкая штука.
да не важно.
Если дело обстоит как описывает автор, то есть запросы делаются без limit, то это очень странно и неинтуитивно.
Аватара пользователя
ifelse
Сообщения: 227
Зарегистрирован: 2013.02.05, 13:05

Re: Sql при Model::findOne()

Сообщение ifelse »

Как я понимаю предполагается, что разработчики будут использовать индексы чтобы решить проблему производительности
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Sql при Model::findOne()

Сообщение zelenin »

ifelse писал(а):Как я понимаю предполагается, что разработчики будут использовать индексы чтобы решить проблему производительности

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

select * from my_table
как тут помогут индексы?
Аватара пользователя
ifelse
Сообщения: 227
Зарегистрирован: 2013.02.05, 13:05

Re: Sql при Model::findOne()

Сообщение ifelse »

Упс, перепутал :)
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Sql при Model::findOne()

Сообщение samdark »

Как часто вам нужен один пост из таблицы без каких-либо условий?
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Sql при Model::findOne()

Сообщение zelenin »

Sam Dark писал(а):Как часто вам нужен один пост из таблицы без каких-либо условий?
а это так важно? От частоты необходимости мне одного поста зависит неочевидность решения? Если так, то ответ: довольно часто.

Думаем дальше: условие where create_time < now() сделает запрос на один пост или все-таки на все?
astronin
Сообщения: 606
Зарегистрирован: 2012.01.30, 17:46

Re: Sql при Model::findOne()

Сообщение astronin »

и в правду странно, а почему нельзя во фреймворке добавить limit(1), чтоб не переживать что, казалось бы простой запрос может "завистнуть" ?
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Sql при Model::findOne()

Сообщение samdark »

Это важно потому как если вы выбираете один пост, в условии уже будет where id = x или что-то подобное. Если там подобного условия нет, скорее всего имеется ошибка в логике, которую лучше заметить сразу обратив внимание на тормоза, чем потом вылавливать долгим и нудным дебагом.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Sql при Model::findOne()

Сообщение zelenin »

Sam Dark писал(а):Это важно потому как если вы выбираете один пост, в условии уже будет where id = x или что-то подобное.
что-то подобное я уже написал в предыдущем комменте. Любой where кроме primary key вернет больше одной записи.
Sam Dark писал(а):Если там подобного условия нет, скорее всего имеется ошибка в логике, которую лучше заметить сразу
автор поста заметил ошибку в логике :-)

Я не понимаю, зачем вы оправдываете баг в функции? Либо для этого должна быть объективная причина, либо это баг в коде. Объективной причины вы не привели.

Я часто использую Model::find()->where('name = value')->one() для проверки наличия (или отсутствия) хотя бы одной записи с данным name, но даже не подозревал что таким запросом выбирал ВСЕ записи (если конечно автор поста прав - я не проверял). Где тут ошибка логики?
yujin1st
Сообщения: 192
Зарегистрирован: 2012.03.26, 12:03

Re: Sql при Model::findOne()

Сообщение yujin1st »

А при чем здесь наличие или отсутствие условий? Мы же начали говорить о получении именно одной записи и оптимизации этого запроса.
Не важно по первичному ключу, по другому ли условию, или же получение связной модели...

Если говорить об страховке на поиск ошибок, на случай если в запросе не будет условий - в каких ситуациях это может быть?
Наличие тормозов не обязательно, даже при наличии ошибки. При этом если знаем, что в базе много данных - то выдергивать все подряд для полной обработки без итераторов и/или лимита - чистое самоубийство. Если нужно всего несколько строк - то лимит и так проставим.
То есть остаются ситуации, где нужно выбрать одну запись:
- Если какая-то переменная в условие принимает не то значение - отсутствие лимита здесь не спасет - будет просто выбрано ненужное множество записей - о чем сразу и увидим.
- И если пишем метод, где условия проставляются в зависимости от ситуаций - здесь и так ошибок может быть много с самими условиями.
Но проставив лимит вручную (зная что автоматом его фреймворк не поставит) - да будет тяжко, не спорю.

Еще остаются выборки количества записей.. Здесь да - ошибки логики трудно отлавливать, но здесь и лимиты не нужны.

И сейчас, получается, при текущей ситуации, даже при правильном условии - база в любом случае будет выдергивать все что может попадать под условия - то есть затормаживается даже если правильно работает.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Sql при Model::findOne()

Сообщение samdark »

zelenin
Если мы хотим одну запись, а условия формируем такое, что выборка даёт больше, нет ли тут логической ошибки программиста?
Я часто использую Model::find()->where('name = value')->one() для проверки наличия (или отсутствия) хотя бы одной записи с данным name, но даже не подозревал что таким запросом выбирал ВСЕ записи (если конечно автор поста прав - я не проверял). Где тут ошибка логики?
Ошибка тут в том, что вам нужно проверить существование. Для этого в API есть http://www.yiiframework.com/doc-2.0/yii ... s()-detail который выбирает соответствующим оптимальным запросом только результат, а не данные, которые в данном случае вам совершенно не нужны.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Sql при Model::findOne()

Сообщение samdark »

yujin1st
Одна «первая попавшаяся из выбранных» запись нужна настолько редко, что если это случилось, скорее всего тут ошибка программиста, чем она действительно нужна.
- Если какая-то переменная в условие принимает не то значение - отсутствие лимита здесь не спасет - будет просто выбрано ненужное множество записей - о чем сразу и увидим.
А почему она принимает не то значение? Не лучше ли исправить логику формирования этого значения, а не пытаться облегчить последствия оставляя логику неверной?
И сейчас, получается, при текущей ситуации, даже при правильном условии - база в любом случае будет выдергивать все что может попадать под условия - то есть затормаживается даже если правильно работает.
Нет: https://stackoverflow.com/questions/384 ... ique-field
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Sql при Model::findOne()

Сообщение zelenin »

Sam Dark писал(а):zelenin
Если мы хотим одну запись, а условия формируем такое, что выборка даёт больше, нет ли тут логической ошибки программиста?
Что за прием дискуссии? Странно, что вы не пытаетесь вникнуть, ища логическую ошибку в ЧАСТНОМ примере.
one() означает, что я хочу выбрать ОДНУ запись, а не ВСЕ, с последующей фильтрацией.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Sql при Model::findOne()

Сообщение zelenin »

Sam Dark писал(а):yujin1st
Одна «первая попавшаяся из выбранных» запись нужна настолько редко, что если это случилось, скорее всего тут ошибка программиста, чем она действительно нужна.
мне нужна в виджете одна запись не старее пяти дней.
->where('time > ' . (time() - 5*60*60*24))->one()

Логическая ошибка? Или может оно мне не нужно? Так продакт-менеджеру и скажу: Yii core developer считает, что тебе это не нужно.
Ответить