mysql: 存储函数调用 + 左连接 = 非常非常慢

mysql: stored function call + left join = very very slow

我有两个表:

module_339 (id,name,description,etc)
module_339_schedule(id,itemid,datestart,dateend,timestart,timeend,days,recurrent)

module_339_schedule.itemid points to module_339

fist table holds conferences

second one keeps the schedules of the conferences

module_339 has 3 items

module_339_schedule has 4000+ items - almost evenly divided between the 3 conferences

我有一个存储函数 - "getNextDate_module_339" - 它将计算指定会议的 "next date",以便能够显示它,并按它排序 - 如果用户需要到。这个存储过程将只获取指定会议的所有日程表条目并循环遍历它们,比较日期和时间。因此它将从 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,它又会很快。 我在这里做错了什么?似乎是函数调用和左连接之间的某种 "collision"。

我认为可以从此查询中删除 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 语句可能 运行 比现在快很多,有或没有左连接。
如果您在这方面需要帮助,请编辑您的问题以包含该功能,希望我(或其他人)能够帮助您。

来自 MySQL 参考手册:

The best way to improve the performance of SELECT operations is to create indexes on one or more of the columns that are tested in the query. The index entries act like pointers to the table rows, allowing the query to quickly determine which rows match a condition in the WHERE clause, and retrieve the other column values for those rows. All MySQL data types can be indexed.

Although it can be tempting to create an indexes for every possible column used in a query, unnecessary indexes waste space and waste time for MySQL to determine which indexes to use. Indexes also add to the cost of inserts, updates, and deletes because each index must be updated. You must find the right balance to achieve fast queries using the optimal set of indexes.

作为第一步,我建议检查连接的列是否都已编入索引。由于默认情况下主键始终被索引,我们可以假设 module_339 已经在 id 列上建立了索引,因此首先验证 module_339_schedule 是否在 itemid 列上建立了索引。您可以使用以下方法检查 MySQL 中 table 的索引:

SHOW INDEX FROM module_339_schedule;

如果 table 在该列上没有索引,您可以使用以下方法添加一个:

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);

您也可以优化存储过程,但您没有将其包含在您的问题中。