复合索引中的OR问题

时间:2011-06-25 06:10:12

标签: mysql performance indexing query-optimization

在我的许多查询中,我都有像

这样的场景
SELECT * from myTable m 
where m.userId = :userId
AND  (m.to = :contactNumber OR m.from = :contactNumber)
AND .....

所以我为(userId,to,from)

创建了一个复合索引

如果OR替换为AND,则效果正常,但OR只使用userId的索引。

我有点困惑,为什么会发生这种情况,还有什么更好的方法来对此进行索引以提高性能,可能会单独索引所有这些吗?

2 个答案:

答案 0 :(得分:2)

复合索引搜索混合在一起的几个东西。将它看作是连接的各列的索引可能会有所帮助。

因此,如果您使用或,您正在寻找userid和to,OR userid和from的组合。但不是所有3个在一起!

它有点取决于内容和所有内容,但您可以为两个“子”查询添加2个复合(所以userid和+ userid和from)。但是用户ID索引不够吗?如果这样会占用足够的行以使其可以管理,我就不会去添加各种复合索引......

答案 1 :(得分:2)

您只需要考虑如何将复合索引放在一起。密钥主要按userId排序。在每个userId中,它们将按to排序,并且在每个这些组中,它将按from排序。

这意味着,虽然您可以使用该索引查找特定的userId值,userId:to对和userId:to:from三元组,但找到特定的userId:from对并不是很好。这是因为这些值将在索引顺序中的许多不同位置,因为to是比from更高级别的键。

执行此操作的一种方法是在userId:from上添加一个额外的索引,然后在联合中使用两个单独的查询,这两个查询都可以使用自己的索引来有效地查找行。类似的东西:

select * from myTable m
    where m.userId = :userId and m.to = :contactNumber
union
select * from myTable m
    where m.userId = :userId and m.from = :contactNumber

第一个查询很可能会使用原始索引,因为userId:to是它的两个顶级组件。您可能也有一个索引,但它可能没有必要,因为您已经有一个可用的索引(并且可能用于您想要所有三个组件的行的其他查询)。

第二个查询可能会使用新索引来有效地查找其行。

union将他们合并两个查询并删除重复项。这需要匹配原始查询的意图。如果您知道查询之间可能没有交叉,那么您可以使用union all跳过(不必要的)重复删除步骤,但我认为您不能在此处执行此操作。

此方法还具有在支持它的数据库中容易受到并行性的潜在优势(查询可以并行运行,并且一旦完成,就可以组合)。

现在请记住这是一般建议。我自己就是一个DB2人,所以我在这里提出的是基于数据库内部工作的一般知识,而不是MySQL的具体细节。

您仍然应该测试查询以确保它们按预期运行(但我认为即使我是MySQL的 author ,您也希望这样做)。换句话说,我已经失去了数次我在这里说了多少次,测量,不要猜测!