如何在多列上加速SELECT .. LIKE查询?

时间:2010-01-11 14:02:48

标签: mysql sql-like

我有一个MySQL表,我经常查询SELECT x, y, z FROM table WHERE x LIKE '%text%' OR y LIKE '%text%' OR z LIKE '%text%'。任何类型的索引都能帮助加快速度吗?

表中有几百万条记录。如果有任何可以加速搜索的内容,是否会严重影响数据库文件的磁盘使用率以及INSERTDELETE语句的速度? (不执行UPDATE

更新:发布后很快,我看到了很多关于LIKE在查询中的使用方式的信息和讨论;我想指出解决方案必须使用LIKE '%text%'(也就是说,我要查找的文本是前缀并附加了%通配符)。数据库也必须是本地的,原因很多,包括安全性。

8 个答案:

答案 0 :(得分:60)

索引不会加速查询,因为对于文本列索引通过从左开始索引N个字符来工作。当您执行LIKE'%text%'时,它无法使用索引,因为在文本之前可能存在可变数量的字符。

你应该做的不是使用这样的查询。相反,你应该使用MySQL支持MyISAM表的FTS(全文搜索)。对于非MyISAM表自己制作这样的索引系统也很容易,你只需要一个单独的索引表,在那里将单词及其相关ID存储在实际表中。

答案 1 :(得分:18)

索引不会帮助文本与前导通配符匹配,索引可用于:

LIKE 'text%'

但我猜这不会削减它。对于这种类型的查询,如果要扩展可以搜索的记录数量,则应该查看全文搜索提供程序。我首选的提供商是Sphinx,非常全功能/快速等。Lucene也可能值得一看。 MyISAM表上的全文索引也可以使用,但最终为任何具有大量写入的数据库追求MyISAM并不是一个好主意。

答案 2 :(得分:12)

索引可以用于加速搜索条件以通配符开头的查询:

LIKE '%text%'

索引可以(可能是,取决于选择性)用于表单的搜索术语:

LIKE 'text%'

答案 3 :(得分:9)

我想补充一点,在某些情况下,如果您正在查看的字段通常为空或包含一些常量,则可以使用索引和like / rlike加速查询。

在这种情况下,似乎可以通过添加带有固定值的“and”子句来限制使用索引访问的行。

我试着在一个巨大的表格中搜索“标签”,这个表通常不包含很多标签。

SELECT * FROM objects WHERE tags RLIKE("((^|,)tag(,|$))" AND tags!=''

如果您在标签上有索引,您会看到它用于限制正在搜索的行。

答案 4 :(得分:6)

也许您可以尝试将mysql5.1升级到mysql5.7。

我有大约70,000条记录。并运行以下SQL:

select * from comics where name like '%test%'; 

mysql5.1中需要 2000ms 。 在mysql5.7或mysql5.6中需要 200ms

答案 5 :(得分:0)

避免全表扫描的另一种方法是选择子字符串并在having语句中检查它们:

SELECT 
    al3.article_number,
    SUBSTR(al3.article_number, 2, 3) AS art_nr_substr,
    SUBSTR(al3.article_number, 1, 3) AS art_nr_substr2,
    al1.*
FROM
    t1 al1 
    INNER JOIN t2 al2 ON al2.t1_id = al1.id
    INNER JOIN t3 al3 ON al3.id = al2.t3_id
WHERE
    al1.created_at > '2018-05-29'
HAVING 
    (art_nr_substr = "FLA" OR art_nr_substr = 'VKV' OR art_nr_subst2 = 'PBR');

答案 6 :(得分:0)

另一种方式:

您可以使用这些字符串REVERSEd来保存计算列并使用

SELECT x, y, z FROM table WHERE x LIKE 'text%' OR y LIKE 'text%' OR z LIKE 'text%' OR xRev LIKE 'txet%' OR yRev LIKE 'txet%' OR zRev LIKE 'txet%' 

如何添加存储的持久化列的示例

ALTER TABLE table ADD COLUMN xRev VARCHAR(N) GENERATED ALWAYS AS REVERSE(x) stored;

,然后在xRevyRev等上创建索引。

答案 7 :(得分:0)

添加全文索引并使用MATCH() AGAINST()

普通索引将无法帮助您进行like查询,尤其是那些在搜索词两边使用通配符的查询。

您可以做的是在要搜索的列上添加全文索引,然后使用MATCH() AGAINST()查询来搜索这些全文索引。

  1. 在所需的列上添加全文索引:

    ALTER TABLE table ADD FULLTEXT INDEX index_table_on_x_y_z (x, y, z);
    
  2. 然后查询这些列:

    SELECT * FROM table WHERE MATCH(x,y,z) AGAINST("text")
    

从我们的试验中,我们发现这些查询在具有超过100万条记录的表中花费大约1毫秒。不错,特别是与耗时16,400毫秒的等效通配符LIKE %text%查询相比。

基准

MATCH(x,y,z) AGAINST("text")耗时1ms

LIKE %text%耗时16400毫秒

快16400倍!