`
zhengdl126
  • 浏览: 2542766 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类

MySQL DISTINCT 的基本实现原理

阅读更多

"SELECT distinct uid FROM user WHERE (".$where .") AND uid != '$uid'";

 

 

--------------------------

 

DISTINCT 实际上和 GROUP BY 操作的实现非常相似,只不过是在 GROUP BY 之后的每组中只取出一条记录而已。所以,DISTINCT 的实现和 GROUP BY 的实现也基本差不多,没有太大的区别。同样可以通过松散索引扫描或者是紧凑索引扫描来实现,当然,在无法仅仅使用索引即能完成 DISTINCT 的时候,MySQL 只能通过临时表来完成。但是,和 GROUP BY 有一点差别的是,DISTINCT 并不需要进行排序。也就是说,在仅仅只是 DISTINCT 操作的 Query 如果无法仅仅利用索引完成操作的时候,MySQL 会利用临时表来做一次数据的“缓存”,但是不会对临时表中的数据进行 filesort 操作。当然,如果我们在进行 DISTINCT 的时候还使用了 GROUP BY 并进行了分组,并使用了类似于 MAX 之类的聚合函数操作,就无法避免 filesort 了。

下面我们就通过几个简单的 Query 示例来展示一下 DISTINCT 的实现。

1.首先看看通过松散索引扫描完成 DISTINCT 的操作:

sky @ localhost : example 11 : 03 : 41 > EXPLAIN SELECT DISTINCT group_id
    ->
FROM group_message \ G
***************************
1. row ***************************
          
id : 1
 
SELECT_type : SIMPLE
        
table : group_message
        
type : range
possible_keys : NULL
          
key : idx_gid_uid_gc
      
key_len : 4
          
ref : NULL
        
rows : 10
        
Extra : Using index for group - by
1 row in set ( 0.00 sec )

我们可以很清晰的看到,执行计划中的 Extra 信息为“Using index for group-by”,这代表什么意思?为什么我没有进行 GROUP BY 操作的时候,执行计划中会告诉我这里通过索引进行了 GROUP BY 呢?其实这就是于 DISTINCT 的实现原理相关的,在实现 DISTINCT的过程中,同样也是需要分组的,然后再从每组数据中取出一条返回给客户端。而这里的 Extra 信息就告诉我们,MySQL 利用松散索引扫描就完成了整个操作。当然,如果 MySQL Query Optimizer 要是能够做的再人性化一点将这里的信息换成“Using index for distinct”那就更好更容易让人理解了,呵呵。

2.我们再来看看通过紧凑索引扫描的示例:

sky @ localhost : example 11 : 03 : 53 EXPLAIN SELECT DISTINCT user_id
    ->
FROM group_message
    ->
WHERE group_id = 2 \ G
***************************
1. row ***************************
          
id : 1
 
SELECT_type : SIMPLE
        
table : group_message
        
type : ref
possible_keys : idx_gid_uid_gc
          
key : idx_gid_uid_gc
      
key_len : 4
          
ref : const
        
rows : 4
        
Extra : Using WHERE ; Using index
1 row in set ( 0.00 sec )

这里的显示和通过紧凑索引扫描实现 GROUP BY 也完全一样。实际上,这个 Query 的实现过程中,MySQL 会让存储引擎扫描 group_id = 2 的所有索引键,得出所有的 user_id,然后利用索引的已排序特性,每更换一个 user_id 的索引键值的时候保留一条信息,即可在扫描完所有 gruop_id = 2 的索引键的时候完成整个 DISTINCT 操作。

3.下面我们在看看无法单独使用索引即可完成 DISTINCT 的时候会是怎样:

sky @ localhost : example 11 : 04 : 40 > EXPLAIN SELECT DISTINCT user_id
    ->
FROM group_message
    ->
WHERE group_id > 1 AND group_id < 10 \ G
***************************
1. row ***************************
          
id : 1
 
SELECT_type : SIMPLE
        
table : group_message
        
type : range
possible_keys : idx_gid_uid_gc
          
key : idx_gid_uid_gc
      
key_len : 4
          
ref : NULL
        
rows : 32
        
Extra : Using WHERE ; Using index ; Using temporary
1 row in set ( 0.00 sec )

当 MySQL 无法仅仅依赖索引即可完成 DISTINCT 操作的时候,就不得不使用临时表来进行相应的操作了。但是我们可以看到,在 MySQL 利用临时表来完成 DISTINCT 的时候,和处理 GROUP BY 有一点区别,就是少了 filesort。实际上,在 MySQL 的分组算法中,并不一定非要排序才能完成分组操作的,这一点在上面的 GROUP BY 优化小技巧中我已经提到过了。实际上这里 MySQL 正是在没有排序的情况下实现分组最后完成 DISTINCT 操作的,所以少了 filesort 这个排序操作。

4.最后再和 GROUP BY 结合试试看:

sky @ localhost : example 11 : 05 : 06 > EXPLAIN SELECT DISTINCT max ( user_id )
    ->
FROM group_message
    ->
WHERE group_id > 1 AND group_id < 10
    ->
GROUP BY group_id \ G
***************************
1. row ***************************
          
id : 1
 
SELECT_type : SIMPLE
        
table : group_message
        
type : range
possible_keys : idx_gid_uid_gc
          
key : idx_gid_uid_gc
      
key_len : 4
          
ref : NULL
        
rows : 32
        
Extra : Using WHERE ; Using index ; Using temporary ; Using filesort
1 row in set ( 0.00 sec )

最后我们再看一下这个和 GROUP BY 一起使用带有聚合函数的示例,和上面第三个示例相比,可以看到已经多了 filesort 排序操作了,正是因为我们使用了 MAX 函数的缘故。要取得分组后的 MAX 值,又无法使用索引完成操作,只能通过排序才行了。

 

 

 

---------------------------------------------

 

使用mysql时,有时需要查询出某个字段不重复的记录,虽然mysql提供有 distinct这个关键字来过滤掉多余的重复记录只保留一条,但往往只用它来返回不重复记录的条数,而不是用它来返回不重记录的所有值。其原因是 distinct只能返回它的目标字段,而无法返回其它字段

下面先来看看例子:

   table
   id name
   1 a
   2 b
   3 c
   4 c
   5 b

比如我想用一条语句查询得到name不重复的所有数据,那就必须使用distinct去掉多余的重复记录。

select distinct name from table
得到的结果是:

   name
   a
   b
   c

好像达到效果了,可是,我想要得到的是id值呢?改一下查询语句吧:

select distinct name, id from table

结果会是:

   id name
   1 a
   2 b
   3 c
   4 c
   5 b

 

试了半天,也不行,最后在mysql手册里找到一个用法,

用group_concat(distinct name)配合group by name实现了我所需要的功能 5.0才支持的.

 

突然灵机一闪,既然可以使用group_concat函数,那其它函数能行吗?

赶紧用count函数一试,成功, 现在将完整语句放出:

select *, count(distinct name) from table group by name

结果:

   id name count(distinct name)
   1 a 1
   2 b 1
   3 c 1

再顺便说一句,group by 必须放在 order by 和 limit之前, 不然会报错。。。OK了

 

 

---------------------------------------

 

分享到:
评论

相关推荐

    MySQL DISTINCT 的基本实现原理详解

    MySQL DISTINCT 是一种用于消除查询结果集中重复行的SQL语句,它的基本实现原理与GROUP BY类似,但在细节上有一定的区别。在理解DISTINCT的工作方式时,我们首先要了解它如何与索引交互,以及在无法利用索引时如何...

    MySQL中distinct语句的基本原理及其与group by的比较

    本文将深入探讨`DISTINCT`语句的基本原理,并与`GROUP BY`进行比较。 首先,`DISTINCT`关键字用于消除查询结果中的重复行,它会返回唯一的、不重复的值。例如,如果你有一个包含用户ID的表,`SELECT DISTINCT user_...

    MySQL关键字Distinct的详细介绍

    MySQL中的`DISTINCT`关键字是用于消除查询结果中的重复行,从而返回唯一不同的值。它在数据查询中扮演着至关重要的角色,特别是在处理可能存在重复记录的数据表时。下面将详细介绍`DISTINCT`关键字的用法及其注意...

    MySQL5.1性能调优与架构设计.mobi

    8.5 Join的实现原理及优化思路 8.6 ORDER BY、GROUP BY和DISTINCT的优化 8.7 小结 第9章 MySQL数据库Schema设计的性能优化 9.0 引言 9.1 高效的模型设计 9.2 合适的数据类型 9.3 规范的对象命名 9.4 小结 ...

    mysql第五章.pdf

    1. 基本查询语句:这是SQL语言从数据库中获取信息的一个基本语句,使用SELECT语句实现从一个或多个表中查询信息,并将结果显示为一个结果集。基本语法格式包括SELECT、FROM以及WHERE子句的使用。例如,使用SELECT ...

    数据库系列(:MySQL 视图、触发器的原理与实战

    ### 数据库系列:MySQL 视图、触发器的原理与实战 #### 视图原理与实战 ##### 一、视图的基本概念 视图(View)是基于一个或多个表的虚拟表,它本身并不存储数据,而是由一系列定义好的SQL查询构成。视图可以被...

    mysql_Query优化

    #### 五、JOIN 实现原理及优化思路 **5.1 JOIN 的基本概念** JOIN 操作用于合并两个或多个表中的行。根据连接条件的不同,JOIN 可分为 INNER JOIN、LEFT JOIN、RIGHT JOIN 和 FULL OUTER JOIN 等。 **5.2 JOIN 的...

    mysql练习作业题.docx

    MySQL是一种广泛使用的开源关系型数据库管理系统,它支持...以上就是关于MySQL的一些基本概念和操作,包括存储引擎、用户管理、数据查询和SQL编程等。通过这些练习题,可以巩固和提升对MySQL数据库的理解和应用能力。

    MySQL排序原理和案例详析

    本文首先会简单介绍SQL如何利用索引避免排序代价,然后会介绍MySQL实现排序的内部原理,并介绍与排序相关的参数,最后会给出几个“奇怪”排序例子,来谈谈排序一致性问题,并说明产生现象的本质原因。 1.排序优化与...

    逐步精通mysql数据库

    1. **基本概念**:首先,我们需要了解什么是数据库,以及关系型数据库的基本原理。MySQL是一个基于SQL(结构化查询语言)的数据库管理系统,它允许用户通过SQL语句来存储、更新和检索数据。 2. **安装与配置**:在...

    mysqlquery优化[整理].pdf

    **8.5 Join的实现原理及优化思路** JOIN操作是数据库中的复杂操作,优化主要包括选择正确的JOIN顺序、使用索引、减少临时表的使用等。LEFT JOIN和RIGHT JOIN可能导致全表扫描,尽量使用INNER JOIN并结合索引来提高...

    MYSQL语法与例题.pdf

    MySQL语法与例题.pdf文档提供了关于MySQL数据库的基本语法知识和一些...文档的内容虽然有些许OCR扫描错误,但整体上提供了有关MySQL数据库操作的基础知识,特别是创建表结构、数据查询与数据库设计原理等方面的内容。

    MySQL面试题经典40问!(全)(含答案解释)

    3. **ACID特性的实现原理**: - **原子性**:使用undo log,记录事务开始前的状态,以便回滚。 - **持久性**:通过redo log,记录已提交的修改,用于系统崩溃后的恢复。 - **隔离性**:通过锁定机制和多版本并发...

Global site tag (gtag.js) - Google Analytics