Новый тип связи в AR

Предварительное обсуждение найденных ошибок перед отправкой их авторам фреймворка, а также внесение новых предложений.
Ответить
Аватара пользователя
Stamm
Сообщения: 407
Зарегистрирован: 2010.03.14, 18:59
Откуда: Россия, Москва
Контактная информация:

Новый тип связи в AR

Сообщение Stamm »

Сейчас есть два метода связей в AR:
1) Запрос через join
2) Отдельные запросы для каждой модели

А возможно ли сделать ещё один вид связи? Возможно это уже реализовано в каком-нибудь экстеншене (прошу кинуть ссылку, если есть).
Суть его следующая: мы запрашиваем из первой таблицы простым запросом без join.
После получения данных выбираются из связаной таблицы через 1 запрос, вида table1_id IN (1, 2, 3) и потом присваиваются нужным элементам из первой модели.

В чём плюс данного введения:
1) мы избавляемся от join'а или кучи мелких запросов:
2) возможно прозрачно использовать nosql (mongodb, etc) с такими связями
Ekstazi
Сообщения: 1428
Зарегистрирован: 2009.08.20, 22:54
Откуда: Молдова, Бельцы
Контактная информация:

Re: Новый тип связи в AR

Сообщение Ekstazi »

В текущей версии - нет. CRelation есть, но, его так просто не перекроишь.
Аватара пользователя
Caveman
Сообщения: 152
Зарегистрирован: 2009.04.04, 20:56
Откуда: Москва
Контактная информация:

Re: Новый тип связи в AR

Сообщение Caveman »

Stamm писал(а):Сейчас есть два метода связей в AR:
1) Запрос через join
2) Отдельные запросы для каждой модели

А возможно ли сделать ещё один вид связи? Возможно это уже реализовано в каком-нибудь экстеншене (прошу кинуть ссылку, если есть).
Суть его следующая: мы запрашиваем из первой таблицы простым запросом без join.
После получения данных выбираются из связаной таблицы через 1 запрос, вида table1_id IN (1, 2, 3) и потом присваиваются нужным элементам из первой модели.

В чём плюс данного введения:
1) мы избавляемся от join'а или кучи мелких запросов:
2) возможно прозрачно использовать nosql (mongodb, etc) с такими связями
Это не отдельный вид связи скорее всего, а просто одна из разновидностей имеющихся. Ведь выборка из промежуточной таблицы все равно будет одной из обычных - has_one, has_many, many-many или stat.

В принципе, даже сейчас можно ПОЧТИ реализовать эту задачу. Для полной реализации мне пришлось влезть во фреймворк (очень зыбкий хак...):
class CJoinElement
...

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

