域名

MySQL:连Explain的Type类型都没搞清楚,怎敢说精通SQL优化?

字号+作者:益华科技来源:域名2025-11-05 11:33:37我要评论(0)

我们在使用SQL语句查询表数据时,提前用explain进行语句分析是一个非常好的习惯。通过explain输出sql的详细执行信息,就可以针对性的进行sql优化。今天我们来分析一下,在explain中1

我们在使用SQL语句查询表数据时,连类型提前用explain进行语句分析是的都没一个非常好的习惯。通过explain输出sql的搞清详细执行信息,就可以针对性的楚敢进行sql优化。

今天我们来分析一下,说精在explain中11种不同type代表的优化含义以及其应用场景。

1、连类型system

应用场景:表中只有一条数据,的都没且存储引擎可以准确的搞清统计到这条数据。

system一般出现在MyISAM、楚敢memory类型的说精表查询中。

由于我们一般使用的优化存储引擎都是InnoDB,所以system这种类型很少会用到。连类型

2、的都没const

应用场景:通过主键或者唯一索引等值查询来定位一条数据。搞清

比如:select * from test where id = 1。

我们知道,MySQL底层使用B+树来保存数据,其结构大体可类似下图,

那么我们在m字段上创建唯一索引约束,如果想找到m=103的记录,b2b信息网通过二分法只需简单两步就可以定位到m=103。

即100->102->103。

即使对于一张记录很多的真正的业务表,因为B+树矮胖的结构,定位一条唯一索引中的记录,速度也是非常快的。

可以粗略的认为,这种查询速度是常数级的。

所以,MySQL就把这种唯一索引或主键(主键也是一种唯一索引)等值匹配的查询定义为const(常数级)。

需要注意的是,由于唯一索引中允许存在多个null值,所以如果对唯一索引进行null值查询,是没法用const的。

3、eq_ref

应用场景:在进行多表连接查询时,被驱动表通过主键或唯一索引键进行等值查询

比如:SELECT * FROM t1 LEFT JOIN t2 ON t1.id = t2.id。源码库

4、ref

应用场景:普通二级索引等值查询。

比如:select * from t2 where key2 =4。

除了唯一索引,我们更多的会使用普通的二级索引。

由于通过二级索引,可能会查询到多个匹配值,相比const性能差那么一点。

MySQL就把这种类型的查询定义为了ref。

在上面我们说到,由于唯一索引可能存在多个null,所以用不了const。

那对于 select * from t2 where key2 is null 来说,不管是唯一索引还是普通索引,其最多用到ref这种类型。

5、ref_or_null

​应用场景:命中索引时,查询条件除了等值查询,还包含null值查询。

比如:select * from t2 where key2 =4 or key2 is null。

其实看名字就很容易理解,MySQL会在B+树上,找到key2=1和key2 is null 这两种记录范围值,然后拿到主键id去回表查询相关信息。

6、index_merge

应用场景:查询条件可以命中多个索引的情况。

比如:select * from t3 where key1 =3 or key2 =4、WordPress模板

索引合并其实也很好理解,当查询条件可以命中多个索引时,MySQL会尝试在两个索引树查找匹配的条件,然后将结果其合并起来。

7、unique_subquery

应用场景:查询条件包含子查询,并且子查询的列可以进行主键等值匹配。

比如:SELECT * FROM t2 WHERE t2.key2 IN ( SELECT id FROM t3 WHERE t2.key2 = t3.key2 ) OR t2.key2 = 1。

通过查看MySQL优化的执行sql,可以看到MySQL将in子查询优化为了exist语句,并且在主键索引上进行了等值查询。

MySQL优化后的语句:/* select#1 */ select `dbs`.`t2`.`id` AS `id`,`dbs`.`t2`.`key2` AS `key2` from `dbs`.`t2` where (<in_optimizer>(`dbs`.`t2`.`key2`,<exists>(<primary_index_lookup>(<cache>(`dbs`.`t2`.`key2`) in t3 on PRIMARY where ((`dbs`.`t2`.`key2` = `dbs`.`t3`.`key2`) and (<cache>(`dbs`.`t2`.`key2`) = `dbs`.`t3`.`id`))))) or (`dbs`.`t2`.`key2` = 1))。

8、index_subquery

应用场景:查询条件包含子查询,并且子查询的列可以通过索引进行等值匹配。

比如:SELECT * FROM t2 WHERE t2.key2 IN ( SELECT key1 FROM t3 WHERE t2.key2 = t3.key2 ) OR t2.key2 = 1。

index_subquery和unique_subquery的区别在于子查询中的列是唯一索引还是普通的二级索引。

9、range

应用场景:命中索引时,查询某一个范围内的结果。

比如:select * from t3 where t3.key1 >1 and t3.key1<3。

在实际的业务场景中,对某个列进行范围查询还是很常见的需求。

10、index

应用场景:直接在某个索引树上做条件判断,并且不需要回表。

比如:select t3.key1 from t3 where t3.key2 =6。

当我们创建了联合索引idx_key1_key2(key1,key2)时,判断条件key2=6时,其虽然不满足索引的最左前缀原则,但是我们可以遍历idx_key1_key2这颗索引树,找到key2=6的记录即可。

