来自任何有实际经验的人,LIKE 查询在
数百万行表上的 MySQL,在速度和效率方面,如果
该字段有一个普通的 INDEX?
不太好(我想我的搜索量在 900k 范围内,不能说我有数百万行 LIKE 的经验)。
通常您应该尽可能地限制搜索,但这取决于表结构和应用程序用例。
此外,在某些 Web 用例中,可以通过一些技巧来实际提高性能和用户体验,例如为单独的关键字编制索引并创建关键字表和 rows_contains_keyword (id_keyword, id_row) 表。关键字表与 AJAX 一起使用以建议搜索词(简单词)并将它们编译为整数 - id_keywords。在这一点上,找到包含这些关键字的行变得真的快。一次更新一行表格也很高效;当然,批量更新成为一个明确的“不要”。
如果只使用 + 运算符,这与 full text MATCH..IN BOOLEAN MODE 已经完成的操作没有太大不同:
SELECT * FROM arts WHERE MATCH (title) AGAINST ('+MySQL +RDBMS' IN BOOLEAN MODE);
您可能需要一个 InnoDB 表来执行此操作:
布尔全文搜索具有以下特点:
- 它们不会自动按照相关性递减的顺序对行进行排序。
...
- InnoDB 表需要 MATCH() 表达式的所有列上的 FULLTEXT 索引才能执行布尔查询。即使没有 FULLTEXT 索引,针对 MyISAM 搜索索引的布尔查询也可以工作,尽管以这种方式执行的搜索会很慢。
...
- 他们不使用适用于 MyISAM 搜索索引的 50% 阈值。
您能否提供有关具体案例的更多信息?
更新:AJAX 方式
设置:您将所有titles 分解为单词。这很快就会给你一个title_words 表( id integer not null autoincrement, word varchar(50) ) 和一个大的title_contains_word ( word_id integer, title_id integer ) 表。
如果您有 1000 万个标题,平均有 4 个单词(对于书籍来说似乎是这样,对于论文来说则不太可能),您可以期望一个 5000 行的 title_words 表和一个包含两个 INTEGER 列的 4000 万行的表;这大约是 400 MB 的额外数据。
对于搜索,用户开始输入一个词,您可以从标题词中自动完成。完成此操作后,查询将变为单词 ID 列表;当然,不在任何标题中的单词甚至都不能输入,因此立即给出否定结果,并且免费。
现在可以通过多种方式进行实际搜索,但我喜欢的一种方式是在每个用户选择之后运行SELECT COUNT(*) FROM title_contains_word WHERE word_id={id},在真正的搜索开始之前。
这允许从 rarest 单词开始构建复合查询或公共表表达式。实际上,如果任何单词的计数低于 20,您可以选择所有这些(平均)八个 TCW 行并获取所有相关单词的 ID,然后简单地验证(在 MySQL 之外)是否有一个标题 ID,例如您的查询的所有 wordID 都存在一对 (titleID, wordID)。
即使你不得不诉诸最粗略的形式,
SELECT a.title_id
FROM title_contains_word AS tcw1
JOIN title_contains_word AS tcw2 USING (title_id)
JOIN title_contains_word AS tcw3 USING (title_id)
JOIN title_contains_word AS tcw4 USING (title_id)
...
WHERE (tcw1.word_id = {id1})
AND (tcw2.word_id = {id2})
...
JOIN 将由非常小的虚拟缓冲表组成,扫描时间非常短。
获得所有相关的标题 ID 后,您就可以使用主键 title_id 从数百万行的大型数据库中直接运行 SELECT。最后的搜索也应该很快。