假设:
CREATE TABLE `APPLICATION_DEVICE_PUSHINFO` (
`applicationId` bigint(20) NOT NULL,
`deviceId` bigint(20) NOT NULL,
`active` bit(1) NOT NULL,
`inactiveAsOf` datetime DEFAULT NULL,
`lastSentOn` datetime DEFAULT NULL,
`registeredOn` datetime DEFAULT NULL,
`target` int(11) DEFAULT NULL,
`token` varchar(4096) NOT NULL,
PRIMARY KEY (`applicationId`,`deviceId`),
KEY `FKE7F2D58285EFFEAA_idx` (`deviceId`),
KEY `index3` (`token`(255)) USING BTREE,
CONSTRAINT `FKE7F2D58285EFFEAA` FOREIGN KEY (`deviceId`) REFERENCES `DEVICES` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
如果我执行以下查询:
explain SELECT token FROM APPLICATION_DEVICE_PUSHINFO group by token having count(deviceId) > 1;;
我明白了:
'1', 'SIMPLE', 'APPLICATION_DEVICE_PUSHINFO', 'ALL', NULL, NULL, NULL, NULL, '7', 'Using temporary; Using filesort'
空值属于可能的键等。
为什么不使用列标记的索引?
答案 0 :(得分:1)
由于您没有WHERE子句,查询需要处理所有行(请注意,在GROUP BY之后应用HAVING子句 - 因此它不限制要处理的行,只是那些返回的行)。
如果你需要触摸所有行,很难从索引中获得任何好处。然而,如果你能够进行仅索引扫描(IOS)和/或从磁盘上预先订购的数据中受益,就有可能获得一些东西。
但是,IOS可能(不确定MySQL是否考虑了NOT NULL约束)会因访问deviceId
列而被阻止,该列未包含在可能用于此查询的索引中({ {1}})。请注意,您需要有一个索引来满足查询的所有需求才能获得仅索引扫描。但是,如果MySQL足够智能并且识别出NOT NULL约束,那么这应该不是问题。否则,请重写您的查询。例如count(*)> 1。
在这种特殊情况下,由于桌子的体积很小(至少根据优化者的估计),你有机会让IOS变得糟糕(正如草莓已经提到的那样)。
如果您需要确保它也适用于更多行,只需填写表格,看它是否会改变执行计划。如果没有,请按上述更改查询,然后重试。如果没有,请返回此处,我们将看到(发布新的执行计划)。
您希望通过索引执行此查询原则上是合理的。让它发挥作用是另一个故事:(