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'));
ПРИМЕЧАНИЕ: Исходный код выше, как часто - не проверено:)