CRUD очень медленный с условиями, есть ли другой способ быстрее?

У меня возникли проблемы с CRUd теперь, когда я заполнил базу данных. CRUD требует возрастов, чтобы показать, потому что он принимает условия из таблиц M: M.

Таблицы: Таблица USER. имеет много меток (hasMany) Таблица LABLE, имеет много пользователей (hasMany) промежуточная таблица UserLabel, имеет два hasOne

Я хочу показать всем пользователям из какого-либо ярлыка с CRUD вот так:

МОДЕЛЬ ПОЛЬЗОВАТЕЛЯ:

class Model_User extends Model_Table {
    public $table ='user';
    function init(){
        parent::init(); 
        $this->addField('fbid')->mandatory('Facebook id required');
        ...

        $this->hasOne('Application');
        $this->hasMany('UserLabel');

        $this->addExpression('ratio')->set(function($model,$select){
            return $select->expr('ROUND(([f2] / [f1]) * 100,0)')
            ->setCustom('f1',$model->getElement('sends'))
            ->setCustom('f2',$model->getElement('clicked'));
        });


        $this->addHook('beforeSave',function($m){
                    $m['updated']=$m->dsql()->expr('now()');
                });
    }

МОДЕЛЬ ЭТИКЕТКА:

class Model_Label extends Model_Table {
    public $table ='label';
    function init(){
        parent::init(); 

        $this->addField('name')->mandatory('Name required');
        $this->addFIeld('application_id')->refModel('Model_Application')->defaultValue($this->api->recall('app'))->system(true);

        $this->addField('active')->type('boolean')->defaultValue('true')->system(true);
        $this->addField('created')->type('timestamp')->defaultValue($this->dsql()->expr('now()'))->system(true);
        $this->addField('updated')->type('timestamp')->system(true);
        $this->hasMany('UserLabel');

        $m = $this->add("Model_UserLabel");
        $this->addExpression("users", $m->dsql()
                ->field($m->dsql()->expr("count(*)"), "all users")
                ->where("label_id", $this->getField("id"))
        );

МОДЕЛЬ ПОЛЬЗОВАТЕЛЬСКОЙ ЭТИКЕТКИ

class Model_UserLabel extends Model_Table {
    public $table ='userlabel';
    function init(){
        parent::init(); 

        $this->hasOne('User');
        $this->hasOne('Label'); 
    }
} 

КОД ДЛЯ КРУДА

$c = $this->add('CRUD');
$c->setModel('User', array('name', 'gender','country','city'));
$c->model->addCondition('id','in',
  $this->add('Model_UserLabel')->addCondition('label_id', $_GET['l'])->dsql()->field('user_id')
);

Есть ли лучший способ сделать это?

пс. Я протестировал это решение, оно намного быстрее, но все еще очень медленное - около 5000 пользователей:

//get all users
$records = $this->api->db->dsql()->option('distinct')->table('user')->join('userlabel.user_id')->field('user.id')->where('userlabel.label_id',$_GET['l'])->do_getAll();
foreach($records as $record){
  $users .= ','.$record['id'];
}
//create CRUD
$c = $this->add('CRUD');
$c->setModel('User', array('name', 'gender','country','city','sends','clicked','ratio'));
$c->model->addCondition("application_id", $this->api->recall('app'));
$c->model->addCondition('id','in',
    '('.$users.')'
);

1 ответ

Исходный код выражает больше, чем слова, поэтому лучше добавить исходный код определения модели (возможно, не полный) в свой вопрос.

Какой должна быть одна строка в вашем CRUD/Grid? Я предполагаю, что это не 1 пользователь = 1 строка, а 1 user_label должна быть одна строка в сетке. Поэтому вы должны установить модель UserLabel в качестве модели для вашей сетки.

А затем определите некоторые дополнительные поля в Model_UserLabel, соединив их непосредственно с таблицами пользователей и / или меток, например так:

class Model_UserLabel extends SQL_Model {
    function init() {
        parent::init();

        // ...

        // fields from user table
        $join_u = $this->join('user', 'user_id');
        $join_u->addField('username'); // this adds fields in current model from joined table
        $join_u->addField('email');

        // fields from label table
        $join_l = $this->join('label', 'label_id');
        $join_l->addField('name');


    }
}

Примечание: приведенный выше исходный код не проверен и приведен здесь только в качестве примера.


РЕДАКТИРОВАТЬ:

Попробуйте это решение - почти так же, как я написал ранее выше:

МОДЕЛЬ ПОЛЬЗОВАТЕЛЬСКОЙ ЭТИКЕТКИ

class Model_UserLabel extends Model_Table {
    public $table ='userlabel';
    function init(){
        parent::init(); 

        $this->hasOne('User');
        $this->hasOne('Label'); 

        // join user table and add fields to this model from joined user table
        $j = $this->join('user', 'user_id');
        $j->addField('name');
        $j->addField('gender');
        $j->addField('country');
        $j->addField('city');

    }
} 

КОД ДЛЯ КРУДА

$m = $this->add('Model_UserLabel'); // UserLabel here not User
$m->addCondition('label_id', $_GET['l']); // and then this is simple

$c = $this->add('CRUD');
$c->setModel($m, array('name', 'gender','country','city'));

Попробуйте это решение и как (почти) всегда - код не проверен.


РЕДАКТИРОВАТЬ:

Пожалуйста, попробуйте эту версию - она ​​работает быстрее? Это в основном ваш пример PS, но вы не должны извлекать все идентификаторы пользователей, присоединяться к ним, а затем создавать огромный выбор с большим количеством "в". Более быстрый результат должен быть, если вы можете сделать все с одним запросом БД без какой-либо дополнительной обработки данных.

// parameters
$app_id = $this->api->recall('app);
$label_id = $_GET['l'];

// prepare model for grid
$m = $this->add('Model_User'); // default User model
$m->_dsql()->option('distinct') // add join to userlabel table + conditions
    ->join('userlabel.user_id')
    ->where('userlabel.label_id', $label_id)
    ->where($m->getField('application_id'), $app_id);

// create CRUD and set it's model. All conditions already set on model above
$c = $this->add('CRUD');
$c->setModel($m, array('name', 'gender','country','city','sends','clicked','ratio'));

ПРИМЕЧАНИЕ: Исходный код выше, как часто - не проверено:)

Другие вопросы по тегам