activerecord - 如何使用 Yii 1.1 在 FROM 子句中执行子查询?
问题描述
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 子句的复杂性,拥有多个andCOALESCE
子句。对我们的 126000 行执行过滤需要 2.6 秒——比我们希望的 API 端点长得多。IF
CASE
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
这种方式不是对WHERE
原始表的所有 126000 行执行非常复杂的子句,而是对这 126000 行model
执行更简单(和索引增强)的子句,然后仅对 2000 相关行执行复杂子句。两个查询的结果是相同的,但是在子句中使用子查询会使其运行速度提高 13 倍。WHERE
WHERE
FROM
问题是,我不知道如何在 Yii 中做到这一点。我知道我可以使用它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);
解决方案
虽然不是一个完美的解决方案,但我确实找到了几乎一样好的东西。将原始查询分成两部分:
- 获取您希望在 FROM 子查询中选择的 ID 或模型
- 将 WHERE 附加到外部查询
id in (...)
如果有人有兴趣,我会寻找我为此编写的代码以作为示例发布在答案中,但到目前为止,这个问题很少受到关注,一旦我找到了一个伪体面的解决方案,我就会继续前进。
推荐阅读
- powershell - 使用 Powershell 从 Txt 文件和变量中搜索值
- azure - 我使用 Azure 搜索,而后者又使用 Lucene。有没有办法可以搜索此查询: colo?r 会导致获取“颜色”和“颜色”值?
- python - 连接到 USB 设备 python libusb 时出错
- python - django admin 的 list_editable 中外键字段的自定义查询集
- python - 对数组 2d python 中的每一行求和
- lua - IntValue 更改但未显示
- sql - 无法将函数参数解析为内部查询?
- ipu - V-IPU 软件在哪里?
- c++ - 大型项目的 C++ 结构化单元测试
- python - Boost/Python 快速入门示例不构建 Windows 10