Yii2 - 替换beforeFind以优化MySql中的嵌套视图

时间:2016-05-23 17:07:21

标签: yii2

Yii1曾经有过beforeFind方法,您可以在其中修改查询或其他任何您想要做的事情。

在Yii2中,建议的替代方法是使用modelQuery解决方案,例如

class MyModel extends \yii\db\ActiveRecord
{

  public static function find()
  {
      return new MyModelQuery(get_called_class());
  }
/* ... */
}

 class MyModelQuery extends \yii\db\ActiveQuery
 {
   public function init( )
   {
     /** do something here **/
   }
 }

但是如何在MyModelQuery中传递或引用MyModel? 例如: -

class MyModelQuery extends \yii\db\ActiveQuery
{
   public function init( )
   {
     $sql = "SET @variable = {$MyModel->variable1}";
   }
 }

修改

为了完整起见,我在未来添加了一个帮助他人的用例。

我已经在MySql下运行了嵌套视图,并且运行得非常糟糕。

在我的情况下,我有订单,订单商品和订单商品费用表,每个一对多到下一个,我想总结订单总数。我有嵌套视图,每个级别一个总和到上面的级别,但是在订单项和订单项费用级别MySql首先对整个表进行分组(我不能使用algorithm = merge,因为我有一个GROUP BY)

我正在实施Pushdown方法,您可以在其中定义要在子视图中使用的SQL变量,以缩小搜索范围,如下所示:http://code.openark.org/blog/mysql/views-better-performance-with-condition-pushdown 而且在这里 https://www.percona.com/blog/2010/05/19/a-workaround-for-the-performance-problems-of-temptable-views/

通过这种方式,如果我可以添加' WHERE order_id ='对于两个子视图的where子句,我将3.5秒查询减少到0.003秒查询。

因此,使用Salem的建议,我可以执行一条SQL语句' SET @ order_id = 1234'在我的查询之前,然后使用函数在订单项和订单项费用视图中选择。注意:这是特定于连接的,因此没有会​​话之间发生冲突的危险。

有点复杂但很快。

但是,看看SQL和PHP中的循环之间的性能比较可能会很有趣......

编辑2

实际上,你通常使用find()作为静态方法,所以没有办法使用$ this-> order_id,所以我把它更改为覆盖了findOne方法

public static function findOne( $orderId )
{
    if ( isset($orderId) )
    {
        $sql = "SET @orderId='{$orderId}'";
        Yii::$app->db->createCommand($sql)->execute();
    }

    return parent::findOne( $orderId );
}

我也将此视图用于其他搜索,因此在视图中我需要检查orderId是否已设置...

where  (
        CASE 
        WHEN ( NOT isnull( get_session_orderId() ) )
          THEN `order`.order_id = get_session_cartref()
          ELSE `order`.order_id LIKE '%'
          END
          )

1 个答案:

答案 0 :(得分:1)

关于如何让ActiveQuery类参与检查我的答案:

Yii2 : ActiveQuery Example and what is the reason to generate ActiveQuery class separately in Gii?

但是如果您要做的事情不需要构建命名作用域,那么您可以通过以下方式覆盖find方法:

public static function find()
{
    return parent::find()->where(['variable' => 'some value']);
}