SQL查询中年龄计算的性能

时间:2013-07-15 00:18:20

标签: mysql sql database performance query-optimization

我正在构建一个动态MySQL用户搜索查询,以便能够处理许多不同的搜索条件。我考虑编写存储过程,但最终在客户端构建查询(PHP中的预准备语句)。其中的标准是能够搜索用户'年龄,即在X和Y岁之间。我想知道如何尽可能有效地做到这一点。最终查询将相当复杂并且具有多个连接,并且将来可能在几百万行上运行,因此我需要尽可能地优化它。我将用户的出生日期存储在具有DATE格式的索引YYYY-MM-DD列中。我有以下用户定义函数(UDF)来计算用户的年龄:

RETURN (DATE_FORMAT(current_time, '%Y') - DATE_FORMAT(date_of_birth, '%Y') - (DATE_FORMAT(current_time, '00-%m-%d') < DATE_FORMAT(date_of_birth, '00-%m-%d')));

计算的细节并不重要;我更关心如何使用它。我担心的一个问题是在我的WHERE子句中使用这个UDF会大大减慢查询速度,因为它需要在每一行上运行,即使我使UDF确定性。我无法保证在检查年龄之前还有其他标准可以缩小匹配行。我不能仅仅根据日期检查出生日期,因为这不准确。我是在考虑是否将上述计算从UDF中拉出来并将其直接嵌入查询的WHERE子句中会产生明显的差异(我认为是)。然后缺点是WHERE子句进一步复杂化这种计算(或实际上是两个,除非有一种方法可以重用结果)。但我想没有办法避免这些计算。在WHERE子句中执行此计算是关于性能的方法,还是有更好的方法?

理论上,我想我甚至可以在age表中添加user列,并计算用户每晚注册并运行预定作业/ cronjob的年龄,以更新有用户的年龄今天的生日(如果我可以有效地选择)。这肯定会加快我的搜索查询速度,但会引入冗余数据。因此,如果无法在搜索查询本身内有效地完成计算,我真的只想这样做。

因此,总结一下:我需要搜索年龄范围内的用户(例如25到30)。我应该在WHERE子句中计算年龄,还是会非常慢,因为必须在每一行上完成?这是我必须做出的牺牲,还是我有更好的选择?

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:4)

如果您想根据当前日期进行准确的年龄计算,那么您应该尝试以下方法:

where date_of_birth between date(now()) - interval 30 years and date(now()) - interval 25 year

在这种情况下,您正在进行date_of_birth的任何转换,因此索引可用于查询。

此外,您不应使用以下表达式:

DATE_FORMAT(current_time, '%Y') - DATE_FORMAT(date_of_birth, '%Y')

DATE_FORMAT()将参数转换为字符串。你想要一个数字,所以只需使用:

year(now()) - year(date_of_birth)

它保存从日期到字符串到int的转换,直接转到int。

编辑:

处理&#34; 25&#34;真正的意义&#34;直到26&#34;,用明确的比较实现逻辑:

where date_of_birth >= date(now()) - interval 30 years and
      date_of_birth < date(now()) - interval 26 year

答案 1 :(得分:2)

这并不是关于UDF或存储过程的性能。无论何时使用列周围的函数,MySQL都不能使用索引。

如果你不希望Highlander在你的数据库中,那么年龄的tinyint无符号列就足够了(0-255)。这需要1个字节/行。你可以在上面放一个索引。此列添加到表中的开销是微不足道的。不要害怕存储空间。另一方面,存储性能受到更大的关注。全扫描搜索的成本远高于此1字节的额外列。

您可以使用date_of_birth列上的触发器更新此列。当然,如果你在桌子上放置适当的索引,夜间cronjob可以有效地选择date_of_birth = DATE(NOW())的行并将年龄增加1。 (我会用存储过程执行此操作,因此一切都可以在MySQL中完成。)

ps。:您编写的函数似乎是存储函数而不是UDF。存储函数用SQL编写并存储在MySQL中。 UDF是用C编写的.so或.dll文件,并加载到MySQL。有关详细信息,请查看:Help with SP and UDF?