public function getTableNameWithAlias()
    {
        // Hack for use custom join
        if(!empty($this->relation) && !empty($this->relation->joinType) && strpos($this->relation->joinType, $this->tableAlias) > -1)
            return ''; 
...

При этом суррогатная связь выглядит примерно так:

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

'lastStatusLog' => array(
                self::HAS_ONE,
                'OrderLog',
                'order_id',
                'joinType' => '
LEFT OUTER JOIN (
    SELECT * FROM (SELECT * FROM `orderlog` WHERE `object` = '.OrderLog::OBJECT_STATUS.' ORDER BY `id` DESC) `ol` GROUP BY `order_id`
) `lastStatusLog`', // <--- ВАЖНО , псевдоним промежуточной таблицы должен быть таким же, как и название связи (для нормальной работы хака) 
                'together' => true
            ) 
Пока все работает, но это все же внесение изменений в код фреймворка...
TM123
Сообщения: 608
Зарегистрирован: 2011.06.09, 11:18

Re: Новый тип связи в AR

Сообщение TM123 »

Совершенно неправильный метод.

1. Использование join работает очень быстро, поэтому для приложений требующих скорости следует использовать его.
2. Запрос по одному позволяет во первых сэкономить память на не хранении лишних данных, во вторых, когда в join таблицах объем данных очень большой, позволяет ускорить работу, потому что подгрузка будет только необходимых данных.

Соответственно первый метод позволяет писать быстрые приложения, второй экономить память. То что вы предлагаете - нечто среднее которое будет работать так же медленно как метод 2 и жрать столько же памяти как метод 1. Если вы использовали метод 2 и вам потребовались данные, поверьте быстрее будет переспросить полностью данные по методу 1, чем вычислить набор необходимых записей, потом их получить, а потом разложить их тормознутым интерпретатором байткода. И очень важно что код будет на столько прост, что в нем просто негде будет приютиться ошибке. Интерпретатор байткода PHP по сравнению с SQL является тормознутым!!!

Предложенный вами метод имеет смысл только для оооооооооооочень медленных каналов связи между БД и App, когда просто проталкивание нового набора данных будет слишком медленный и как следствие стоит сэкономить время на загрузке оригинального набора данных. Тоже самое относится если канал между БД и App платный или приходится платить за каждый запрос к БД. Мне кажется что такие варианты скорее экзотика.

Что касается mongoDB, думаю не стоит пытаться водрузить AR заточенный на реляционные модели пытаться водрузить документориентированные БД.

С полгода назад у меня была похожая идея, но потом вникнув в фреймворк больше я пришел к выводу что идея глупая, но я готов предметно пообсуждать ее, может я зря ее отбросил.
Аватара пользователя
Caveman
Сообщения: 152
Зарегистрирован: 2009.04.04, 20:56
Откуда: Москва
Контактная информация:

Re: Новый тип связи в AR

Сообщение Caveman »

TM123 писал(а):Совершенно неправильный метод.
Понятное дело, что это нехороший вариант и надо думать, когда его применять.
Для моих целей это пока идеальный вариант. Возможно придется в дальнейшем пересмотреть.
Аватара пользователя
andy_s
Сообщения: 127
Зарегистрирован: 2012.01.22, 13:15

Re: Новый тип связи в AR

Сообщение andy_s »

Возможно, я не понял вопроса, но Yii ActiveRecord именно так и делает (использует два запроса, один из которых "IN"), когда извлекаются связанные данные, а для основных установлен LIMIT: http://www.yiiframework.com/doc/guide/1 ... .arr#sec-8
По умолчанию Yii использует "жадную" загрузку, то есть генерирует один SQL запрос, кроме того случая, когда к главной модели применяется LIMIT. Если выставить опцию together в описании связи в true, то мы получим единственный SQL запрос даже если используется LIMIT. Если использовать false, то выборка из некоторых таблиц будет производиться отдельными запросами. К примеру, для того, чтобы использовать отдельные SQL запросы для выборки последних записей и комментариев к ним, связь comments модели Post следует описать следующим образом:
Когда я выводил с помощью CGridView список каталогов вместе со списком подкаталогов, в логе можно было наблюдать два запроса: первый извлекал сами каталоги, а второй генерировал большой IN из id каталогов (связь HAS_MANY).
TM123
Сообщения: 608
Зарегистрирован: 2011.06.09, 11:18

Re: Новый тип связи в AR

Сообщение TM123 »

Если посмотреть на логи то есть только 2 типа загрузки
1. Жадная, т.е. со всеми join связями которые заданы для жадной загрузки
2. Грузится только главная таблица, а все остальные данные по связям поштучно по мере поступления запросов на них.
Аватара пользователя
Stamm
Сообщения: 407
Зарегистрирован: 2010.03.14, 18:59
Откуда: Россия, Москва
Контактная информация:

Re: Новый тип связи в AR

Сообщение Stamm »

Я не предлагаю использовать повсеместно и только в MySQL, а только как одну из опций, которая некоторым была бы полезна, особенно в тренде роста популярности нереляционных баз. Я эту тему больше создал для обсуждения и возможно для включения в следующий релиз yii2. Я думаю, что noSQL в нём будет из коробки. Тогда можно было бы довольно легко и прозрачно использовать AR и переключить на использование noSql решения вместо реляционной и подставить эту опцию.
TM123
Сообщения: 608
Зарегистрирован: 2011.06.09, 11:18

Re: Новый тип связи в AR

Сообщение TM123 »

Мне кажется что для nonSQL баз надо делать свой механизм. Входящая точка может быть одна CModel, но подключаться должны свои специализированные классы, а не просто класс который умеет работать с соответствующим диалектом SQL для конкретной БД, как это сделано сейчас.

Я не большой знаток документ ориентированных баз, но из того немногого что знаю мне кажется что надо делать так.
Аватара пользователя
radamir
Сообщения: 142
Зарегистрирован: 2009.08.10, 08:02
Откуда: Новосибирск

Re: Новый тип связи в AR

Сообщение radamir »

Можно подсмотреть тут http://www.yiiframework.com/extension/directmongosuite.
Ответить