1

我在 MyISAM 数据库中有一个包含 1760 万行的表。

我想在其中搜索一个文章编号,但结果不能依赖于特殊字符,如点、逗号等。

我正在使用这样的查询:

 SELECT * FROM `table`
 WHERE 
 replace(replace(replace( replace( `haystack` , ' ', '' ),
 '/', '' ), '-', '' ), '.', '' )
 LIKE 'needle'

这种方法非常非常慢。table上有一个索引haystack,但EXPLAIN显示查询不能使用它,这意味着查询必须在 3.8 秒内扫描 1760 万行。

查询在一个页面中运行多次(10-15 倍),因此页面加载速度极慢。

我应该怎么办?在查询中使用替换是一个坏主意吗?

4

3 回答 3

1

当您对表中的实际数据进行替换时,MySQL 不能使用索引,因为它没有任何需要与needle.

也就是说,如果您的替换设置是静态的,则最好对数据进行非规范化并添加一个新列haystack_search,其中包含应用了所有替换的数据。此列可以在INSERT或期间填充UPDATE。然后可以有效地使用此列上的索引。

请注意,您可能希望%LIKE查询中使用它,否则它实际上与正常的相等比较相同。现在,如果您使用类似的%needle%搜索词(即带有变量开始),MySQL 将再次无法使用索引并回退到表扫描,因为它只有在看到搜索词的固定开始时才能使用索引,即类似的东西needle%

所以最后,您可能最终不得不调整您的数据库引擎,以便它可以将表保存在内存中。MyISAM 表(或 MySQL 5.6 及更高版本也使用 InnoDB 表)的另一种选择是在数据上使用全文索引,这再次允许相当有效的搜索。

于 2013-11-06T09:12:55.713 回答
0

您可以尝试LENGTH在列上使用,不确定它是否会产生更好的效果。此外,在使用时,LIKE您应该使用%

SELECT * FROM `table`
WHERE 
haystack LIKE 'needle%' AND
LENGTH(haystack) - LENGTH(REPLACE(haystack,'/','')) = 0 AND
LENGTH(haystack) - LENGTH(REPLACE(haystack,'-','')) = 0 AND
LENGTH(haystack) - LENGTH(REPLACE(haystack,'.','')) = 0;

如果干草堆正好是针,那么就这样做

SELECT * FROM `table`
WHERE 
haystack='needle';
于 2013-11-06T09:06:16.610 回答
0

将函数应用于列是“不好的”,因为它会强制扫描列。

也许这是一个更好的方法:

SELECT list
     , of
     , relevant
     , columns
     , only
FROM   your_table
WHERE  haystack LIKE 'two[ /-.]needles'

在这种情况下,我们正在搜索“two needles”,其中单词之间的空格可以是方括号内的任何字符,即“two needles”、“two/needles”、“two-needles”或“two.needles” ”。

于 2013-11-06T09:10:02.193 回答