MySQL(逻辑分层,存储引擎,sql优化,索引优化以及底层实现(B+Tree))

一 , 逻辑分层  

链接层:链接与线程处理,这一层并非MySQL独有,通常的基于C/S架构的都有相似组件,好比链接处理、受权认证、安全等。mysql

服务层:包括缓存查询、解析器、优化器,这一部分是MySQL核心功能,包括解析、优化SQL语句,查询缓存目录,内置函数(日期、时间、加密等函数)的实现。算法

引擎层:负责数据存储,存储引擎的不一样,存储方式、数据格式、提取方式等都不相同,这一部分也是很大影响数据存储与提取的性能的;对存储层的抽象。sql

存储层:存储数据,文件系统。数据库

二 , 存储引擎缓存

查看数据库支持的存储引擎:show engines;安全

若是要想查看数据库默认使用哪一个引擎,能够经过使用命令: show variables like '%storage_engine%';架构

指定数据库对象的引擎:并发

create table tb(
id int(4) auto_increment ,
name varchar(5),
dept varchar(5) ,
primary key(id)
)ENGINE=MyISAM AUTO_INCREMENT=1
DEFAULT CHARSET=utf8 ;

查看建表语句:show create table default_table;数据库设计

MySQL 存储引擎 MyISAM 与 InnoDB 如何选择?

虽然 MySQL 里的存储引擎不仅是 MyISAM 与 InnoDB 这两个,但经常使用的就是它俩了。可能有站长并未注意过 MySQL 的存储引擎,其实存储引擎也是数据库设计里的一大重要点,那么博客系统应该使用哪一种存储引擎呢?函数

