从零开始java数据库SQL优化(一):一篇解决MYSQL查询优化总纲

目录

目录

一:问题场景

二:优化

1.查询计划 

2.分析计划

 连接类型

三:索引的使用与选择

1.索引的使用以及优化

(1) MYSQL中的索引原理

(2) 4中树结构在索引中的应用(附红黑树)

2、树结构选择合适的索引。

3、mysql中建立索引的规范

4、mysql的索引分类以及使用场景

(1)索引的总分类

(2)Mysql中的索引

 (3)、建立合适索引,避免滥用索引。

四:优化SQL减低查询时间

1.使用limit关键字

2.添加合适的索引

3.避免全表查询

五:SQL优化建议

1.SQL从程序中查询到程序显示结果的过程

2.SQL层级优化



一:问题场景

  在一次项目中,出现一个SQL优化问题,问题场景就是,在用户登陆时,将用户的部门、岗位、角色以及权限(其中权限整合在菜单表中,每2个表都是用一个中间表关联)查询出来作为一个全局常量(MSYQL数据库)。

  不多说,直接上SQL语句吧。

SELECT 
			a.fk_user_id AS "fk_user_id",
			a.user_realname AS "user_realname",
			a.user_name AS "user_name",
			a.user_type AS "user_type",
			a.sex AS "sex",
			a.phone AS "phone",
			a.password AS "password",
			a.user_addr AS "user_addr",
			a.avater AS "avater",
			a.status AS "status",
			
			
			
			fr.role_id as role_id,
			fr.role_code as role_code,
			fr.role_name as role_name,
			fr.role_range as role_range,
			
			
			fd.dept_id as dept_id,
			fd.dept_name as dept_name,
			fd.parent_id     as dept_parent,
			fd.parent_ids     as dept_parents,
			fd.company_name as company_name, 
			 
			fp.post_id as post_id,
			fp.post_name as post_name,
			fp.post_split as post_split,
			
			m.perms as perms
			
			FROM fk_user a
		 	LEFT JOIN fk_user_role fkur ON fkur.user_id = a.fk_user_id
			LEFT JOIN fk_role fr ON fr.role_id = fkur.role_id
			LEFT JOIN fk_role_menu rm ON rm.role_id = fr.role_id
			LEFT JOIN fk_menu m ON m.menu_id = rm.menu_id
	
			LEFT JOIN fk_dept fd ON fd.dept_id = a.dept_id
			LEFT JOIN fk_user_post fup ON fup.user_id = a.fk_user_id
			LEFT JOIN fk_post fp ON fp.post_id = fup.post_id

 where a.user_name ='admin'  

  在使用本地数据库连接(localhost:3306)基本查询就消耗了0.270s左右。见下图:

从零开始java数据库SQL优化(一):一篇解决MYSQL查询优化总纲_第1张图片

二:优化

1.查询计划 

   很尴尬,实际上查询的几张表数据一共也就在250条左右(其中菜单表和角色菜单表大概在160条),这里我们再来看一下SQL的查询计划统计:

从零开始java数据库SQL优化(一):一篇解决MYSQL查询优化总纲_第2张图片

2.分析计划

  其中,我们看type一行的查询涉及到3个名词:ALL,ref,eq_ref。Type学名为连接类型,连接类型决定查询时间。

 连接类型

  ALL:全表扫描,最耗时的查询,即使在查询出符合条件的数据,还要继续查询其余剩下的数据。(在本例场景中实际代码

              已经控制了用户名唯一,那么在查询出该用户就应该停止继续往下查询,但是如果要查询所有的用户则查询类型肯定

              是ALL)。

INDEX: 加索引的全表查询,比较耗时的一种查询,就是在查询字段上添加一个索引。众所周知Mysql中的索引结构为B+树。在

              同等数据结构中,B+数据的时间复杂度为  log(2)n优化程度仅次于1,降低了树高(即查询表列的行数减少了),常见

              的索引优化就是讲表数据按照b+树排列,较少全表查询的实际行数。

RANGE:范围搜索,可以看出在是将查询数据行数按照一定的条件控制,减少实际查询行数(一定是基于索引)。常见得IN,

             BETWEEN等都是这种类型。