由于查询结果需要的key1在这个联合索引上,也不需要回表,此时就可以使用index。

相对来说,index的性能是比较慢的。

11、all

应用场景:直接遍历整个聚簇索引。

比如: select * from t1。

当MySQL无法通过where条件匹配到合适的索引或者因为全部扫描的代价更小时,MySQL就会选择all这种类型来全表扫描。

这种方式也是最不推荐的。

最后

总得来说,我们在进行查询时,查询类型可分为两大类:全部扫描和索引查询。

索引查询又可以细分:

唯一索引等值查询。普通索引等值查询。普通索引范围查询。扫描整个索引树。

对于一条查询sql来说,不同的查询类型虽然结果可能是一样的,但是其性能却可能天差地别。

不同类型性能从强到差:system > const > eq_ref > ref > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > all。

建议大家在平时书写sql时,多用explain进行分析,尝试去优化代码,只有不断的实践,才能让自己的sql能力越来越强。

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • 印尼硫磺购买攻略(探索印尼硫磺市场的最佳途径)

    印尼硫磺购买攻略(探索印尼硫磺市场的最佳途径)

    2025-11-05 11:02

  • 一条 INSERT 背后的秘密:揭开 InnoDB 记录结构的神秘面纱

    一条 INSERT 背后的秘密:揭开 InnoDB 记录结构的神秘面纱

    2025-11-05 10:02

  • 未来新兴的智能工作场所将如何发展

    未来新兴的智能工作场所将如何发展

    2025-11-05 09:23

  • F5亚太区首席技术官Mohan Veloo:以ADSP平台重构AI时代的应用交付与安全边界,加速释放AI潜能

    F5亚太区首席技术官Mohan Veloo:以ADSP平台重构AI时代的应用交付与安全边界,加速释放AI潜能

    2025-11-05 09:05

网友点评
精彩导读
本文记录配置Linux服务器的初步流程,也就是系统安装完成后,下一步要做的事情。这主要是我自己的总结和备忘,假如有遗漏,欢迎大家补充。下面的操作针对Debian/Ubuntu系统,其他Linux系统也类似,就是部分命令稍有不同。  第一步:root用户登录 首先,使用root用户登录远程主机(假定IP地址是128.199.209.242)。 ssh root@128.199.209.242这时,命令行会出现警告,表示这是一个新的地址,存在安全风险。键入yes,表示接受。然后,就应该可以顺利登入远程主机。接着,修改root用户的密码。 passwd第二步:新建用户 首先,添加一个用户组(这里假定为admin用户组)。 addgroup admin然后,添加一个新用户(假定为bill)。useradd -d /home/bill -s /bin/bash -m bill 上面命令中,参数d指定用户的主目录,参数s指定用户的shell,参数m表示假如该目录不存在,则创建该目录。接着,设置新用户的密码。 passwd bill 将新用户(bill)添加到用户组(admin)。usermod -a -G admin bill 接着,为新用户设定sudo权限。visudovisudo命令会打开sudo设置文件/etc/sudoers,找到下面这一行。root    ALL=(ALL:ALL) ALL在这一行的下面,再添加一行。root    ALL=(ALL:ALL) ALLbill    ALL=(ALL) NOPASSWD: ALL上面的NOPASSWD表示,切换sudo的时候,不需要输入密码,我喜欢这样比较省事。假如出于安全考虑,也可以强制要求输入密码。root    ALL=(ALL:ALL) ALLbill    ALL=(ALL:ALL) ALL然后,先退出root用户的登录,再用新用户的身份登录,检查到这一步为止,是否一切正常。exitssh bill@128.199.209.242第三步:SSH设置 首先,确定本机有SSH公钥(一般是文件~/.ssh/id_rsa.pub),假如没有的话,使用ssh-keygen命令生成一个(可参考我写的SSH教程)。 在本机上另开一个shell窗口,将本机的公钥拷贝到服务器的authorized_keys文件。 cat ~/.ssh/id_rsa.pub | ssh bill@128.199.209.242 mkdir -p .ssh && cat - >>~/.ssh/authorized_keys# 或者在服务器端,运行下面命令echo ssh-rsa [your public key] >~/.ssh/authorized_keys然后,进入服务器,编辑SSH配置文件/etc/ssh/sshd_config。sudo cp /etc/ssh/sshd_config ~sudo nano /etc/ssh/sshd_config在配置文件中,将SSH的默认端口22改掉,可以改成从1025到65536之间的任意一个整数(这里假定为25000)。Port 25000然后,检查几个设置是否设成下面这样,确保去除前面的#号。Protocol 2PermitRootLogin noPermitEmptyPasswords noPasswordAuthentication noRSAAuthentication yesPubkeyAuthentication yesAuthorizedKeysFile .ssh/authorized_keysUseDNS no上面主要是禁止root用户登录,以及禁止用密码方式登录。接着,在配置文件的末尾,指定允许登陆的用户。 AllowUsers bill保存后,退出文件编辑。接着,改变authorized_keys文件的权限。 sudo chmod 600 ~/.ssh/authorized_keys && chmod 700 ~/.ssh/然后,重启SSHD。sudo service ssh restart# 或者sudo /etc/init.d/ssh restart下面的一步是可选的。在本机~/.ssh文件夹下创建config文件,内容如下。Host s1HostName 128.199.209.242User billPort 25000最后,在本机另开一个shell窗口,测试SSH能否顺利登录。ssh s1第四步:运行环境配置 首先,检查服务器的区域设置。 locale假如结果不是en_US.UTF-8,建议都设成它。sudo locale-gen en_US en_US.UTF-8 en_CA.UTF-8sudo dpkg-reconfigure locales然后,更新软件。sudo apt-get updatesudo apt-get upgrade最后,再根据需要,做一些安全设置,比如搭建防火墙,关闭HTTP、HTTPs、SSH以外的端口,这里就不一一介绍了,谢谢阅读,希望能帮到大家,请继续关注脚本之家,我们会努力分享更多优秀的文章。

