0

我正在构建一个能够处理许多不同搜索条件的动态 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 子句中计算年龄,还是会因为必须在每一行上完成而非常慢?这是我必须做出的牺牲,还是我有更好的选择?

任何帮助深表感谢。

4

2 回答 2

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。

编辑:

要处理“25”真正意味着“最多 26”的情况,请使用显式比较来实现逻辑:

where date_of_birth >= date(now()) - interval 30 years and
      date_of_birth < date(now()) - interval 26 year
于 2013-07-15T00:55:38.993 回答
2

这与 UDF 或存储过程的性能无关。每当您在列周围使用函数时,MySQL 都不能在其上使用索引。

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

您可以使用 date_of_birth 列上的触发器更新此列。当然,如果您在表上放置适当的索引,则每晚 cronjob 可以有效地选择 date_of_birth = DATE(NOW()) 的行并将年龄增加一。(我会用一个存储过程来做到这一点,所以一切都可以在 MySQL 中完成)。

ps.:您编写的函数似乎是存储函数而不是UDF。存储函数用 SQL 编写并存储在 MySQL 中。UDF 用 C 语言编写,编译为 .so 或 .dll 文件并加载到 MySQL。有关更多信息,您可以查看:对 SP 和 UDF 的帮助?

于 2013-07-15T08:49:38.390 回答