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:存储函数调用+左连接=非常非常慢的主要内容,如果未能解决你的问题,请参考以下文章

非常着急!c语言被调函数如何用主函数的内容

MySQL存储过程执行慢

MS Access 中通过 ODBC 连接 MS SQL 表的查询非常慢

AJAX 响应非常慢

选择下的 SQL 函数使其非常慢

mysql的 视图触发器事务存储过程函数索引与慢查询优化