本文记录配置Linux服务器的初步流程,也就是系统安装完成后,下一步要做的事情。这主要是我自己的总结和备忘,假如有遗漏,欢迎大家补充。下面的操作针对Debian/Ubuntu系统,其他Linux系统也类似,就是部分命令稍有不同。 第一步:root用户登录 首先,使用root用户登录远程主机(假定IP地址是128.199.209.242)。 ssh root@128.199.209.242这时,命令行会出现警告,表示这是一个新的地址,存在安全风险。键入yes,表示接受。然后,就应该可以顺利登入远程主机。接着,修改root用户的密码。 passwd第二步:新建用户 首先,添加一个用户组(这里假定为admin用户组)。 addgroup admin然后,添加一个新用户(假定为bill)。useradd -d /home/bill -s /bin/bash -m bill 上面命令中,参数d指定用户的主目录,参数s指定用户的shell,参数m表示假如该目录不存在,则创建该目录。接着,设置新用户的密码。 passwd bill 将新用户(bill)添加到用户组(admin)。usermod -a -G admin bill 接着,为新用户设定sudo权限。visudovisudo命令会打开sudo设置文件/etc/sudoers,找到下面这一行。root ALL=(ALL:ALL) ALL在这一行的下面,再添加一行。root ALL=(ALL:ALL) ALLbill ALL=(ALL) NOPASSWD: ALL上面的NOPASSWD表示,切换sudo的时候,不需要输入密码,我喜欢这样比较省事。假如出于安全考虑,也可以强制要求输入密码。root ALL=(ALL:ALL) ALLbill ALL=(ALL:ALL) ALL然后,先退出root用户的登录,再用新用户的身份登录,检查到这一步为止,是否一切正常。exitssh bill@128.199.209.242第三步:SSH设置 首先,确定本机有SSH公钥(一般是文件~/.ssh/id_rsa.pub),假如没有的话,使用ssh-keygen命令生成一个(可参考我写的SSH教程)。 在本机上另开一个shell窗口,将本机的公钥拷贝到服务器的authorized_keys文件。 cat ~/.ssh/id_rsa.pub | ssh bill@128.199.209.242 mkdir -p .ssh && cat - >>~/.ssh/authorized_keys# 或者在服务器端,运行下面命令echo ssh-rsa [your public key] >~/.ssh/authorized_keys然后,进入服务器,编辑SSH配置文件/etc/ssh/sshd_config。sudo cp /etc/ssh/sshd_config ~sudo nano /etc/ssh/sshd_config在配置文件中,将SSH的默认端口22改掉,可以改成从1025到65536之间的任意一个整数(这里假定为25000)。Port 25000然后,检查几个设置是否设成下面这样,确保去除前面的#号。Protocol 2PermitRootLogin noPermitEmptyPasswords noPasswordAuthentication noRSAAuthentication yesPubkeyAuthentication yesAuthorizedKeysFile .ssh/authorized_keysUseDNS no上面主要是禁止root用户登录,以及禁止用密码方式登录。接着,在配置文件的末尾,指定允许登陆的用户。 AllowUsers bill保存后,退出文件编辑。接着,改变authorized_keys文件的权限。 sudo chmod 600 ~/.ssh/authorized_keys && chmod 700 ~/.ssh/然后,重启SSHD。sudo service ssh restart# 或者sudo /etc/init.d/ssh restart下面的一步是可选的。在本机~/.ssh文件夹下创建config文件,内容如下。Host s1HostName 128.199.209.242User billPort 25000最后,在本机另开一个shell窗口,测试SSH能否顺利登录。ssh s1第四步:运行环境配置 首先,检查服务器的区域设置。 locale假如结果不是en_US.UTF-8,建议都设成它。sudo locale-gen en_US en_US.UTF-8 en_CA.UTF-8sudo dpkg-reconfigure locales然后,更新软件。sudo apt-get updatesudo apt-get upgrade最后,再根据需要,做一些安全设置,比如搭建防火墙,关闭HTTP、HTTPs、SSH以外的端口,这里就不一一介绍了,谢谢阅读,希望能帮到大家,请继续关注脚本之家,我们会努力分享更多优秀的文章。