mysql:存储函数调用+左连接=非常非常慢
Posted
技术标签:
【中文标题】mysql:存储函数调用+左连接=非常非常慢【英文标题】:mysql: stored function call + left join = very very slow 【发布时间】:2015-05-01 06:00:55 【问题描述】:我有两张桌子:
module_339 (id,name,description,etc)
module_339_schedule(id,itemid,datestart,dateend,timestart,timeend,days,recurrent)
module_339_schedule.itemid 指向 module_339
一桌会议室
第二个保留会议日程
module_339 有 3 个项目
module_339_schedule 有 4000 多个项目 - 几乎平分在 3 个会议之间
我有一个存储函数 - “getNextDate_module_339” - 它将计算指定会议的“下一个日期”,以便能够显示它并按它排序 - 如果用户想要的话。这个存储过程将只获取指定会议的所有日程条目并循环它们,比较日期和时间。因此,它会从 module_339_schedule 中进行一次简单的读取,然后遍历项目并比较日期和时间。
问题:这个查询很慢:
SELECT
distinct(module_339.id)
,min( getNextDate_module_339(module_339.id,1,false)) AS ND
FROM
module_339
LEFT JOIN module_339_schedule on module_339.id=module_339_schedule.itemid /* standard schedule adding */
WHERE 1=1 AND module_339.is_system_preview<=0
group by
module_339.id
order by
module_339.id asc
如果我删除函数调用或 LEFT JOIN,它又会很快。 我在这里做错了什么?似乎是函数调用和左连接之间的某种“冲突”。
【问题讨论】:
【参考方案1】:我认为group by
部分可以从此查询中删除,从而使您也可以删除min
函数。另外,WHERE 1=1 AND...
没什么意义,所以我也改变了它。
试试这个:
SELECT DISTINCT module_339.id
,getNextDate_module_339(module_339.id,1,false) AS ND
FROM module_339
LEFT JOIN module_339_schedule ON module_339.id=module_339_schedule.itemid /* standard schedule adding */
WHERE module_339.is_system_preview<=0
ORDER BY module_339.id
请注意,这可能不会对性能产生太大影响。
我认为性能方面最糟糕的部分可能是 getNextDate_module_339
函数。
如果你能找到一种方法来获得它的功能而不使用函数作为子查询,那么你的 sql 语句可能会比现在运行得更快,不管有没有左连接。
如果您需要帮助,请编辑您的问题以包含该功能,希望我(或其他人)能够帮助您。
【讨论】:
这会加快速度,唯一的问题是这个查询是实际查询的简化版本 - 说明了错误 - 并且是自动生成的,所以我必须检查它是否没有影响过程中的其他任何事情。不过,您的回答解决了我提出的准时问题。因此,我会将您的答案标记为解决方案。谢谢! 忘了说:存储函数本身非常快,正是在这种组合中,一切都变得非常缓慢。【参考方案2】:来自 mysql 参考手册:
提高 SELECT 操作性能的最佳方法是在查询中测试的一个或多个列上创建索引。索引条目的作用类似于指向表行的指针,允许查询快速确定哪些行与 WHERE 子句中的条件匹配,并检索这些行的其他列值。所有 MySQL 数据类型都可以被索引。
虽然为查询中使用的每个可能的列创建索引可能很诱人,但不必要的索引会浪费空间和时间,让 MySQL 确定要使用哪些索引。索引还会增加插入、更新和删除的成本,因为每个索引都必须更新。您必须找到适当的平衡点,才能使用最佳索引集实现快速查询。
作为第一步,我建议检查连接的列是否都已编入索引。由于默认情况下主键总是被索引,我们可以假设 module_339 已经在 id 列上建立了索引,所以首先验证 module_339_schedule 在 itemid 列上被索引。您可以使用以下方法在 MySQL 中检查该表上的索引:
SHOW INDEX FROM module_339_schedule;
如果表在该列上没有索引,您可以使用以下方法添加索引:
CREATE INDEX itemid_index ON module_339_schedule (itemid);
这应该会加速查询的连接组件。
由于您的查询还引用了 module_339.is_system_preview,您还可以考虑使用以下方法向该列添加索引:
CREATE INDEX is_system_preview_index ON module_339 (is_system_preview);
您也许还可以优化存储过程,但您的问题中没有包含它。
【讨论】:
索引已正确创建;存储的函数在自己调用时非常快 您还可以检查数据库中的字符集是否与表中的字符集匹配。见***.com/a/16949603/4853273。以上是关于mysql:存储函数调用+左连接=非常非常慢的主要内容,如果未能解决你的问题,请参考以下文章