Mysql高级2

x33g5p2x  于2021-11-21 转载在 Mysql  
字(6.2k)|赞(0)|评价(0)|浏览(438)

Mysql的体系结构概览

1) 连接层

最上层是一些客户端和链接服务,包含本地sock 通信和大多数基于客户端/服务端工具实现的类似于 TCP/IP的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程池的概念,为通过认证安全接入的客户端提供线程。同样在该层上可以实现基于SSL的安全链接。服务器也会为安全接入的每个客户端验证它所具有的操作权限。

2) 服务层

第二层架构主要完成大多数的核心服务功能,如SQL接口,并完成缓存的查询,SQL的分析和优化,部分内置函数的执行。所有跨存储引擎的功能也在这一层实现,如 过程、函数等。在该层,服务器会解析查询并创建相应的内部解析树,并对其完成相应的优化如确定表的查询的顺序,是否利用索引等, 最后生成相应的执行操作。如果是select语句,服务器还会查询内部的缓存,如果缓存空间足够大,这样在解决大量读操作的环境中能够很好的提升系统的性能。

3) 引擎层

存储引擎层, 存储引擎真正的负责了MySQL中数据的存储和提取,服务器通过API和存储引擎进行通信。不同的存储引擎具有不同的功能,这样我们可以根据自己的需要,来选取合适的存储引擎。

4)存储层

数据存储层, 主要是将数据存储在文件系统之上,并完成与存储引擎的交互。

存储引擎

和大多数的数据库不同, Oracle,SqlServer等数据库只有一种存储引擎,MySQL提供了插件式的存储引擎架构。

存储引擎就是存储数据,建立索引,更新查询数据等等技术的实现方式 。存储引擎是基于表的,而不是基于库的。所以存储引擎也可被称为表类型。

InnoDB

InnoDB存储引擎是Mysql的默认存储引擎。InnoDB存储引擎提供了具有提交、回滚、崩溃恢复能力的事务安全。
但是对比MyISAM的存储引擎,InnoDB写的处理效率差一些,并且会占用更多的磁盘空间以保留数据和索引。

InnoDB 存储表和索引有以下两种方式 :

①. 使用共享表空间存储, 这种方式创建的表的表结构保存在.frm文件中, 数据和索引保存在 innodb_data_home_dir 和 innodb_data_file_path定义的表空间中,可以是多个文件。

②. 使用多表空间存储, 这种方式创建的表的表结构仍然存在 .frm 文件中,但是每个表的数据和索引单独保存在 .ibd 中

MyISAM

MyISAM 不支持事务、也不支持外键,其优势是访问的速度快,对事务的完整性没有要求或者以SELECT、INSERT为主的应用基本上都可以使用这个引擎来创建表 。

存储方式

每个MyISAM在磁盘上存储成3个文件,其文件名都和表名相同,但拓展名分别是 :

.frm (存储表定义);

.MYD(MYData , 存储数据);

.MYI(MYIndex , 存储索引);

MEMORY

Memory存储引擎将表的数据存放在内存中。每个MEMORY表实际对应一个磁盘文件,格式是.frm ,该文件中只存储表的结构,而其数据文件,都是存储在内存中,这样有利于数据的快速处理,提高整个表的效率。MEMORY 类型的表访问非常地快,因为他的数据是存放在内存中的,并且默认使用HASH索引 , 但是服务一旦关闭,表中的数据就会丢失。

MERGE

MERGE存储引擎是一组MyISAM表的组合,这些MyISAM表必须结构完全相同,MERGE表本身并没有存储数据,对MERGE类型的表可以进行查询、更新、删除操作,这些操作实际上是对内部的MyISAM表进行的。

相当于视图(将两张表合并显示)

存储引擎的选择

InnoDB : 是Mysql的默认存储引擎,用于事务处理应用程序,支持外键。如果应用对事务的完整性有比较高的要求,在并发条件下要求数据的一致性,数据操作除了插入和查询意外,还包含很多的更新、删除操作,那么InnoDB存储引擎是比较合适的选择。InnoDB存储引擎除了有效的降低由于删除和更新导致的锁定, 还可以确保事务的完整提交和回滚,对于类似于计费系统或者财务系统等对数据准确性要求比较高的系统,InnoDB是最合适的选择。

MyISAM : 如果应用是以读操作和插入操作为主,只有很少的更新和删除操作,并且对事务的完整性、并发性要求不是很高,那么选择这个存储引擎是非常合适的。

MEMORY:将所有数据保存在RAM中,在需要快速定位记录和其他类似数据环境下,可以提供几块的访问。MEMORY的缺陷就是对表的大小有限制,太大的表无法缓存在内存中,其次是要确保表的数据可以恢复,数据库异常终止后表中的数据是可以恢复的。MEMORY表通常用于更新不太频繁的小表,用以快速得到访问结果。

