我有一个MySQL表,我经常查询SELECT x, y, z FROM table WHERE x LIKE '%text%' OR y LIKE '%text%' OR z LIKE '%text%'
。任何类型的索引都能帮助加快速度吗?
表中有几百万条记录。如果有任何可以加速搜索的内容,是否会严重影响数据库文件的磁盘使用率以及INSERT
和DELETE
语句的速度? (不执行UPDATE
)
更新:发布后很快,我看到了很多关于LIKE
在查询中的使用方式的信息和讨论;我想指出解决方案必须使用LIKE '%text%'
(也就是说,我要查找的文本是前缀并附加了%通配符)。数据库也必须是本地的,原因很多,包括安全性。
答案 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;
,然后在xRev
,yRev
等上创建索引。
答案 7 :(得分:0)
MATCH() AGAINST()
。普通索引将无法帮助您进行like
查询,尤其是那些在搜索词两边使用通配符的查询。
您可以做的是在要搜索的列上添加全文索引,然后使用MATCH() AGAINST()
查询来搜索这些全文索引。
在所需的列上添加全文索引:
ALTER TABLE table ADD FULLTEXT INDEX index_table_on_x_y_z (x, y, z);
然后查询这些列:
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倍!