如何在Yii 1.1中执行FROM子句中的子查询?

41zrol4v  于 2022-11-09  发布在  其他
关注(0)|答案(1)|浏览(174)

我有一个由Yii生成的相当大且复杂的查询。为了生成这个查询,我们使用CDbCritera::with来急切地加载多个相关的模型,并且我们使用多个作用域来限制返回的记录。生成的查询大约有700行长,但看起来像这样:

SELECT `t`.`column1` as `t0_c0`,
       `t`.`column2` as `t0_c1`,
       `related1`.`column1` as `t1_c0`,
       ...
       `related9`.`column5` as `t9_c4`
FROM `model` `t`
    LEFT OUTER JOIN `other_model` `related1`
                 ON ( `t`.`other_model_id` = `related1`.`id` )
    ...
    LEFT OUTER JOIN `more_models` `related9`
                 ON ( `t`.`more_models_id` = `related9`.`id` )
WHERE
    ...big long WHERE clause using all of related1 - related9 to filter model...
LIMIT 10

我们的数据库有相当多的数据,但也不是不必要的。在本例中,model表有大约126000行,每个“相关”模型都是BELONGS_TO关系,并且t.XXX_id上有一个索引,因此连接相当简单。问题是WHERE子句的复杂性。处理多个COALESCEIFCASE子句。在126000行上执行过滤器需要2.6秒--比我们希望的API端点要长得多。
WHERE子句分为多个不同的部分,如下所示:

WHERE
    ( ... part 1 ... )
    AND
    ( ... part 2 ... )
    AND
    ( ... part 3 ... )

其中每个部件对应于范围之一,并且每个部件使用一个或多个相关模型
其中一个作用域只对***单个***相关模型进行过滤,并在此过程中将表从126000行过滤到大约2000行。我通过实验(在MySQL Workbench中)发现,只需执行以下操作,就可以将查询时间从2.6秒缩短到0.2秒:

SELECT `t`.`column1` as `t0_c0`,
       `t`.`column2` as `t0_c1`,
       `related1`.`column1` as `t1_c0`,
       ...
       `related9`.`column5` as `t9_c4`
FROM
    (
        SELECT `model`.*
        FROM `model`
        LEFT OUTER JOIN `other_model`
                     ON ( `t`.`other_model_id` = `other_model`.`id` )
        WHERE
            ( ... part 1 ... )
    ) `t`
    LEFT OUTER JOIN `other_model` `related1`
                 ON ( `t`.`other_model_id` = `related1`.`id` )
    ...
    LEFT OUTER JOIN `more_models` `related9`
                 ON ( `t`.`more_models_id` = `related9`.`id` )
WHERE
    ( ... part 2 ... )
    AND
    ( ... part 3 ... )
LIMIT 10

通过这种方式,我们不必对原始model表的所有126000行执行非常复杂的WHERE子句,而是执行简单得多的(和索引增强的)WHERE子句,然后只对2000个相关行执行复杂的WHERE子句。但是在FROM子句中使用子查询会使它的运行速度提高13倍。
我知道我可以使用CDbCommand来构建一个查询,甚至传入原始SQL,但是我得到的是一个“行”数组--它们不会被Yii理解,也不会被正确地转换成正确的模型。
Yii的ActiveRecord系统是否有办法说出类似下面的话?

$criteria = new CDbCriteria;
$criteria->scopes = array("part1");
$subQuery = Model::model()->buildQuery($criteria);

$criteria = new CDbCriteria;
$criteria->scopes = array("part2", "part3");
$fullQuery = $subQuery->findAll($criteria);
bgibtngc

bgibtngc1#

虽然不是一个完美的解决方案,但我确实找到了***几乎***一样好的解决方案。
1.获取要在FROM子查询中选择的ID或模型
1.使用id in (...)将WHERE附加到外部查询
如果有人感兴趣的话,我会找到我为这个问题写的代码,作为一个例子贴在答案里,但是到目前为止,这个问题得到的关注很少,一旦我找到了一个伪体面的解决方案,我就继续前进了。

相关问题