distinct实际上和group by的操作非常相似,只不过是在group by之后的每组中取出一条记录而已。
但是distinct分组的时候是不使用排序来做分组的。
同样distinct也分为松散索引扫描和紧凑索引扫描
松散索引
测试过程中我发现如果distinct中的字段本身是唯一的或者没有数据则Extra中不是Using index for group-by,而是显示using Index,说明MySQL在这块还是比较智能的。
如果插入了数据需要更新表信息,analyze table group_message
mysql> explain select distinct gid from group_message \G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: group_message type: range possible_keys: IDX_GID_UID_GMT key: IDX_GID_UID_GMT key_len: 5 ref: NULL rows: 3 Extra: Using index for group-by 1 row in set (0.03 sec) mysql> explain select distinct id from group_message \G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: group_message type: index possible_keys: PRIMARY,IDX_GID_UID_GMT key: IDX_GID_UID_GMT key_len: 16 ref: NULL rows: 5 Extra: Using index 1 row in set (0.03 sec)
紧凑索引扫描:
mysql> explain select distinct uid from group_message where gid = 1\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: group_message type: ref possible_keys: IDX_GID_UID_GMT key: IDX_GID_UID_GMT key_len: 5 ref: const rows: 5 Extra: Using where; Using index 1 row in set (0.32 sec)
distinct不能使用索引的情况:我们发现只使用了临时表并没有使用到排序。
mysql> explain select distinct uid from group_message \G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: group_message type: index possible_keys: IDX_GID_UID_GMT key: IDX_GID_UID_GMT key_len: 16 ref: NULL rows: 5 Extra: Using index; Using temporary 1 row in set (0.02 sec)
表结构:
mysql> show create table group_message \G *************************** 1. row *************************** Table: group_message Create Table: CREATE TABLE `group_message` ( `id` int(11) NOT NULL, `message` varchar(1000) DEFAULT NULL, `gid` int(11) DEFAULT NULL, `uid` int(11) DEFAULT NULL, `gmt_ctreate` datetime DEFAULT NULL, PRIMARY KEY (`id`), KEY `IDX_GID_UID_GMT` (`gid`,`uid`,`gmt_ctreate`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.03 sec)