【问题标题】:Searching for a faster query than like '%something.%'搜索比“%something.%”更快的查询
【发布时间】:2014-02-21 09:11:43
【问题描述】:

我有一大堆域名和一大堆单词。我想检查我的列表中有多少个域名在它们的末尾有这些单词。我尝试了 2 个查询,但都花费了太多时间来执行。试图找出是否有任何方法可以使查询更快。

首先我尝试了这个查询,返回结果大约需要 50 分钟:

SELECT COUNT(*) AS count 
FROM   table 
WHERE  domain_name LIKE '%my_word.%'; 

然后我想如果我从中删除.%,也许它会更快,所以我尝试了这个,但它仍然很慢:

SELECT COUNT(*) AS count 
FROM   table 
WHERE  SUBSTRING_INDEX(domain_name, '.', 1) LIKE '%my_word'; 

有人知道查询可能会更快吗?

谢谢。

【问题讨论】:

  • 你用的是什么mysql表引擎??
  • 我正在使用innodb引擎
  • 你能提供一些匹配的样本吗?
  • 样本匹配是什么意思?例如单词best 存在于383,956 个域名的开头或结尾。这就是我正在搜索查询以查找单词是否位于域开头的速度非常快,但查找它是否位于末尾的查询非常慢
  • 即使我现在也有同样的问题..!!!

标签: mysql sql


【解决方案1】:

为获得最佳结果,您需要在数据上创建 FULLTEXT 索引,使用 innoDb mysql 引擎

例如

SELECT  *
FROM    domain_name
WHERE   MATCH(data) AGAINST ('+word1 +word2 +word3' IN BOOLEAN MODE)

参考http://dev.mysql.com/doc/refman/5.0/en/fulltext-boolean.html

【讨论】:

  • 这可以在没有空格的情况下使用吗?即使是这样,它也会让我返回该单词位于域中间的结果,例如如果我搜索example,它会得到codeexampletest.com 作为结果,这是我不想要的。感谢您的尝试
  • #1214 - 使用的表类型不支持 FULLTEXT 索引 :(
  • innoDb mysql引擎支持,但你使用的是myIsam
【解决方案2】:

您的问题可以通过全文索引解决,但它仅在 innodb 的 5.6 版本中兼容,并且您可以在任何版本的 myisam 表中使用。

通过以下命令创建全文索引-

ALTER TABLE my_table ADD FULLTEXT(domain_name);

现在您可以按照以下方式使用查询-

SELECT count(*) FROM my_table WHERE MATCH (domain_name) AGAINST ('your_word');

【讨论】:

    【解决方案3】:

    由于您的查询不是在寻找单独的单词,我相信它不会从全文索引中受益(引擎不知道如何将域解析为单独的单词)。我也不相信substring 解决方案会产生比LIKE 运算符更好的性能。您正在处理简单的字符串匹配,而数据库不是运行它的最佳场所。

    也就是说,我认为提高查询速度的最佳方法是减少需要从磁盘读取的字节数。您可以通过在该列上创建一个简单的索引来实现它(查询仍然是索引扫描,但它会比表扫描便宜)。您可以做的另一件事是从该列中删除不必要的字符,例如 .com.net,因为这将允许在每次访问磁盘时获取更多有意义的数据

    【讨论】:

    • 感谢您的建议,但我无法删除 .com 和 .net 等...该数据库用于一个正在运行的网站,该网站实际上是一个 whois 网站,whoisology.com,所以不能真正删除信息
    • 嗨,@CodeBird,对不起,我不是很清楚,我不是要从现有列中删除.com.net,而是要创建一个新列,为此目的进行了优化,没有无关紧要的字节。
    【解决方案4】:

    您需要从末尾加上双 SUBSTRING_INDEXSUBSTRING 才能进行单词匹配。
    以下将计算 example.com 以及 example.desomethingexample.com

    选择计数(*) 从 t1 哪里子串( SUBSTRING_INDEX( SUBSTRING_INDEX(域名, '.', -2), '.',1), length('example')*(-1)) = 'example';

    SQLFiddle

    另外,您可以避免两次键入模式,使用变量 (Fiddle):

    SET @WORD = '例子'; 设置@LNGTH = 长度(@WORD)*(-1); 选择计数(*) 从 t1 哪里子串( SUBSTRING_INDEX( SUBSTRING_INDEX(域名, '.', -2), '.',1), @LNGTH) = @WORD;

    【讨论】:

    • 我不想要子域我想要域,如果我搜索单词 example,codeexample.com 应该算数
    • 是的,但是要找到像examplecode.com 这样开头有example 的域的数量非常快,就像需要几秒钟一样,问题是词尾
    • 这肯定行不通。而且您仍然在“。”之间缺少,。以及 1. 感谢您的帮助。
    • 试试看,会告诉你的
    • 使用这个在 50 的地方减少到 27 分钟:SELECT COUNT(*) FROM table WHERE RIGHT(SUBSTRING_INDEX(domain_name, '.',1), length('men')) = '男装;
    猜你喜欢
    • 1970-01-01
    • 2012-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-22
    • 1970-01-01
    • 1970-01-01
    • 2011-10-19
    相关资源
    最近更新 更多