MySQL中的快速子字符串搜索策略是否足够快?

MySQL中的快速子字符串搜索策略是否足够快?,mysql,sql,database,database-design,Mysql,Sql,Database,Database Design,我有一个包含数百万行的用户表。我正在实现一个搜索功能,允许某人通过键入用户名来查找用户。这个自动完成功能需要非常快。鉴于此,在MySQL中,列索引使用类似{string}的方法加速查询,以下方法的性能是否足以在200毫秒内返回?(注意:内存开销不是问题,用户名最多30个字符) 创建一个USERSEARCH表,该表具有用户表的外键和索引的ngram用户名列: USERSEARCH user_id username_ngram -------------

我有一个包含数百万行的用户表。我正在实现一个搜索功能,允许某人通过键入用户名来查找用户。这个自动完成功能需要非常快。鉴于此,在MySQL中,列索引使用类似{string}的方法加速查询,以下方法的性能是否足以在200毫秒内返回?(注意:内存开销不是问题,用户名最多30个字符)

创建一个USERSEARCH表,该表具有用户表的外键和索引的ngram用户名列:

    USERSEARCH
    
    user_id    username_ngram   
    -------------------------
    1          crazyguy23         
    1          razyguy23       
    1          azyguy23      
    1          zyguy23       
    ...       
然后,查询将是:

    SELECT user_id FROM myapp.usersearch WHERE username_ngram LIKE {string}%
    LIMIT 10

我知道存在第三方解决方案,但出于其他原因,我现在不想使用它们。就速度而言,这种方法可行吗?如果db需要检查所有O(30n)行,其中n是用户数,我是否高估了索引的威力?

可能不会。union distinct将处理每个子查询直到完成

如果只需要任意行,请将其表述为:

(SELECT user_id
 FROM myapp.usersearch
 WHERE username_1 LIKE {string}%
 LIMIT 10
) UNION DISTINCT
(SELECT user_id
 FROM myapp.usersearch
 WHERE username_2 LIKE {string}%
 LIMIT 10
)
LIMIT 10;
这至少可以为常见前缀节省大量时间,比如说
'S'

这就是说,这只是返回一个包含10个
user\u id
s的任意列表,而可能还有更多


我不知道对于你的申请来说速度是否足够快。您必须通过测试一组适当的数据来做出判断。

我认为您需要使用mysql全文索引来提高性能。 您需要更改语法以使用全文索引

创建全文索引

在usersearch(username\ngram)上创建全文索引ix\u usersearch\u username\ngram


mysql官方文档如何使用全文索引

假设使用SSD,那应该非常快,是的

以下是一些进一步的优化:

  • 我会在您的查询中添加一个
    DISTINCT
    ,因为多次返回同一个用户id没有意义。尤其是在搜索非常常见的前缀时,例如单个字母

  • 也考虑只搜索至少3个输入字母。“更少”往往是毫无意义的(因为希望您的用户名至少有3个字符长),并且对您的数据库来说是一个不必要的打击

  • 如果您不添加更多的列(我希望您不添加,因为此表是用于快速搜索的!),我们可以做得更好。交换列。生成主键(用户名、内存、用户id)。这样,您就可以直接在主键上搜索。(注意结果的字母顺序的额外好处!好吧…匹配后缀的字母顺序,也就是说,不是完整的用户名。)

  • 确保您有一个关于用户id的索引,以便在需要更改用户名时能够替换用户的所有内容。(要执行此操作,只需删除该用户id的所有行并插入全新的行。)

  • 也许我们可以做得更好。因为这只是为了快速搜索,所以可以使用隔离级别
    READ\u UNCOMMITTED
    。如果我没弄错的话,这样可以避免放置任何读锁,而且应该更快。它可以读取未提交的数据,但那又怎么样。。。之后,您只需在另一个表中查询任何生成的用户ID,如果该用户仍在创建中,则可能找不到这些ID。您没有丢失任何东西。:)


  • 为什么要使用
    \n
    列来表示应成行的可变数量的数据(与您编辑的问题相关),这样更好。。现在你的性能测试揭示了什么?我们不能保证它会运行在注意到没有orderby的LIMIT是相当没有意义的sbig-O符号只有在谈论算法时才有意义,而不是数据的大小。就说你有大约100万行(十的最接近幂可以,四舍五入)来给我们举一个数据集大小的例子。“用户只需要感觉得到很好的照顾。”——是的!如果第一次选择发现了10个匹配项,有没有办法在联合之后进行下一次选择?也许通过在第二个选择中插入某种变量(例如限制10计数(*)@Rage。您可能可以使用CTE实现这一点,但这可能很棘手。这是完全相同的
    SELECT
    的两个副本。也许你想要一些不同的东西?全文索引不能满足我的需要。它索引了完整的单词。如果我在username_ngram上有一个全文索引,那么字符串“guy”就永远找不到了。默认情况下是的。读一下。如果这对你不起作用,那没关系。但我认为这是可能的。