MERGE:用于将一系列等同的MyISAM表以逻辑方式组合在一起,并作为一个对象引用他们。MERGE表的优点在于可以突破对单个MyISAM表的大小限制,并且通过将不同的表分布在多个磁盘上,可以有效的改善MERGE表的访问效率。这对于存储诸如数据仓储等VLDB环境十分合适。

优化SQL步骤

随着生产数据量的急剧增长,很多 SQL 语句开始逐渐显露出性能问题,对生产的影响也越来越大,此时这些有问题的 SQL 语句就成为整个系统性能的瓶颈,因此我们必须要对它们进行优化。

1.查看SQL执行频率

MySQL 客户端连接成功后,通过 show [session|global] status 命令可以提供服务器状态信息。
“session”或者“global”来显示 session 级(当前连接)的计结果和 global 级(自数据库上次启动至今)的统计结果

show status like 'Com_______';//7个占位符_  
//Com_***      :  这些参数对于所有存储引擎的表操作都会进行累计。
show status like 'Innodb_rows_%';
//Innodb_*** :  这几个参数只是针对InnoDB 存储引擎的,累加的算法也略有不同。

2.定位低效率执行SQL

通过以下两种方式定位执行效率较低的 SQL 语句

  • 慢查询日志 : 通过慢查询日志定位那些执行效率较低的 SQL 语句,用–log-slow-queries[=file_name]选项启动时,mysqld 写一个包含所有执行时间超过 long_query_time 秒的 SQL 语句的日志文件。
  • show processlist : 慢查询日志在查询结束以后才纪录,所以在应用反映执行效率出现问题的时候查询慢查询日志并不能定位问题,可以使用show processlist命令查看当前MySQL在进行的线程,包括线程的状态、是否锁表等,可以实时地查看 SQL 的执行情况,同时对一些锁表操作进行优化。

3.explain分析执行计划

可以通过 EXPLAIN或者 DESC命令获取 MySQL如何执行 SELECT 语句的信息

1.explain 之 id:

1) id 相同时,表示加载表的顺序是从上到下
2) id 不同时,id值越大,优先级越高,越先被执行

2.explain 之 select_type:

3.explain 之 table

展示这一行的数据是关于哪一张表的

4.explain 之 type

5.explain 之 key

possible_keys : 显示可能应用在这张表的索引, 一个或多个。 
key : 实际使用的索引, 如果为NULL, 则没有使用索引。
key_len : 表示索引中使用的字节数, 该值为索引字段最大可能长度,并非实际使用长度,在不损失精确性的前提下, 长度越短越好 。

6.explain 之 rows

扫描行的数量

7.explain 之 extra

4.show profile分析SQL

show profiles 能够在做SQL优化时帮助我们了解时间都耗费到哪里去了。

通过 have_profiling 参数,能够看到当前MySQL是否支持profile:

默认profiling是关闭的,可以通过set语句在Session级别开启profiling:

set profiling=1; //开启profiling 开关;

执行show profiles 指令, 来查看SQL语句执行的耗时.

通过show profile for query query_id 语句可以查看到该SQL执行过程中每个线程的状态和消耗的时间.

Tip:
Sending data 状态表示MySQL线程开始访问数据行并把结果返回给客户端,而不仅仅是返回个客户端。由于在Sending data状态下,MySQL线程往往需要做大量的磁盘读取操作,所以经常是整各查询中耗时最长的状态。

5.trace分析优化器执行计划

MySQL5.6提供了对SQL的跟踪trace, 通过trace文件能够进一步了解为什么优化器选择A计划, 而不是选择B计划

索引的使用

索引是数据库优化最常用也是最重要的手段之一, 通过索引通常可以帮助用户解决大多数的MySQL的性能优化问题。

避免索引失效

1). 全值匹配 ,对索引中所有列都指定具体值。
该情况下,索引生效,执行效率高。就是查询条件按照索引来查的

2). 最左前缀法则
如果索引了多列,要遵守最左前缀法则。指的是查询从索引的最左前列开始,并且不跳过索引中的列。
如果符合最左法则,但是出现跳跃某一列,只有最左列索引生效

3). 范围查询右边的列,索引失效 。

4). 不要在索引列上进行运算操作, 索引将失效。

5). 字符串不加单引号,造成索引失效。
只要是varchar类型的都要加上单引号,虽然不加也能查出来

6). 尽量使用覆盖索引查询,避免select *
如果查询列,超出索引列,也会降低性能。(看extra)

TIP : 

using index :使用覆盖索引的时候就会出现

using where:在查找使用索引的情况下,需要回表去查询所需的数据

using index condition:查找使用了索引,但是需要回表查询数据

using index ; using where:查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询数据

7). 用or分割开的条件, 如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到

8). 以%开头的Like模糊查询,索引失效。
如果仅仅是尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引失效

解决方案 : 通过覆盖索引来解决

9). 如果MySQL评估使用索引比全表更慢,则不使用索引。
当一列大多数是相同的值的时候,在查询的时候会自动全表搜索

10). is NULL , is NOT NULL 有时索引失效。
跟上面差不多,看谁占的多

