MySQL中使用索引的IN子句的最大数目

MySQL中使用索引的IN子句的最大数目,mysql,sql,Mysql,Sql,我目前正试图查询一个包含多(3)个in子句的表,如: SELECT * FROM table WHERE a IN (2884,5320) AND b IN ('a', 'b', 'c') AND c IN (1, 2, 3) AND d='abcd' AND date BETWEEN 0 AND 1383177599 该表的索引类似于索引(a、b、c、d、日期) 但是,当我对查询运行解释程序时,解释程序显示没有合适的索引可供使用

我目前正试图查询一个包含多(3)个in子句的表,如:

 SELECT *
 FROM table
 WHERE
     a IN (2884,5320)
   AND 
     b IN ('a', 'b', 'c')
   AND 
     c IN (1, 2, 3)
   AND d='abcd'
   AND date BETWEEN 0 AND 1383177599
该表的索引类似于
索引(a、b、c、d、日期)

但是,当我对查询运行解释程序时,解释程序显示没有合适的索引可供使用。即使I
强制索引
,情况仍然如此

如果我将s中的上述
之一更改为
=
,例如

SELECT *
FROM table
WHERE
    a = 2884
  AND 
    b IN ('a', 'b', 'c')
  AND 
    c IN (1, 2, 3)
  AND d = 'abcd'
  AND date BETWEEN 0 AND 1383177599
MySQL将允许我强制它使用索引,但会选择另一个非覆盖索引。无论
中的哪个
更改为
=
,情况都是如此

我的问题:

对于索引查询,您可以使用的in子句的数量是否有限制?这里有什么明显的我遗漏的吗

关于这张桌子需要知道的几件事:
9GB,约8000000行。它包含一个非常大的文本列(JSON字段),但该列不是上面查询的任何列。上述in条款可能会大得多(200-300项)

谢谢

编辑:
这是explain在查询中的输出(使用
强制索引
1,“简单”、“表格”、“全部”、“更正索引”、NULL、NULL、NULL、6977553,“使用where”

如果正确的索引是上面解释的(
索引(a,b,c,d,date)

您不能期望通过索引为范围谓词(如
中的
)搜索多个列

即使有多列索引(a、b、c、d、date),最左边的列也应该是相等谓词(
=
),最多一列可以是范围谓词。索引中的任何后续列都没有帮助

例如:

WHERE a = 2884 AND b = 'b' AND c IN (1, 2, 3) AND d = 'abcd'
因此
a
b
是相等谓词,
c
是范围谓词,
d
是另一个相等谓词

对查询运行EXPLAIN,注意
len
ref
列表明您只使用索引的前两列。通过搜索索引在前三列上找到的所有行,
d
的条件很难实现

           id: 1
  select_type: SIMPLE
        table: t
         type: ref
possible_keys: a
          key: a
      key_len: 7              <--- two columns' length
          ref: const,const    <--- only two values for index columns `a` and `b`
         rows: 4
        Extra: Using where; Using index
我在演讲中会更多地讨论这个问题


请回复您的评论:

有没有办法不用重写代码就可以解决这个问题

您已经知道,您只能有一个从索引中受益的范围谓词。您仍然可以在WHERE子句中使用其他范围谓词,但它们不会从索引中获得任何好处

但这并不是一个交易破坏者,因为如果你索引的一个范围表达式可以帮助缩小99%的搜索范围,那就是一个胜利。然后将其他表达式应用于匹配的行是我们可以承受的代价

优化器将尽可能选择最有效的索引,这在很大程度上取决于索引的选择性。然后,查询使用索引来缩小搜索范围,并且只有通过该搜索的行子集会根据其他条件进行测试

再看看您的查询:

... WHERE
 a IN (2884,5320)
AND 
 b IN ('a', 'b', 'c')
AND 
 c IN (1, 2, 3)
AND d='abcd'
AND date BETWEEN 0 AND 1383177599
假设我们知道只有1%的行匹配(1,2,3)
中的
c,但其他术语平均匹配20-40%的行

我们可以索引等式谓词,没关系。然后我们可以为索引选择另一列,因为所有其他术语都是范围谓词。我们选择最有选择性的列:
c
。因此,最佳索引位于(d,c),并且必须按该顺序排列


您的应用程序中可能有其他查询,这些查询具有不同的选项,其中WHERE子句中引用了哪些列,以及我们正在搜索的特定值。因此,我们可能需要另一个具有不同列集的索引,或者甚至需要具有不同顺序的相同列的索引。需要多个索引并不罕见,因为正如我在演示文稿中提到的,您需要创建的索引取决于您想要优化的查询。

您可以显示explain的输出吗?是的,附加到问题@Ashalyndt这是一个很好的解释@Bill,非常感谢。我已经看过了附件中的演示,现在我似乎很清楚它是如何工作的。基本上,它看起来是这样的,我在查询中遇到了一个基本的设计缺陷,为了以任何正常方式执行,我在
(range)子句中只能有1个
。有没有办法不用重写代码就可以解决这个问题?我可以使用MySQL的任何技巧继续在
s中使用多个
,还是我在这一点上卡住了?感谢@Bill的快速响应,非常感谢。最后一个问题:如果允许我在索引中使用一个range子句,为什么MySQL不让我为上面的A列强制使用索引?它似乎应该让我使用索引,因为它是索引中最左边的列,是第一个范围。我不能说。当我测试它时,我可以让它在您描述的情况下使用索引。我正在MySQL 5.6.13上进行测试。我可以建议您在上创建一个测试
... WHERE
 a IN (2884,5320)
AND 
 b IN ('a', 'b', 'c')
AND 
 c IN (1, 2, 3)
AND d='abcd'
AND date BETWEEN 0 AND 1383177599