我们有一个名为content的表,表的大小超过5Gb。我们的Yii2后端应用程序有一个查看这些内容的部分,并且很少有过滤器可以过滤掉内容。我需要过滤被分配或未分配到类别的内容。
A内容可以在多个类别中共享。因此,在Content表和Category表之间存在一对多的关系。
映射表为content_cat_xref。
模型如下:
内容模型
/**
* @return yiidbActiveQuery
*/
public function getContentCatXrefs()
{
return $this->hasMany(ContentCatXref::className(), ['content_id' => 'id']);
}
<<p>Content_cat_xref模型/strong>/**
* @return yiidbActiveQuery
*/
public function getCategory()
{
return $this->hasOne(Category::className(), ['id' => 'category_id']);
}
/**
* @return yiidbActiveQuery
*/
public function getContent()
{
return $this->hasOne(Content::className(), ['id' => 'content_id']);
}
控制器
public function actionIndex()
{
$searchModel = new commonmodelsContentSearch();
$dataProvider = $searchModel->searchMedia(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider
]);
}
<<p>ContentSearch模型/strong>public function searchMedia($params)
{
$query = Content::find()->where(['file_type_id'=>[1,2,3,4,5,6,8,11]]);
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$this->load($params);
if (!$this->validate()) {
return $dataProvider;
}
//Conditionally add filters
if(isset($this->is_category_available) && $this->is_category_available === 'yes'){
$query = $query->joinWith(['contentCatXrefs' => function($queryw){
$queryw->andWhere(['is not', 'content_cat_xref.category_id', new yiidbExpression('null')]);
}]);
}else if(isset($this->is_category_available) && $this->is_category_available === 'no'){
$query = $query->joinWith(['contentCatXrefs' => function($queryw){
$queryw->andWhere(['is', 'content_cat_xref.category_id', new yiidbExpression('null')]);
}]);
}
if(!is_null($this->file_name) && !empty($this->file_name)) {
$query->andWhere("MATCH (file_name) AGAINST ("".$this->file_name."" IN NATURAL LANGUAGE MODE)");
}
if(!is_null($this->file_path) && !empty($this->file_path)) {
$query->andWhere("MATCH (file_path) AGAINST ("".$this->file_path."" IN NATURAL LANGUAGE MODE)");
}
$query->andFilterWhere(['type_code'=>$this->type_code]);
$query->andFilterWhere(['file_type_id'=>$this->file_type_id]);
$query->andFilterWhere(['content.active_status'=>$this->active_status]);
$query->andFilterWhere(['content.content_status'=>$this->content_status]);
if(is_null($this->file_name)) {
$query->orderBy("id desc");
}
return $dataProvider;
}
我有几个问题
连接两个表(content和content_cat_xref)来检索数据的正确和有效的方法应该是什么?我需要过滤分配或不分配给类别的内容。因此,我使用这个过滤器
if(isset($this->is_category_available) && $this->is_category_available === 'yes'){ $query = $query->joinWith(['contentCatXrefs' => function($queryw){ $queryw->andWhere(['is not', 'content_cat_xref.category_id', new yiidbExpression('null')]); }]); }else if(isset($this->is_category_available) && $this->is_category_available === 'no'){ $query = $query->joinWith(['contentCatXrefs' => function($queryw){ $queryw->andWhere(['is', 'content_cat_xref.category_id', new yiidbExpression('null')]); }]); }
我在这里使用急切加载来提高性能。但是当连接这两个表时,它会给出重复的记录。在我使用distinct之后,它会降低性能。正确的做法应该是什么?
在内容搜索模型中构建查询时,是否有方法将参数传递给关系函数?
如果我们按id降序排序内容,再次降低性能。
如果有人能提供指导,我将不胜感激。
- 如果目标是过滤分配或未分配到类别的内容,我建议在"content"中保留一个标志;表格或者,您可以在现有表中添加索引,以提高连接和条件的性能,但它总是比单个表上标记字段上的条件慢。你可以用&;explain&;语句,以获取所使用索引的信息,并且它将有助于您添加新索引 。
- 问题不在于Yii2,而是记录是否保留在表中。如果在"content_cat_xref"中有多个条目表中从"内容"表,那么您的联接将返回多个记录,其中记录来自"content"表将是相同的各自的行,但记录从"content_cat_xref"每一行都是不同的。解决方案是使用子查询(将影响性能)或维护第1点 中解释的标志。
- 在Yii2中,根据模型类中的方法返回形成关系。你可以在这些方法中写条件。例如:
if($this->is_category_available == 'yes') { return $this->hasMany(ContentCatXref::className(), ['content_id' => 'id']) ->andOnCondition(['a_type' => 1]); } else { return $this->hasMany(ContentCatXref::className(), ['content_id' => 'id']) ->andOnCondition(['a_type' => 0]); }
- 添加索引