如何在Mysql中创建MUL键索引?

时间:2016-11-30 12:52:25

标签: mysql

我们需要在"source path" column上创建索引,该索引已在MUL - Key中。例如,它有/src/com/Vendor/DTP/Emp/Grd1/Sal/2016/Jan/31-01/Joseph,我们需要像'%Sal/2016/Jan%'一样搜索它有近1000万条记录。 请提出改进​​性能的建议。

    | Field      | Type     | Null | Key | Default | Extra          |
    +------------+----------+------+-----+---------+----------------+
    | Id         | int(11)  | NO   | PRI | NULL    | auto_increment |
    | Name       | char(35) | NO   |     |         |                |
    | Country    | char(3)  | NO   | UNI |         |                |
    | source Path| char(20) | YES  | MUL |         |                |
    | Population | int(11)  | NO   |     | 0       |          

1 个答案:

答案 0 :(得分:1)

不幸的是,以%开头的搜索无法使用索引(它与复合索引无关)。

你有一些选择:

  • 路径中的值似乎具有实际意义。理想的解决方案是使用元数据,例如:这个月,名字,等等" SAL"代表并将其存储在自己的列或属性表中,然后查询该元数据。这显然只有在每个路径都有所需元数据的特定情况下才有可能,因此这可能不是一个选项。

  • 您可以添加"搜索表" (例如(id, subpath))包含源路径的所有子路径,例如

    '/src/com/Vendor/DTP/Emp/Grd1/Sal/2016/Jan/31-01/Joseph'
    '/com/Vendor/DTP/Emp/Grd1/Sal/2016/Jan/31-01/Joseph'
    '/Vendor/DTP/Emp/Grd1/Sal/2016/Jan/31-01/Joseph'
    ...
    '/Sal/2016/Jan/31-01/Joseph'
    ...
    '/31-01/Joseph'
    '/Joseph'
    

    你的例子中有11行。现在可以在其上使用索引,例如在

    ... 
    where exists 
     (select * from subpaths s
      where s.subpath like '/Sal/2016/Jan%' and s.id = outerquery.id)
    

    这依赖于了解搜索字词的开头。如果您的示例Sal中的%Sal/2016/Jan实际上应包含字词结尾,例如/NoSal/2016/Jan,您必须修改输入字词以删除第一个字,因此%Sal/2016/Jan%会要求您搜索/2016/Jan%(带索引),然后重新检查结果集也适合%Sal/2016/Jan%(参见一个例子的全文选项,它有相同的"问题"只查找单词的开头)。

    您必须维护搜索表,这通常在触发器中完成(在原始表中插入,更新或删除值时更新子路径表)。

    由于这是一个新表,因此您无法(直接)将其与另一个索引相结合,例如如果where country = 'A' and subpath like 'Sal/2016/Jan%'已经消除了99.99%的行,则优化country = 'A'。如果MySQL实际使用索引(因为优化器可以尝试不同的东西),然后可能重新组织您的查询(例如使用explainjoin),您可能必须检查force index以查询您的查询

  • 您可以使用fulltext search。从userinput中,您必须生成类似

    的查询
    select * from 
      (select * from table 
       where match(`source Path`) against ('+SAL +2016 +Jan' in boolean mode)) subquery
    where `source path` like '%Sal/2016/Jan%'  
    

    全文搜索不关心单词的顺序,因此如果它实际上是正确的路径,则必须重新检查结果集,但全文搜索将使用(全文)索引来加速它。它只会查找单词的开头,所以类似于"搜索表"选项,如果Sal可以是单词的结尾,则必须将其从全文搜索中删除。默认情况下,只有至少包含3或4个字母的单词(取决于您的引擎)才会添加到索引中,因此您必须将ft_min_word_leninnodb_ft_min_token_size的值设置为符合您要求的值。

搜索表方法可能是最方便的解决方案,因为它可以与您当前的搜索非常相似地使用:您可以将用户输入直接添加到一个位置(无需解释它来创建against (...)表达式并且您也可以在其他情况下轻松使用它(例如join table2 on concat(table2.Year,'/',table2.Month,'%') like ...之类的东西);但是你必须设置触发器(或者你需要维护表),这比仅添加全文索引要复杂一些。