我正在使用yii2数据提供程序从数据库中提取数据。原始查询如下所示
SELECT `client_money_operation`.* FROM `client_money_operation`
LEFT JOIN `user` ON `client_money_operation`.`user_id` = `user`.`id`
LEFT JOIN `client` ON `client_money_operation`.`client_id` = `client`.`id`
LEFT JOIN `client_bonus_operation` ON `client_money_operation`.`id` = `client_bonus_operation`.`money_operation_id`
WHERE (`client_money_operation`.`status`=0) AND (`client_money_operation`.`created_at` BETWEEN 1 AND 1539723600)
GROUP BY `operation_code` ORDER BY `created_at` DESC LIMIT 10
此查询需要107秒才能执行。
表client_money operations
包含132000行。我该怎么做才能优化此查询或正确设置数据库?
答案 0 :(得分:0)
尝试分页。但是,如果您必须一次显示大量记录,则可以删除尽可能多的左联接。如果确实需要显示在一次性结果集中,则可以在client_money_operation表中复制一些数据。
答案 1 :(得分:0)
SELECT mo.*
FROM `client_money_operation` AS mo
LEFT JOIN `user` AS u ON mo.`user_id` = u.`id`
LEFT JOIN `client` AS c ON mo.`client_id` = c.`id`
LEFT JOIN `client_bonus_operation` AS bo ON mo.`id` = bo.`money_operation_id`
WHERE (mo.`status`=0)
AND (mo.`created_at` BETWEEN 1 AND 1539723600)
GROUP BY `operation_code`
ORDER BY `created_at` DESC
LIMIT 10
是GROUP BY
的相当混乱的用法。首先,在SELECT
列表中有许多未聚合的列时,按一列分组是不合适的。并且created_at
中使用ORDER BY
是没有意义的,因为尚不清楚哪个日期将与每个operation_code
相关联。也许您想要MIN(created_at)
?
优化...
将对mo
和(希望)PRIMARY KEY
查找到其他表进行全面扫描。请提供EXPLAIN SELECT ...
,以便我们进行检查。
mo
上唯一有用的索引是INDEX(status, created_at)
,它可能有用也可能没有用,具体取决于该日期范围的大小。
bo
需要一些以money_operation_id
开头的索引。
operation_code
和created_at
在哪些表中?它与优化器有很大的不同。
但是有一种模式可以用来大大加快查询速度。 (我无法在不知道这些列所在的表的情况下,也无法使其工作的情况下为您提供详细信息。)
SELECT mo.*
FROM ( SELECT mo.id FROM .. WHERE .. GROUP BY .. ORDER BY .. LIMIT .. ) AS x
JOIN mo ON x.id = mo.id
ORDER BY .. -- yes, repeated
也就是说,首先(在派生表中)完成 minimum 的工作,以查找所需的10行的id,然后然后使用JOIN (s)从那里获取其他所需的列。
(如果无法使yii2生成此类代码,那么就这样了。)