MySQL中使用索引的IN子句的最大数目
我目前正试图查询一个包含多(3)个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、日期) 但是,当我对查询运行解释程序时,解释程序显示没有合适的索引可供使用
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