11). in 走索引, not in 索引失效。

12). 单列索引和复合索引。
尽量使用复合索引,而少使用单列索引
写一条就相当于创建了多个索引

SQL优化

1.大批量插入数据
对于 InnoDB 类型的表,有以下几种方式可以提高导入的效率

1) 主键顺序插入

因为InnoDB类型的表是按照主键的顺序保存的,所以将导入的数据按照主键的顺序排列,可以有效的提高导入数据的效率。如果InnoDB表没有主键,那么系统会自动默认创建一个内部列作为主键,所以如果可以给表创建一个主键,将可以利用这点,来提高导入数据的效率。

2) 关闭唯一性校验

在导入数据前执行 SET UNIQUE_CHECKS=0,关闭唯一性校验,在导入结束后执行SET UNIQUE_CHECKS=1,恢复唯一性校验,可以提高导入的效率。

3) 手动提交事务

如果应用使用自动提交的方式,建议在导入前执行 SET AUTOCOMMIT=0,关闭自动提交,导入结束后再执行 SET AUTOCOMMIT=1,打开自动提交,也可以提高导入的效率。

2.优化insert语句

1).多值插入

如果需要同时对一张表插入很多行数据时,应该尽量使用多个值表的insert语句,这种方式将大大的缩减客户端与数据库之间的连接、关闭等消耗。使得效率比分开执行的单个insert语句快。

2).在事务中进行数据插入

3).数据有序插入

3.优化order by语句

1.两种排序方式:

1). 第一种是通过对返回数据进行排序,也就是通常说的 filesort 排序,所有不是通过索引直接返回排序结果的排序都叫 FileSort 排序。
2). 第二种通过有序索引顺序扫描直接返回有序数据,这种情况即为 using index,不需要额外排序,操作效率高。

尽量减少额外的排序,通过索引直接返回有序数据。where 条件和Order by 使用相同的索引,并且Order By 的顺序和索引顺序相同, 并且Order by 的字段都是升序,或者都是降序。否则肯定需要额外的操作,这样就会出现FileSort(耗时较长)。

2.Filesort 的优化:

通过创建合适的索引,能够减少 Filesort 的出现,但是在某些情况下,条件限制不能让Filesort消失,那就需要加快 Filesort的排序操作。对于Filesort , MySQL 有两种排序算法

1)两次扫描算法:先根据条件取出排序字段和行指针信息,然后在排序区 sort buffer 中排序,如果sort buffer不够,则在临时表 temporary table 中存储排序结果。完成排序之后,再根据行指针回表读取记录,该操作可能会导致大量随机I/O操作。
2)一次扫描算法:一次性取出满足条件的所有字段,然后在排序区 sort  buffer 中排序后直接输出结果集。排序时内存开销较大,但是排序效率比两次扫描算法要高。

MySQL 通过比较系统变量 max_length_for_sort_data 的大小和Query语句取出的字段总大小, 来判定是否那种排序算法,如果max_length_for_sort_data 更大,那么使用第二种优化之后的算法;否则使用第一种。

可以适当提高 sort_buffer_size 和 max_length_for_sort_data 系统变量,来增大排序区的大小,提高排序的效率

4.优化group by 语句

由于GROUP BY 实际上也同样会进行排序操作,而且与ORDER BY 相比,GROUP BY 主要只是多了排序之后的分组操作.

如果查询包含 group by 但是用户想要避免排序结果的消耗, 则可以执行order by null 禁止排序。

5.优化嵌套查询

有些情况下,子查询是可以被更高效的连接(JOIN)替代。
连接(Join)查询之所以更有效率一些 ,是因为MySQL不需要在内存中创建临时表来完成这个逻辑上需要两个步骤的查询工作

6.优化OR条件

对于包含OR的查询子句,如果要利用索引,则OR之间的每个条件列都必须用到索引 , 而且不能使用到复合索引; 如果没有索引,则应该考虑增加索引。

建议使用 union 替换 or :

UNION 语句的 type 值为 ref,OR 语句的 type 值为 range,可以看到这是一个很明显的差距

UNION 语句的 ref 值为 const,OR 语句的 type 值为 null,const 表示是常量值引用,非常快

这两项的差距就说明了 UNION 要优于 OR 。

7.优化分页查询

一般分页查询时,通过创建覆盖索引能够比较好地提高性能。一个常见又非常头疼的问题就是 limit 2000000,10 ,此时需要MySQL排序前2000010 记录,仅仅返回2000000 - 2000010 的记录,其他记录丢弃,查询排序的代价非常大 。

优化思路一:
在索引上完成排序分页操作,最后根据主键关联回原表查询所需要的其他列内容(先按照索引排序那一页的数据)

优化思路二:
该方案适用于主键自增的表且不能断层?,可以把Limit 查询转换成某个位置的查询

8.使用SQL提示

在from 表后加上
USE INDEX
IGNORE INDEX
FORCE INDEX

相关文章