我有两个表,identities
和events
。
identities
只有两列identity1
和identity2
,两者都有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'
答案 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;该参考)。根据您的情况,这不是一个选项,这实际上是您的子查询不的原因。答案 1 :(得分:-1)
管理IN运算符更容易,因为它只是一个构造,它在多个条件下定义OR运算符,并且=运算符在同一个值上。如果使用OR运算符,优化器可能不会认为您总是在相同的值上使用=运算符。
答案 2 :(得分:-1)
因为您的查询正在为事件表中的每一行调用此内部查询。
在第二种情况下,不使用缩进表。
你应该使用加入。