这个查询(使用不同的名称而不是“jack”)在我的慢速查询日志中发生了很多次。为什么?
Users 表有很多字段(超过我选择的这三个字段)和大约 40.000 行。
select name,username,id from Users where ( name REGEXP
'[[:<:]]jack[[:>:]]' ) or ( username REGEXP '[[:<:]]jack[[:>:]]' )
order by name limit 0,5;
id
是主要的和自增的。
name
有索引。
username
有唯一索引。
有时需要 3 秒! 如果我在 MySQL 上解释选择,我得到了这个:
select type: SIMPLE
table: Users
type: index
possible keys: NULL
key: name
key len: 452
ref: NULL
rows: 5
extra: Using where
这是我能做的最好的吗?我可以解决什么问题?
最佳答案
如果你必须使用正则表达式风格的 WHERE
子句,你肯定会被慢查询问题所困扰。为了使正则表达式搜索起作用,MySQL 必须将名称列中的每个值与正则表达式进行比较。而且,您的查询还查看了您的用户名列,从而使问题加倍。
这意味着 MySQL 无法利用任何索引,这是所有 DBMS 加速大型表查询的方式。
您可以尝试一些操作。所有这些都涉及与 REGEXP 说再见。
一个是这样的:
WHERE name LIKE CONCAT('jack', '%') OR username LIKE CONCAT('jack', '%')
如果您在姓名和用户名列上创建索引,这应该会非常快。它将查找所有以“jack”开头的名称/用户名。注意
WHERE name LIKE CONCAT('%','jack') /* SLOW!!! */
将查找以“jack”结尾的名称,但会像您的正则表达式搜索一样缓慢。
您可以做的另一件事是弄清楚为什么您的应用程序需要能够搜索名称或用户名的一部分。您可以从您的应用程序中消除此功能,或者找出一些更好的方法来处理它。
可能更好的方法:
- 让您的用户将他们的名字分成名字和姓氏字段,然后分别搜索。
- 创建一个单独的“搜索所有用户”功能,仅在用户需要时使用,从而减少缓慢的正则表达式查询的频率。
- 自己使用某种预处理程序将他们的名字分解成一个单独的名字-单词表。在不使用正则表达式的情况下搜索名称-单词表。
- 弄清楚如何使用 MySQL 全文搜索来实现此功能。
所有这些都涉及一些编程工作。
关于针对 REGEXP 的 Mysql 优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12318083/