REF:  单条件不限查询。简而言之,就是将查询放在一定的范围内查询,允许重复查询(这里区别于全表在于使用的索引,虽然

          不是唯一索引)。

REF_EQ:单条件唯一查询。与上面不同的是,我们知道查询结果唯一,在查询出结果就不在继续查询了,所以时间程度 <= REF

CONST: 主键条件查询。将主键放在where条件之后,会别MYSQL优化器存储为一个常量。

三:索引的使用与选择

1.索引的使用以及优化

  在上面分析可知,除了ALL没有用到索引,其他所有的类型都用到了索引。那么我们就先来看看mysql中的索引。

(1) MYSQL中的索引原理

  在Mysql5.7+,Mysql默认的存储引擎为InnoDB。该引擎有2中索引:B+树索引以及哈希索引,其中哈希索引是Mysql更具表的使用情况自动创建的,无法人为干涉。

(2) 4中树结构在索引中的应用(附红黑树)

  在上面,我们说到InnoDB默认为B+树,其实在索引中同期的树结构还有B树,B-树,B*树,下面我们就谈谈几种树结构的特性。

 B树:又称 二叉树结构。每一个节点拥有2个子节点,大于该节点走右节点,小于该节点做左边。如图所示:

              从零开始java数据库SQL优化(一):一篇解决MYSQL查询优化总纲_第3张图片                                   从零开始java数据库SQL优化(一):一篇解决MYSQL查询优化总纲_第4张图片

             通过图形我们可以看出3层树结构存储7个数据(图中为了方便看,第三层省了一个)。查询一次 最多走3层树,效率明显提高(可以看出其实存储的是数  字的情况下比较好比较,这也是为什么我们有时候强调分 布式环境中最好不要使用UUID作为主键的原因)。 b树的时间复杂度 O(logN)

B-树:多链路查找树结构。每一个节点拥有>2个子节点。通过二分法查询找到左右2个关键字然后去中间查询。如图

        从零开始java数据库SQL优化(一):一篇解决MYSQL查询优化总纲_第5张图片

   如图,如果我们需要查询E这个节点。首先确定E在DG中,但是又不是D和G,因此我们取DG中间节点去查询。在这里我们看到3层树结构存储了至少17个关键字。但是吧,不一定说明其效率高于B树,毕竟谁也说不清在去中间结构判断消耗的时间。

B+树:多链路近似二分法。B+树在每一个连接节点不会存储节点指针只存储节点关键字,每一个非连接子节点存储根节点和对应连接节点的数据。 B+树的时间复杂度为  log(M-1)N~log(M/2)N

         从零开始java数据库SQL优化(一):一篇解决MYSQL查询优化总纲_第6张图片

  实际上,B+树就是将对应链路数据下沉下沉到最后一层,链路上的其他只记录关键字,不记录对应的指针信息等。因此,在B+树查询中效率接近二分法而且比B+效率高。

B*树: b+树的变种,允许同级关键字可以向相邻的兄弟节点上放。简而言之,b+树的每一个节点存放的关键字容量有限,点满本节点就必须裂变出子节点。而B*树,在本节点点满后,可以问同层左右未满的节点存放,充分利用了空间。(但是b*树每一个节点的容量小于b+树)

               从零开始java数据库SQL优化(一):一篇解决MYSQL查询优化总纲_第7张图片

 毋庸置疑,B*树查询效率接近B+树,但是在同级别上,其空间利用率很高。当然,如果B+树在每一个节点存放数据相同,B+树层级一定<=B*树。

附:红黑树,

  红黑树也是一种多链路树结构,每一条链路都是红黑相间,根节点为黑色。每一个子节点必然为2个即使为NULL也是需要该节点而且必为黑色。

 从零开始java数据库SQL优化(一):一篇解决MYSQL查询优化总纲_第8张图片

  红黑树的时间复杂度为:O(lgn)。

 

2、树结构选择合适的索引。

  上面我们分析几种树结构,那么分析完了有什么作用呢?通过对应数据库的树结构,合理的设计表结构。比如Mysql的InnoDB的默认为B+树,那么在设计表结构时就应该往这个方面靠。