下面咱们分别来看两种存储引擎的区别。

  • 1、InnoDB支持事务,MyISAM不支持,这一点是很是之重要。事务是一种高级的处理方式,如在一些列增删改中只要哪一个出错还能够回滚还原,而MyISAM就不能够了。
  • 2、MyISAM适合查询以及插入为主的应用,InnoDB适合频繁修改以及涉及到安全性较高的应用
  • 3、InnoDB支持外键,MyISAM不支持
  • 4、MyISAM是默认引擎,InnoDB须要指定
  • 5、InnoDB不支持FULLTEXT类型的索引
  • 6、InnoDB中不保存表的行数,如select count(*) from table时,InnoDB须要扫描一遍整个表来计算有多少行,可是MyISAM只要简单的读出保存好的行数便可。注意的是,当count(*)语句包含where条件时MyISAM也须要扫描整个表
  • 7、对于自增加的字段,InnoDB中必须包含只有该字段的索引,可是在MyISAM表中能够和其余字段一块儿创建联合索引
  • 8、清空整个表时,InnoDB是一行一行的删除,效率很是慢。MyISAM则会重建表
  • 9、InnoDB支持行锁(某些状况下仍是锁整表,如 update table set a=1 where user like '%lee%'

经过以上九点区别,结合我的博客的特色,推荐我的博客系统使用MyISAM,由于在博客里主要操做是读取和写入,不多有链式操做。因此选择MyISAM引擎使你博客打开也页面的效率要高于InnoDB引擎的博客,固然只是我的的建议,大多数博客仍是根据实际状况下谨慎选择。

三, sql优化

3.1.1  mysql 内部实现索引原理(B+Tree)

3.1.1.1 ,  二叉树

      

3.1.1.2 ,  B-Tree        

 B-Tree中的每一个节点根据实际状况能够包含大量的关键字信息和分支,以下图所示为一个3阶的B-Tree: 
        

每一个节点占用一个盘块的磁盘空间,一个节点上有两个升序排序的关键字和三个指向子树根节点的指针,指针存储的是子节点所在磁盘块的地址。两个关键词划分红的三个范围域对应三个指针指向的子树的数据的范围域。以根节点为例,关键字为17和35,P1指针指向的子树的数据范围为小于17,P2指针指向的子树的数据范围为17~35,P3指针指向的子树的数据范围为大于35。

模拟查找关键字29的过程:

  1. 根据根节点找到磁盘块1,读入内存。【磁盘I/O操做第1次】 
  2. 比较关键字29在区间(17,35),找到磁盘块1的指针P2。
  3. 根据P2指针找到磁盘块3,读入内存。【磁盘I/O操做第2次】
  4. 比较关键字29在区间(26,30),找到磁盘块3的指针P2。
  5. 根据P2指针找到磁盘块8,读入内存。【磁盘I/O操做第3次】
  6. 在磁盘块8中的关键字列表中找到关键字29。

 分析上面过程,发现须要3次磁盘I/O操做,和3次内存查找操做。因为内存中的关键字是一个有序表结构,能够利用二分法查找提升效率。而3次磁盘I/O操做是影响整个B-Tree查找效率的决定因素。

 B-Tree相对于AVLTree缩减了节点个数,使每次磁盘I/O取到内存的数据都发挥了做用,从而提升了查询效率。

3.1.1.3 ,  B+Tree(查询任意数据的次数是 n)

  B+Tree是在B-Tree基础上的一种优化,使其更适合实现外存储索引结构,InnoDB存储引擎就是用B+Tree实现其索引结构。

从上一节中的B-Tree结构图中能够看到每一个节点中不只包含数据的key值,还有data值。而每个页的存储空间是有限的,若是data数据较大时将会致使每一个节点(即一个页)能存储的key的数量很小,当存储的数据量很大时一样会致使B-Tree的深度较大,增大查询时的磁盘I/O次数,进而影响查询效率。在B+Tree中,全部数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,而非叶子节点上只存储key值信息,这样能够大大加大每一个节点存储的key值数量,下降B+Tree的高度。

B+Tree相对于B-Tree有几点不一样:

  1. 非叶子节点只存储键值信息。
  2. 全部叶子节点之间都有一个链指针。
  3. 数据记录都存放在叶子节点中。

将上一节中的B-Tree优化,因为B+Tree的非叶子节点只存储键值信息,假设每一个磁盘块能存储4个键值及指针信息,则变成B+Tree后其结构以下图所示: 

一般在B+Tree上有两个头指针,一个指向根节点,另外一个指向关键字最小的叶子节点,并且全部叶子节点(即数据节点)之间是一种链式环结构。所以能够对B+Tree进行两种查找运算:一种是对于主键的范围查找和分页查找,另外一种是从根节点开始,进行随机查找。

上面都应该知道B+Tree 了吧,因此咱们在创建索引时,会生成一个B+Tree  若是咱们在只查询索引字段时,sql 语句就直接去B+Tree 查,不会再去数据表中查了,这样提高性能是很重要的。 还有就是对于老是修改的字段不要对他创建索引,由于字段修改了,B+Tree 结构就要重构,这要是会下降性能的。

3.1.1 索引分类:

mysql索引的四种类型:主键索引惟一索引普通索引全文索引。经过给字段添加索引能够提升数据的读取速度,提升项目的并发能力和抗压能力。索引优化时mysql中的一种优化方式。索引的做用至关于图书的目录,能够根据目录中的页码快速找到所需的内容

主键索引:  主键是一种惟一性索引,但它必须指定为PRIMARY KEY,每一个表只能有一个主键。

alert table tablename add primary key (`字段名`)

  惟一索引:    索引列的全部值都只能出现一次,即必须惟一,值能够为

alter table table_name add primary key (`字段名`);

   普通索引 :   基本的索引类型,值能够为空,没有惟一性的限制。

alter table table_name add index (`字段名`);

   全文索引:
        全文索引的索引类型为FULLTEXT。全文索引能够在varchar、char、text类型的列上建立。能够经过ALTER TABLE或CREATE INDEX命令建立。对于大规模的数据集,经过ALTER TABLE(或者CREATE INDEX)命令建立全文索引要比把记录插入带有全文索引的空表更快。MyISAM支持全文索引,InnoDB在mysql5.6以后支持了全文索引。        全文索引不支持中文须要借sphinx(coreseek)迅搜<、code>技术处理中文。

3.2.2 索引的机制

1.为何咱们添加完索引查询速度为变快

    传统的查询方法,是按照表的顺序遍历的,不论查询几条数据,mysql须要将表的数据从头至尾遍历一遍

    在咱们添加完索引以后,mysql通常经过BTREE算法生成一个索引文件,在查询数据库时,找到索引文件进行遍历(折半查找大幅查询效率),找到相应的键从而获取数据

2.索引的代价
    2.1建立索引是为产生索引文件的,占用磁盘空间
    2.2索引文件是一个二叉树类型的文件,可想而知咱们的dml操做一样也会对索引文件进行修改,因此性能会降低

3.在哪些column上使用索引?
    3.1较频繁的做为查询条件字段应该建立索引
    3.2惟一性太差的字段不适合建立索引,尽管频繁做为查询条件,例如gender性别字段
    3.3更新很是频繁的字段不适合做为索引
    3.4不会出如今where子句中的字段不应建立索引

总结: 知足如下条件的字段,才应该建立索引.
a: 确定在where条常用 b: 该字段的内容不是惟一的几个值 c: 字段内容不是频繁变化

3.2.二、SQL解析顺序

接下来再走一步,让咱们看看一条SQL语句的前世此生。
首先看一下示例语句
SELECT DISTINCT  .....   FROM .....  JOIN  .....  ON   .....  WHERE.....   GROUP BY    .....   HAVING  .....   ORDER BY   .....   LIMIT .....

  然而它的执行顺序是这样的

FROM   .....  ON  .....    JOIN  .....   WHERE     ..... GROUP BY     .....  HAVING  .....    SELECT    DISTINCT   .....  ORDER BY   .....  LIMIT   .....
  3.2.3 如何创建索引          

 通常说来,索引应创建在那些将用于JOIN,WHERE判断和ORDERBY排序的字段上。尽可能不要对数据库中某个含有大量重复的值的字段创建索引。对于一个ENUM类型的字段来讲,出现大量重复值是颇有可能的状况.

 3.2.4     使用索引时,有一些技巧:

  1.索引不会包含有NULL的列

  只要列中包含有NULL值,都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此符合索引就是无效的。

 2. 索引要创建在常常进行select操做的字段上。而常常修改的字段,没不必创建索引了,由于,你创建了索引会生成一个B+树,你修改了该索引的字段后,这个B+树就须要修改,反而对性能不是很好。

 3. 复合索引 : 复合索引,不要跨列或无序使用(最佳左前缀)

 4.like语句操做: 通常状况下不鼓励使用like操做,若是非使用不可,注意正确的使用方式。like ‘%aaa%’不会使用索引,而like ‘aaa%’可使用索引。

    5. 不要在索引上进行任何操做(计算、函数、类型转换),不然索引失效

   6.不使用NOT IN 、<>、!=操做,但<,<=,=,>,>=,BETWEEN,IN是能够用到索引的

   7.索引要创建在常常进行select操做的字段上。

  这是由于,若是这些列不多用到,那么有无索引并不能明显改变查询速度。相反,因为增长了索引,反而下降了系统的维护速度和增大了空间需求。

   8.索引要创建在值比较惟一的字段上。

    9.对于那些定义为text、image和bit数据类型的列不该该增长索引。由于这些列的数据量要么至关大,要么取值不多。

   10.在join操做中(须要从多个数据表提取数据时),mysql只有在主键和外键的数据类型相同时才能使用索引,不然及时创建了索引也不会使用。

 三, sql性能问题

  a.分析SQL的执行计划  : explain   ,能够模拟SQL优化器执行SQL语句,从而让开发人员 知道本身编写的SQL情况

  b.MySQL查询优化其会干扰咱们的优化(mysql服务层有一个sql优化器),能够对咱们写的sql进行优化,这是咱们控制不了的。

  查询执行计划:  explain +SQL语句     explain SELECT * from book ;

      

    

id : 编号
select_type :查询类型
table :表
type :索引类型 system>const>eq_ref>ref>range>index>all ,要对type进行优化的前提:有索引 通常能达到range 就行。
possible_keys :预测用到的索引
key :实际使用的索引
key_len :实际使用索引的长度
ref :表之间的引用
rows :经过索引查询到的数据量
Extra :额外的信息 下面是他可能发出的状况

  i). using filesort : 性能消耗大;须要“额外”的一次排序(查询)  。常见于 order by 语句中。 解决:where哪些字段,就order by那些字段2

  ii). using temporary:性能损耗大 ,用到了临时表。通常出如今group by 语句中。 解决: 避免:查询那些列,就根据那些列 group by .

  iii). using index :性能提高; 索引覆盖(覆盖索引)。缘由:不读取原文件,只从索引文件中获取数据 (不须要回表查询)
只要使用到的列 所有都在索引中,就是索引覆盖using index

  iii).using where (须要回表查询)。

    假设age是索引列     但查询语句select age,name from ...where age =...,此语句中必须回原表查Name,所以会显示using where.  解决 吧name  也添加到索引中去。

相关文章
相关标签/搜索