为什么这个MySQL IN需要比WHERE OR更长的时间?

时间:2016-05-20 14:29:55

标签: mysql

我有两个表,identitiesevents

identities只有两列identity1identity2,两者都有HASH INDEX。

events有大约50列,而_p列有一个HASH INDEX。

CREATE TABLE `identities` (
  `identity1` varchar(255) NOT NULL DEFAULT '',
  `identity2` varchar(255) DEFAULT NULL,
  UNIQUE KEY `uniques` (`identity1`,`identity2`),
  KEY `index2` (`identity2`) USING HASH,
  KEY `index1` (`identity1`) USING HASH
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-

CREATE TABLE `events` (
  `rowid` int(11) NOT NULL AUTO_INCREMENT,
  `_p` varchar(255) NOT NULL,
  `_t` int(10) NOT NULL,
  `_n` varchar(255) DEFAULT '',
  `returning` varchar(255) DEFAULT NULL,
  `referrer` varchar(255) DEFAULT NULL,
  `url` varchar(255) DEFAULT NULL,

  [...]

  `fcc_already_sells_online` varchar(255) DEFAULT NULL,
  UNIQUE KEY `_p` (`_p`,`_t`,`_n`),
  KEY `rowid` (`rowid`),
  KEY `IDX_P` (`_p`) USING HASH
) ENGINE=InnoDB AUTO_INCREMENT=5231165 DEFAULT CHARSET=utf8;

那么,为什么这个查询:

SELECT SQL_NO_CACHE * FROM events WHERE _p IN (SELECT identity2 FROM identities WHERE identity1 = 'user@example.com') ORDER BY _t

需要约40秒,而这一个:

SELECT SQL_NO_CACHE * FROM events WHERE _p = 'user@example.com' OR _p = 'user2@example.com' OR _p = 'user3@example.com' OR _p = 'user4@example.com' ORDER BY _t
当它们基本相同时,它只需要20ms?

编辑:

这个内部查询需要3,3ms:

SELECT SQL_NO_CACHE identity2 FROM identities WHERE identity1 = 'user@example.com'

3 个答案:

答案 0 :(得分:2)

原因:

MySQL将条件IN <static values list>IN <sub-query>视为不同的东西。在documentation中充分说明了第二个等于= ANY()查询,即使该索引存在,它也不能使用索引。 MySQL只是不够聪明。相反,当索引存在意味着MySQL可以轻松使用索引时,第一个被视为简单的范围扫描。

可能的解决方法:

在我看来,有一些解决方法,你甚至已经提到过其中一个。所以它可能是:

  • 使用JOIN。如果有一个要加入的字段,这很可能是解决问题的最佳方法。实际上,因为版本5.6 MySQL已经tries to enforce this optimization可能,但是在复杂情况下或者在没有相关子查询的情况下不起作用(所以基本上如果MySQL不能&#34;跟踪&#34;该参考)。根据您的情况,这不是一个选项,这实际上是您的子查询的原因。
  • 查询应用程序中的子资源并形成静态列表。是的,尽管通常的做法是避免由于连接/网络/查询计划开销导致的多个查询,但实际上它可以工作。在您的情况下,即使您之前在所有重新计算的内容上有200毫秒的开销,仍然值得独立查询子资源,然后将静态列表替换为应用程序中的下一个查询。

答案 1 :(得分:-1)

this is already asked

管理IN运算符更容易,因为它只是一个构造,它在多个条件下定义OR运算符,并且=运算符在同一个值上。如果使用OR运算符,优化器可能不会认为您总是在相同的值上使用=运算符。

答案 2 :(得分:-1)

因为您的查询正在为事件表中的每一行调用此内部查询。

在第二种情况下,不使用缩进表。

你应该使用加入。