分析MySQL中优化distinct的技巧

 更新时间:2015年05月08日 09:41:15   作者:罗龙九  
这篇文章主要介绍了分析MySQL中优化distinct的技巧,主要是通过减少本地扫描的次数来进行优化的方法,需要的朋友可以参考下

有这样的一个需求:select count(distinct nick) from user_access_xx_xx;

这条sql用于统计用户访问的uv,由于单表的数据量在10G以上,即使在user_access_xx_xx上加上nick的索引,

通过查看执行计划,也为全索引扫描,sql在执行的时候,会对整个服务器带来抖动;

root@db 09:00:12>select count(distinct nick) from user_access;

+———————-+

| count(distinct nick) |

+———————-+

|        806934 |

+———————-+

1 row in set (52.78 sec)

执行一次sql需要花费52.78s,已经非常的慢了

现在需要换一种思路来解决该问题:

我们知道索引的值是按照索引字段升序的,比如我们对(nick,other_column)两个字段做了索引,那么在索引中的则是按照nick,other_column的升序排列:

我们现在的sql:select count(distinct nick) from user_access;则是直接从nick1开始一条条扫描下来,直到扫描到最后一个nick_n,

那么中间过程会扫描很多重复的nick,如果我们能够跳过中间重复的nick,则性能会优化非常多(在oracle中,这种扫描技术为loose index scan,但在5.1的版本中,mysql中还不能直接支持这种优化技术):

20155893909060.jpg (532×255)

所以需要通过改写sql来达到伪loose index scan:

root@db 09:41:30>select count(*) from ( select distinct(nick) from user_access)t ;

| count(*) |

+———-+

|  806934 |

1 row in set (5.81 sec)

Sql中先选出不同的nick,最后在外面套一层,就可以得到nick的distinct值总和;

最重要的是在子查询中:select distinct(nick) 实现了上图中的伪loose index scan,优化器在这个时候的执行计划为Using index for group-by ,

需要注意的是mysql把distinct优化为group by,它首先利用索引来分组,然后扫描索引,对需要的nick只扫描一次;

两个sql的执行计划分别为:

优化写法:

root@db 09:41:10>explain select distinct(nick) from user_access-> ;

+—-+————-+——————————+——-+—————+————-| id | select_type | table            | type | possible_keys | key               | key_len | ref | rows  | Extra          |

+—-+————-+——————————+——-+—————+————-

| 1 | SIMPLE   | user_access | range | NULL     | ind_user_access_nick | 67   | NULL | 2124695 | Using index for group-by |

+—-+————-+——————————+——-+—————+————-

原始写法:

root@db 09:42:55>explain select count(distinct nick) from user_access;

+—-+————-+——————————+——-+—————+————-

| id | select_type | table            | type | possible_keys | key            | key_len | ref | rows   | Extra    |

+—-+————-+——————————+——-+—————+————-

| 1 | SIMPLE   | user_access | index | NULL     | ind_user_access | 177   | NULL | 19546123 | Using index |

相关文章

  • MySQL中Nested-Loop Join算法小结

    MySQL中Nested-Loop Join算法小结

    数据库中JOIN操作的实现主要有三种:嵌套循环连接(Nested Loop Join),归并连接(Merge Join)和散列连接或者哈稀连接(Hash Join)。其中嵌套循环连接又视情况又有两种变形:块嵌套循环连接和索引嵌套循环连接。
    2015-12-12
  • MySQL数据库之字符集 character

    MySQL数据库之字符集 character

    这篇文章主要介绍了MySQL数据库之字符集 character,文章基于MySQL的的相关资料展开详细介绍,具有一定的参考价值需要的小伙伴可以参考一下
    2022-05-05
  • Mysql如何通过binlog日志恢复数据详解

    Mysql如何通过binlog日志恢复数据详解

    binlog日志用于记录所有更新了数据或者已经潜在更新了数据的所有语句,下面这篇文章主要给大家介绍了关于Mysql如何通过binlog日志恢复数据的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2022-02-02
  • Mysql实现递归树查询的使用示例

    Mysql实现递归树查询的使用示例

    Mysql我们可以使用递归查询来构建一个递归树,本文就来介绍一下Mysql实现递归树查询的使用示例,具有一定的参考价值,感兴趣的可以了解一下
    2023-10-10
  • MySQL 数据库两台主机同步实战(linux)

    MySQL 数据库两台主机同步实战(linux)

    MySQL支持单向、异步复制,复制过程中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器。主服务器将更新写入二进制日志文件,并维护日志文件的一个索引以跟踪日志循环。
    2009-04-04
  • MySQL数据库超时设置配置的方法实例

    MySQL数据库超时设置配置的方法实例

    这篇文章主要给大家介绍了关于MySQL数据库超时设置配置的相关资料,通过文中的设置方法可以很好的解决大家遇到的mysql数据库超时问题,需要的朋友可以参考下
    2021-10-10
  • Linux服务器中MySQL远程连接的开启方法

    Linux服务器中MySQL远程连接的开启方法

    今天在Linux服务器上安装了msyql数据库,在本地访问的时候可以访问,但是我想通过远程的方式访问的时候就不能访问了,查询资料后发现,Linux下MySQL默认安装完成后只有本地访问的权限,没有远程访问的权限,需要你给指定用户设置访问权限才能远程访问该数据库
    2017-06-06
  • MySQL普通表如何转换成分区表

    MySQL普通表如何转换成分区表

    分表和表分区的目的就是减少数据库的负担,提高数据库的效率,通常点来讲就是提高表的增删改查效率,下面这篇文章主要给大家介绍了关于MySQL普通表如何转换成分区表的相关资料,需要的朋友可以参考下
    2022-05-05
  • mysql数据库如何导入导出sql文件

    mysql数据库如何导入导出sql文件

    这篇文章主要介绍了mysql数据库如何导入导出sql文件问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • Linux中安装MySQL5.7.42的详细教程

    Linux中安装MySQL5.7.42的详细教程

    这篇文章主要介绍了Linux中安装MySQL5.7.42,本文通过实例图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-09-09

最新评论