mysql慢选择查询,尝试了我知道的每一个优化技巧!
Posted
技术标签:
【中文标题】mysql慢选择查询,尝试了我知道的每一个优化技巧!【英文标题】:mysql slow select query, tried every optimization trick I know! 【发布时间】:2011-04-19 21:09:25 【问题描述】:我有以下疑问:
SELECT
`date`,
al.cost,
SUM(l.bnd) AS bnd,
l.type,
count(*) AS amount
FROM alogs AS al
INNER JOIN logs AS l ON al.logid = l.id
WHERE
aid = 0 AND
l.`date` >= '2010-01-17' AND
l.`date` <= '2011-04-19'
GROUP BY l.`date`, l.type
日志计数 500 万行 alogs 统计了 430 万行 执行时间约为 90 秒。
我有: logs.id 上的主键(auto inc) logs.date 上的索引 (BTREE) alogs.logid 上的索引 (BTREE) alogs.aid 上的索引 (BTREE)
我试过了: - logs.type 上的索引(BTREE),但这并没有改善任何东西(我认为因为类型只能是两件事) - logs.date 和 logs.type 的覆盖索引 - 每月在内部对日志表进行分区,但使用上面使用的时间跨度(覆盖所有分区)它甚至会变得更慢,因为有超过 2k 个不同的 id,所以无法根据帮助进行分区 - 从查询中剥离功能,直到可以快速查看问题所在。 我只需要删除 GROUP 子句(以及 SUM() 和 count(*) 函数即可获得正确的结果),这样执行时间就达到了亚秒级。 - 删除内存中的group子句和group,但是超过300万行的结果太多了,甚至需要更长的时间。
还有其他我可以做但我不知道的事情吗?如果是这样,我很想听听!
谢谢,
王者荣耀
编辑 (2011-04-22 11:30) 这是 EXPLAIN EXTENDED 结果
id| select_type| table| type | possible_keys| key | key_len| ref | rows | Extra
1 | SIMPLE | al | ref | logid,aid | adid | 4 | const | 3010624| Using temporary; Using filesort
1 | SIMPLE | l | eq_ref| PRIMARY,date | PRIMARY| 4 | al.logid| 1 | Using where
【问题讨论】:
选择了多少行? 哦,这真的取决于援助是什么,但在这种情况下,查询返回 168 行。 (如果没有 group 条款,这是 3-4mil) 您没有发布EXPLAIN
或EXPLAIN EXTENDED
的结果。你试过了吗?
编辑了帖子,你去吧。
【参考方案1】:
如果您的日期范围是日志表中的一小组行,您希望它使用该索引。你说你在logs.date上创建了一个索引,但是你需要一个在(logs.date,logs.id)上的复合索引,所以mysql不必从磁盘读取行来获取id来加入alogs表.您需要一个关于 alogs(log_id) 的索引以用于连接。
您也可以通过将 SELECT 中的列也放入索引中来挤出更多信息,所以
logs(date, id, bnd, type)
alogs(log_id, aid, cost)
【讨论】:
感谢您的回复。第一篇文章中的时间跨度是整个日期范围。当我尝试您建议的索引时,它变得慢了一秒。我尝试了较小的日期范围(几个月),但仍然需要 85 秒。【参考方案2】:如果aid
过滤器删除了大部分行,这样的事情会减少正在连接的数据:
SELECT
l.`date`,
sum(al.cost) as cost,
SUM(l.bnd) AS bnd,
l.type,
sum(qty) AS amount
FROM logs AS l
INNER JOIN
(
SELECT logid, sum(cost) as cost, COUNT(*) as qty
FROM alogs
WHERE aid = 0
GROUP BY logid
) al ON al.logid = l.id
GROUP BY l.`date`, l.type
如果不了解数据结构的更多信息(每个 logs
记录有很多 alogs
记录?),很难提出进一步的改进建议。在连接和GROUP BY
子句之前计算数据可以通过减少需要处理的总行数来大大加快执行速度。由于没有分组的查询返回的速度非常快,进一步的索引和调整不太可能提高执行速度。
【讨论】:
非常好,这将时间缩短了一半。但是,当我在 WHERE 子句中添加日期范围时,它变得和以前一样慢。一条日志记录可以有 1、2、3 或 4 条日志记录。以上是关于mysql慢选择查询,尝试了我知道的每一个优化技巧!的主要内容,如果未能解决你的问题,请参考以下文章