【问题标题】:Correct indexing when using OR operator使用 OR 运算符时正确索引
【发布时间】:2011-10-29 23:18:44
【问题描述】:

我有一个这样的查询:

SELECT fields FROM table
WHERE field1='something' OR field2='something' 
OR field3='something' OR field4='something'

为此查询索引此类表的正确方法是什么?

这样的查询需要一整秒的时间来运行!我有 1 个索引,其中包含所有 4 个字段,所以我认为 mysql 会做这样的事情:

遍历索引中的每一行,这样想: field1 是什么东西?字段2怎么样?字段3?字段4?好的,不,去下一行。

【问题讨论】:

    标签: mysql indexing where-clause


    【解决方案1】:

    您误解了索引的工作原理。

    想想电话簿(相当于姓氏在前,名字在后的两列索引)。如果我让你在电话簿中找出所有姓“史密斯”的人,你会受益于姓名是这样排列的。您可以假设 Smiths 是组织在一起的。但是,如果我要求您查找所有名字为“John”的人,您不会从索引中受益。 Johns 可以有任何姓氏,因此他们分散在整本书中,您最终不得不从头到尾艰难地搜索。

    现在,如果我要求您查找姓氏为“Smith”或名字为“John”的所有人,您可以像以前一样轻松找到 Smiths,但这对您查找 Johns 没有任何帮助.它们仍然散布在整本书中,你必须努力寻找它们。

    SQL 中的多列索引也是如此。索引按第一列排序,然后在第一列相同的情况下按第二列排序,然后在前两列都相同的情况下按第三列排序,依此类推。它不是按所有列排序的同时地。因此,除了索引中最左侧的列之外,您的多列索引无助于提高搜索词的效率。

    回到你原来的问题。

    为此查询索引此类表的正确方法是什么?

    在每列上创建一个单独的单列索引。根据 MySQL 的 estimation of how many I/O operations,其中一个索引将是比其他索引更好的选择。如果使用该索引,则会产生该索引。

    现代版本的 MySQL 也有一些关于 index merging 的聪明之处,因此查询可能在给定表中使用多个索引,然后尝试合并结果。否则 MySQL 往往会被限制为在给定查询中对每个表使用一个索引。

    许多人成功使用的另一个技巧是对每个索引列(应该使用相应的索引)进行单独查询,然后UNION 结果。

    SELECT fields FROM table WHERE field1='something' 
    UNION
    SELECT fields FROM table WHERE field2='something' 
    UNION
    SELECT fields FROM table WHERE field3='something' 
    UNION
    SELECT fields FROM table WHERE field4='something' 
    

    最后一个观察:如果您发现自己在四个字段中搜索相同的'something',您应该重新考虑所有四个字段是否实际上是相同的,并且您设计了一个violates First Normal form with repeating groups 的表。如果是这样,也许 field1 到 field4 属于子表中的单个列。那么索引和查询就变得容易多了:

    SELECT fields from table INNER JOIN child_table ON table.pk = child_table.fk
    WHERE child_table.field = 'something'
    

    【讨论】:

      【解决方案2】:

      除了之前的评论: 如果优化器认为这是个好主意,一些 RDMS(如 Mysql/PostgreSql)可以使用索引合并。 因此,您可以为每个字段创建不同的索引或创建一些复合索引,如 field1,field2 和 field3,field4。最后,您应该尝试几种不同的解决方案,并选择最佳的解释方案。

      【讨论】:

        猜你喜欢
        • 2012-12-03
        • 1970-01-01
        • 2011-10-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-02-17
        • 1970-01-01
        相关资源
        最近更新 更多