【问题标题】:optimize tables for search using LIKE clause in MySQL使用 MySQL 中的 LIKE 子句优化搜索表
【发布时间】:2026-01-15 13:10:01
【问题描述】:

我正在为我网站的消息部分构建一个搜索功能,并拥有一个包含超过 9,000,000 行的消息数据库,并在 sendersubjectmessage 字段上建立索引。我希望在查询中使用 LIKE mysql 子句,例如 (ex)

SELECT sender, subject, message FROM Messages WHERE message LIKE '%EXAMPLE_QUERY%';

检索结果。不幸的是,当存在前导通配符时,MySQL 不使用索引,这是搜索查询可能出现在消息中的任何位置所必需的(这就是通配符的工作方式,不是吗?)。查询非常非常慢而且我也不能使用全文索引,因为烦人的 50% 规则(我不能排除那么多)。无论如何(甚至,任何替代方法)都可以使用 like 和两个通配符优化查询吗?任何帮助表示赞赏。

【问题讨论】:

  • 您有 900 万行,除了消息之外,您无法过滤其他任何内容?没有发送日期和发件人?
  • 看看SphinxSE。我喜欢这种东西。
  • @RobinCastlin 我可以,这只是一个例子。但按消息内容搜索是任何消息应用程序的关键功能

标签: php mysql indexing


【解决方案1】:

'%EXAMPLE_QUERY%'; 是一个非常非常糟糕的主意.. 我会给你一些

A.避免在 LIKE 查询开头使用通配符,而是使用 'EXAMPLE_QUERY%';

B.创建可以轻松使用的关键字MATCH

【讨论】:

  • 感谢您的提示!但是有两个问题a.如果避免使用开头的通配符,它​​不会只搜索以该查询开头的东西,所以如果它出现在中间它是无效的吗? b. 50% 规则阻止我使用匹配/反对子句
【解决方案2】:
select * from emp where ename like '%e';

给出以字母 e 结尾的 emp_name。

select * from emp where ename like 'A%';

给出以字母 a 开头的 emp_name。

select * from emp where ename like '_a%';

给出第二个字母是 a 的 emp_name。

【讨论】:

    【解决方案3】:

    您应该使用全文索引(您说过不能),自己设计全文搜索或从 MySQL 卸载搜索并使用 Sphinx/Lucene。对于 Lucene,您可以使用 Zend Framework 中的 Zend_Search_Lucene 实现或使用 Solr。

    MySQL 中的普通索引是 B+Trees,如果字符串的开头不知道,则不能使用它们(开头有通配符时就是这种情况)

    另一种选择是使用参考表自行实现搜索。将文本拆分为单词并创建包含单词 record_id 的表。然后在搜索中,您将查询拆分为单词并搜索参考表中的每个单词。通过这种方式,您不会将自己限制在整个文本的开头,而仅限于给定单词的开头(无论如何您都会匹配其余单词)

    【讨论】:

    • 太棒了!我只需要知道。不过,有两个问题。 1.有没有已知的方法可以强制mysql在使用全文搜索时忽略50%规则? 2. lucene 库会让搜索变得高效吗?
    • @roozbubu 据我所知,包含 IN BOOLEAN MODE 的全文查询不使用 50% 规则 - read documentation
    【解决方案4】:

    如果你想坚持使用 MySQL,你应该使用 FULL TEXT 索引。全文索引索引文本块中的单词。然后,您可以搜索词干并按相关性顺序返回结果。所以你可以在一段文本中找到“example”这个词,但是你仍然不能在“xampl”上有效地搜索到“example”。

    MySQL 的全文搜索不是很好,但功能齐全。

    http://dev.mysql.com/doc/refman/5.1/en/fulltext-search.html

    【讨论】: