从任何有实际经验的人看来,如果字段有一个普通的 INDEX,LIKE 查询在数百万行表的速度和效率方面如何在 MySQL 中执行?
不太好(我想我在 900k 范围内进行了一些搜索,不能说我有数百万行 LIKE 的经验)。
通常您应该尽可能地限制搜索,但这取决于表结构和应用程序用例。
此外,在某些Web用例中,可以通过一些技巧来实际提高性能和用户体验,例如索引单独的关键字并创建关键字表和 rows_contains_keyword (id_keyword, id_row) 表。关键字表与 AJAX 一起使用来建议搜索词(简单词)并将它们编译为整数 - id_keywords。那时,查找包含这些关键字的行变得非常快。一次更新一行表格也很高效;当然,批量更新成为明确的“不要”。
如果仅使用 + 运算符,这与全文 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方式
设置:您将所有title
s 分解为单词。这很快就会给你一张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 的额外数据。
对于搜索,用户开始输入一个单词,您可以从 titlewords自动完成该单词。完成此操作后,查询将变为单词 ID 列表;当然,任何标题中没有的单词甚至都不能输入,因此会立即给出否定结果,而且是免费的。
实际搜索现在可以通过多种方式进行,但我喜欢的一种方式是SELECT COUNT(*) FROM title_contains_word WHERE word_id={id}
在每个用户选择之后,在真正的搜索开始之前运行。
这允许从最稀有的单词开始构建复合查询或公共表表达式。实际上,如果任何单词的计数低于 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 。最后一次搜索也应该很快。