Mysql

Mysql ,mysql,indexing,Mysql,Indexing,我想得到所有比x早的行,除了那些具有特定批处理id的行 表t: id, created_at, batch_id 查询: SELECT * FROM t WHERE created_at < '2019-01-01' AND batch_id NOT IN (1,2,3) 即使我的行数小于1M,查询速度也很慢。 我在created_at,batch_id和created_at,batch_id上有索引。 我希望复合索引能让它更快,但DB决定改用created_at 每个批处理id大

我想得到所有比x早的行,除了那些具有特定批处理id的行

表t:

id, created_at, batch_id
查询:

SELECT * FROM t 
WHERE created_at < '2019-01-01' 
AND batch_id NOT IN (1,2,3)
即使我的行数小于1M,查询速度也很慢。 我在created_at,batch_id和created_at,batch_id上有索引。 我希望复合索引能让它更快,但DB决定改用created_at


每个批处理id大约有100行。MySQL索引的一般规则是,它最多会对一个范围条件使用索引,索引中的任何后续列都不会对搜索有利

示例:如果在A、B、C列上有索引,则:

在您的查询中,两个条件都是在。。。批次id不在…,是范围条件。也就是说,它们不是相等=条件,因此,除相等以外的任何类型的条件都算作范围条件

颠倒索引列的顺序不会改变这一点。由于这两个条件都是范围条件,MySQL将只对两列中的一列使用索引,即索引的第一列,以两者中的任何一列为准

您看到MySQL在上切换到单列索引,因为优化器知道它无论如何只能使用一列,而且它更喜欢使用更紧凑的索引,因为每页可以容纳更多的索引项

它选择了在上创建的索引,因为人们认为它更具选择性。您说过每个批次id大约有100行,总共有100万行。因此,batch_id NOT IN 1,2,3仅过滤掉0.03%的行。而created_at的条件可能会过滤掉更多的内容,使其成为更好的选择

你说查询仍然很慢。你不会说它有多慢,或者你期望它有多快。也许你对表演有不切实际的期望

也许您的数据库服务器需要更强大的硬件。你不能说你的服务器有什么规格

也许您正在同一台服务器上运行其他要求很高的进程,它们正在与mysqld争夺资源

您不会说您配置了什么MySQL调优参数。也许你的缓冲池太小了。您不需要说明您使用的MySQL的版本。

请将INDEXcreated_放在并保持INDEXcreated_在,batch_id。然后提供解释选择。。。。如果它说使用索引条件又称ICP,那么相对于您所拥有的,有一点好处

这似乎是因为

对于INDEXcreated_at,Bill所说的会导致优化器退出那里。 没有它,它只能在另外两个之间做出决定。如果它选择了复合的,那么它才意识到它可以使用索引条件下推来做不在。ICP提供了一个很小的好处,这个好处最近才在MySQL中实现。 唉,没有一个索引可以很好地处理你的WHERE

你说这个表包含id,created\u at,batch\u id?就这些吗?如果是这样,那么综合指数也在覆盖。这提供了另一个小的加速。养成拼写列而不是使用*的习惯,尤其是在这里提问时。我鼓励你说

INDEX(created_at, batch_id, id)
为了清楚地表明您希望do涵盖这一点:

SELECT id, created_at, batch_id  FROM t
    WHERE created_at < '2019-01-01' 
      AND batch_id NOT IN (1,2,3)
SELECT id, created_at, batch_id  FROM t
    WHERE created_at < '2019-01-01' 
      AND batch_id NOT IN (1,2,3)