【问题标题】:mysql: stored function call + left join = very very slowmysql:存储函数调用+左连接=非常非常慢
【发布时间】: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,它又会很快。 我在这里做错了什么?似乎是函数调用和左连接之间的某种“冲突”。

【问题讨论】:

    标签: mysql stored-functions


    【解决方案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);
    

    您也许还可以优化存储过程,但您的问题中没有包含它。

    【讨论】:

    • 索引已正确创建;存储的函数在自己调用时非常快
    • 您还可以检查数据库中的字符集是否与表中的字符集匹配。见stackoverflow.com/a/16949603/4853273
    猜你喜欢
    • 1970-01-01
    • 2012-10-23
    • 2012-01-03
    • 2012-01-29
    • 1970-01-01
    • 2010-12-07
    • 1970-01-01
    • 2012-06-30
    • 2020-02-04
    相关资源
    最近更新 更多