3、mysql中建立索引的规范

  (1)命名规范:表名_字段名,需要加索引的字段,要在where条件中,数据量少的字段不需要加索引,如果where条件中是

                               OR关系,加索引不起作用,符合最左原则。

   (2)约束规范:索引中Index和key。其中Key是数据库中的物理结构,即是约束,约束结构完整性,同时也是索引,包含外检

                                  等。而Index则是数据库的虚拟结构,只负责实现辅助查询,他创建时会在表空间创建虚拟目录以助辅助。

 

4、mysql的索引分类以及使用场景

  这里,我们不谈如何去创建索引,只谈所有哪些?如何在合适的场景选择合适的索引。

(1)索引的总分类

  索引分为聚簇和非聚簇索引。

聚簇索引:按照表行物理排序为顺序的,其多行索引查询的速度很快。(暂戏称为全文索引吧)

非聚簇索引:按照表字段顺序为顺序的(也就是说这是针对单行数据),其单行查询书读很快。

 

(2)Mysql中的索引

普通索引:  没有任何约束的索引,一般添加在常用的查询字段上。比如我们在存储文章到数据库中,其中标题为一个字段且这

                     个字段会被经常查询,那么就可以在该字段上添加一个索引。(当然这里只是举一个不合适的例子,一般针对文

                     章的存储不会放入Mysql数据库中,而是放入对应的搜索索引中的。)

 

唯一索引:  这个索引在普通索引上添加一个约束,当查询到该条数据时,查询就会停止然后返回结果。比如,在用户表中查询

                     用户名就可以在该字段上添加一个唯一索引。毕竟多数的代码设计都是保证了用户名唯一,不唯一当我没说。

 

全文索引:  在Mysql3.23+就支持了全文索引,当然这个索引目前只适用于Mysam并且在数据量特别大的情况下,生成全文索引

                    速度特别慢。

 

组合索引: 多个字段同时且多用查询时,建立查询。比如用户表中的用户名和密码这俩个字段,在登录时一定会诶查询,那么

                     我们针对username和pwd建立索引,最后生成username+pwd 和  pwd 2个索引,遵循最左原则。

 

 (3)、建立合适索引,避免滥用索引。

    在上面我们谈到索引建立的好处,但是索引并不是越多越好,索引的乱建会导致Mysql服务性能下降严重时会导致服务崩溃。

原因在于一个索引字段在新增/修改/删除,会在操作数据时 新增/修改/删除 索引目录。

 

四:优化SQL减低查询时间

  在上面我们谈到了除了ALL之外,所有的类型的查询都用了索引,因此我们对索引进行讲解。现在我们回归优化SQL降低查询类型提高查询效率。(这里提供以下MYSQL的SQL语句性能分析文章)

1.使用limit关键字

   limit关键字在很大方面控制Send_data的时长。具体可看这篇从零开始java数据库SQL优化(番外):SQL执行性能分析。

 

2.添加合适的索引

  在对应的字段上添加合适的索引

从零开始java数据库SQL优化(一):一篇解决MYSQL查询优化总纲_第9张图片

3.避免全表查询

  也就是避免Type = ALL

 

五:SQL优化建议

1.SQL从程序中查询到程序显示结果的过程

  (1)ORM框架解析参数,封装成SQL语句

  (2)MYSQL接收到SQL语句,进行优化器编译

 (3)执行SQL语句,将数据从I/O磁盘读取到内存中

 (4)从带村中读取数据

 

2.SQL层级优化

  (1)ORM框架解析从参数,封装SQL,这里离说实话没办法,现在ORM开源框架如Mybatis等都已经封装好

  (2)MYSQL-SERVER解析编译。

           解析过程,通过解析SQL参数,封装可查询的语句。这里其实对于一些where条件以及决定查询Type都是这个过程决定的

                               因此,避免全表查询的优化就在这一步。

          编译过程,解析完成,开始对执行语句进行编译。这里可以优化,可以预编译SQL语句,比如添加视图,临时表或者存储过

                            程等让其直接执行预编译好的语句。

(3)I/O磁盘读取到内存中,这里优化就是索引级别的了,可以添加索引,即目录索引配合SQL查询

(4)内存读取数据,这个没办法ORM框架已经封装好,顶多网络优化。

 

 

 

 

 

你可能感兴趣的:(从零开始)