python MySQL中的中缀搜索(中间带有模式搜索),带有索引

cgh8pdjw  于 2023-04-28  发布在  Python
关注(0)|答案(1)|浏览(126)

我有一个MySQL 8 InnoDB压缩表,带有索引:

set global innodb_file_per_table=1;
create table t (id int primary key auto_increment, 
                key varchar(200), value varchar(200))
                  row_format=compressed engine=innoDB;
create index key_index on t(key) using BTREE;
create index value_index on t(value) using BTREE;

对于2000万个项目,一个(前缀)搜索就像

select * from t where email like "hello%"

需要几毫秒(感谢索引!)...但是像这样的 (中缀) 搜索

select * from t where email like "%hello%"

需要40秒

**如何加快查询速度?**我读过https://dev.mysql.com/doc/refman/8.0/en/fulltext-search.html,但我不想使用太复杂的工具:什么是最轻的解决方案,能够进行搜索,如:

******abc***************************
  |     |                        |
  |     an exact sequence        |
  |                              |
  0, 1 or many characters        0, 1 or many characters

注意:我使用mysql-8.0.33-winx64和Python(import mysql.connector)。

mwkjh3gx

mwkjh3gx1#

如果全文索引对于您的口味来说太复杂,那么只有其他方法可以加快查询速度:

  • 获得更快的计算机
  • 删除数百万行数据,直到表变小,并且表扫描足够快。

在模式的开始处使用通配符显示的查询必然要进行表扫描,即使您有一个b树索引。这种模式匹配不能使用b树索引。
想想电话簿的类比。这本书是按姓和名排序的。如果你按某人的姓查找,你可以快速搜索,因为它是排序的。但是如果你搜索的人的姓氏有一些字符模式 * 在中间 *,事实上,这本书是按姓氏排序没有帮助。你仍然需要查看每一页上的每一个条目。这就像数据库中的表扫描。
MySQL中的FULLTEXT索引可能也没有帮助。如果您搜索的是整个单词,而不是任意的模式或子字符串,它会很有帮助,因为它不支持前导通配符搜索。
https://dev.mysql.com/doc/refman/8.0/en/fulltext-boolean.html说:
*
星号用作截断(或通配符)运算符。与其他运算符不同,它被附加到要受影响的单词后面。如果单词以*运算符之前的单词开始,则单词匹配。
你不能在单词前使用这个通配符,只能在单词前缀后使用。这正是MySQL当前版本中实现此功能的方式。
MySQL支持生成的列和这些列的索引,所以你可以在LIKE表达式上创建一个索引:

alter table t 
  add column contains_hello boolean as (email like '%hello%'),
  add key (contains_hello);

然后在该列中搜索为真的行:

select * from t where contains_hello = true;

这将使用索引,但仅用于在生成的列的定义中固定的模式'%hello%'。不能生成为任何参数都带参数的生成列。
基本上,没有好的选择。为任何新模式创建索引的代价至少与执行表扫描一样高(实际上更高)。

相关问题