简体   繁体   English

性能提升 - Yii2 急切加载

[英]Performance improvement - Yii2 Eager loading

We have a table called content and size of table is over 5Gb.我们有一个名为 content 的表,表的大小超过 5Gb。 Our Yii2 backend application has a section to view those content and there are few filters available to filter out contents.我们的 Yii2 后端应用程序有一个部分可以查看这些内容,并且几乎没有过滤器可用于过滤掉内容。 I need to filter contents which are assigned or not assigned to categories.我需要过滤已分配或未分配给类别的内容。

Relations关系

A Content can be shared within many categories.内容可以在许多类别中共享。 So there is a one to many relationship between Content and Category tables.因此 Content 和 Category 表之间存在一对多的关系。

Mapping table is content_cat_xref.映射表是 content_cat_xref。

Models are as follows.型号如下。

Content model内容 model

 /**
 * @return \yii\db\ActiveQuery
 */
public function getContentCatXrefs()
{
    return $this->hasMany(ContentCatXref::className(), ['content_id' => 'id']);
}

Content_cat_xref model Content_cat_xref model

/**
 * @return \yii\db\ActiveQuery
 */
public function getCategory()
{
    return $this->hasOne(Category::className(), ['id' => 'category_id']);
}

/**
 * @return \yii\db\ActiveQuery
 */
public function getContent()
{
    return $this->hasOne(Content::className(), ['id' => 'content_id']);
}

Controller Controller

 public function actionIndex()
{
    $searchModel = new \common\models\ContentSearch();
    $dataProvider = $searchModel->searchMedia(Yii::$app->request->queryParams);
    return $this->render('index', [
        'searchModel' => $searchModel,
        'dataProvider' => $dataProvider
    ]); 
}

ContentSearch Model内容搜索 Model

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 \yii\db\Expression('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 \yii\db\Expression('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;
}

I have few questions我有几个问题

  1. What should be the correct and efficient way to join two tables( content and content_cat_xref) to retrieve data.连接两个表(content 和 content_cat_xref)以检索数据的正确有效方法应该是什么。 I need to filter contents which are assigned or not assigned to categories.我需要过滤已分配或未分配给类别的内容。 So, I use this filter for that.所以,我为此使用了这个过滤器。

     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 \yii\db\Expression('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 \yii\db\Expression('null')]); }]); }
  2. I use eager loading to improve performance here.我在这里使用急切加载来提高性能。 But It gives duplicate records when joining these two tables.但是在加入这两个表时它会给出重复的记录。 After I use distinct then it reduce the performance.在我使用 distinct 之后,它会降低性能。 What should be the correct way to do this Yii2?执行此 Yii2 的正确方法应该是什么?

  3. Is there are way to pass params to relation functions when constructing query in content search model?在内容搜索 model 中构造查询时,有没有办法将参数传递给关系函数?

  4. If we order content by id descending, again reduce the performance.如果我们按 id 降序排列内容,再次降低性能。

It is highly appreciated if there is anyone who can provide guidance on this.如果有人可以提供这方面的指导,我们将不胜感激。

  1. If the goal is to filter contents which are assigned or not assigned to categories, I will suggest to maintain a flag in "content" table.如果目标是过滤分配或未分配给类别的内容,我建议在“内容”表中维护一个标志。 Or you can add index in existing tables to improve the performance on join and conditions, but it will be always slower than the condition on a flag field on a single table.或者您可以在现有表中添加索引以提高连接和条件的性能,但它总是比单个表上的标志字段上的条件慢。 You can use "explain" statement to get the information about the indexes used nd also it will be helpful to you to add new index您可以使用“解释”语句来获取有关使用的索引的信息,这也将有助于您添加新索引
  2. Issue is not with Yii2 but will the records maintain in the tables.问题不在于 Yii2,而是记录会保留在表中。 If you have multiple entries in "content_cat_xref" table for a respective row from "content" table, then your join will return multiple records, where records from "content" table will be same for respective row but records from "content_cat_xref" will be different for each row.如果“content”表中的相应行在“content_cat_xref”表中有多个条目,那么您的联接将返回多条记录,其中“content”表中的记录对于相应的行将相同,但“content_cat_xref”中的记录将不同对于每一行。 Solution is to use subquery (will effect the performance) or maintain the flag as explained in point 1解决方案是使用子查询(会影响性能)或维护标志,如第 1 点所述
  3. In Yii2, relations are formed based on method return in model class.在 Yii2 中,基于 model class 中的方法返回形成关系。 You can write conditions in that methods.您可以在该方法中编写条件。 eg:例如:
 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]); }
  1. Add indexes in your table在表中添加索引

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM