【发布时间】:2015-02-19 06:25:56
【问题描述】:
很少发生的情况是一对一的情况,第二个表可以为第一个表提供数百万个结果。例如,我有一个包含数百万个“radacct”的“radcliente”表,但只需要使用最后一个帐户进行过滤。以下是更好解释的示例:
这是标准:
$criteria = new CDbCriteria();
$criteria->with = [
'acct', // slow because it will take millions of lines to have only the last
];
$criteria->together = true;
$clientes = Cliente::model()->findAll($criteria);
这是 Yii 生成的查询(非常慢,超过 40 秒,它返回数百万行以在 AR 中只使用一个):
SELECT
`t`.`id` AS `t0_c0`,
-- ...
`t`.`spc_serasa` AS `t0_c56`,
`acct`.`radacctid` AS `t1_c0`,
-- ...
`acct`.`cliente_id` AS `t1_c27`
FROM
`radcliente` `t`
LEFT OUTER JOIN `radacct` `acct` ON (`acct`.`cliente_id`=`t`.`id`)
ORDER BY
radacctid DESC
应用我的解决方案限制加入一行后(这么快!200ms-):
SELECT
`t`.`id` AS `t0_c0`,
..
`t`.`spc_serasa` AS `t0_c56`,
`acct`.`radacctid` AS `t1_c0`,
-- ...
`acct`.`cliente_id` AS `t1_c27`
FROM
`radcliente` `t`
LEFT OUTER JOIN `radacct` `acct` ON (
acct.radacctid = (
SELECT radacctid
FROM `radacct` `acct`
WHERE (acct.cliente_id = t.id)
ORDER BY radacctid DESC
LIMIT 1
)
)
这是 CActiveDataProvider 生成的总项目数查询,我的解决方案是限制连接到一个(慢,10 秒计数):
SELECT
COUNT(*)
FROM (
SELECT
`t`.`id` AS `t0_c0`,
-- ...
`t`.`spc_serasa` AS `t0_c56`,
`endereco_instalacao`.`id` AS `t1_c0`,
`telefones`.`id` AS `t2_c0`,
`telefones`.`telefone` AS `t2_c3`,
`emails`.`id` AS `t3_c0`,
`emails`.`email` AS `t3_c3`,
`metodo_cobranca`.`id` AS `t4_c0`,
`acct`.`radacctid` AS `t5_c0`,
`acct`.`framedipaddress` AS `t5_c22`
FROM
`radcliente` `t`
LEFT OUTER JOIN `radcliente_endereco_instalacao` `endereco_instalacao` ON (
endereco_instalacao.id = (
SELECT id
FROM `radcliente_endereco_instalacao` `endereco_instalacao`
WHERE (
endereco_instalacao.cliente_id = t.id
)
LIMIT 1
)
)
LEFT OUTER JOIN `radcliente_telefone` `telefones` ON (`telefones`.`cliente_id`=`t`.`id`)
LEFT OUTER JOIN `radcliente_email` `emails` ON (`emails`.`cliente_id`=`t`.`id`)
LEFT OUTER JOIN `radmetodo_cobranca` `metodo_cobranca` ON (
metodo_cobranca.id = (
SELECT id
FROM `radmetodo_cobranca` `metodo_cobranca`
WHERE (metodo_cobranca.cliente_id = t.id)
AND (metodo_cobranca.arquivo = 'nao')
ORDER BY metodo_cobranca.id DESC
LIMIT 1
)
)
LEFT OUTER JOIN `radacct` `acct` ON (
acct.radacctid = (
SELECT radacctid
FROM `radacct` `acct`
WHERE (acct.cliente_id = t.id)
ORDER BY radacctid DESC
LIMIT 1
)
)
GROUP BY t.id
) sq
但问题是CActiveDataProvider生成的计数(返回结果大约需要10秒)有办法优化而不必丢失关系(因为我以后需要按关系过滤)?
更新
感谢您的回复。我一直在做一些测试,并注意到在所有情况下都很慢,表'radacct'因其大小而加剧了问题,因此不应限制子查询中的 1。按照模型和链接访问系统,如果需要认证是:
访问:
http://177.86.111.30/dev2/teste
用户名:帮助
密码:1
要下载 radcliente 和 radacct 的模型和架构:http://177.86.111.30/files.zip
【问题讨论】:
-
请列出问题表中定义了哪些索引。
-
1.考虑将问题减少到证明该概念所需的最低限度。 2. 然后提供适当的 DDL(和/或 sqlfiddle)。 3.然后提供一个想要的结果集,对应2中提供的数据集。
-
问题与'radacct'表中的数百万行有关,无法放在SQLFiddle上,我将打开我的服务器并在页面中传递一个链接进行测试。谢谢。
-
可能你需要跳过 Active Record 并使用其他 Yii DB API 来处理你的查询yiiframework.com/forum/index.php/topic/…
-
只加载了10条记录,这个数是统计要在CGridView中使用的总数。
标签: mysql sql database performance yii