java面试总结之三

前言html

数据库是java开发过程必不可少的数据存储工具,一般咱们分为关系型数据库和非关系型数据库,上一篇中已经简单的介绍了redis,这里说一说关系型数据库mysql。java

一、mysql引擎mysql

  这里只说咱们常见的两种引擎,MyISAM和Innodb,其余相关的引擎有兴趣的能够自行了解。首先咱们简单的说说这两种引擎的区别。redis

  1)MyISAM,不支持事务,支持全文索引、表锁,在磁盘上有三个与表名相同的文件,.FRM文件存储表结构,.MYD文件存储表数据,.MYI文件存储表索引,MyISAM不缓存数据,只缓存索引。算法

  2)InnoDB,支持事务、外键、行锁和非锁定读,即默认状况下读不产生锁。InnoDB由一系列后台线程和一大块内存组成。默认状况下,后台线程有7个,4个IO线程,1个master thread,1个lock监控线程,1个error监控线程。sql

  在实际开发中,因为事务和行级锁等机制的缘由,Innodb可能接触的更多一些。MyISAM更多用于查询,尤为是select * from tableName,能够直接获取到数值,不须要全表扫描。数据库

二、mysql结构编程

  mysql的结构以下图所示,我的十分喜欢这张图,经过这张图还能够大体了解一条SQL语句的执行过程
后端

  1)Connectors,与其余编程语言(java等)中的sql语句进行交互
  2)Connection pool,链接池,管理缓存用户链接、线程处理等须要缓存的数据
  3)Management services&Utilities,系统管理和控制工具
  4)SQL interface,SQL接口,接收用户的sql命令,并返回用户须要的结果
  5)parser,解析器,验证并解析用户传来的sql语句,将sql语句解析成数据结构,并将这个数据结构传递到后续步骤,若是解析过程须要错误,说明sql语句是错误的,中止执行
  6)Optimlzer,优化器,产生多种执行计划,数据库选择最优的方案执行
  7)cache&buffer,缓存,若是查询缓存有命中,则直接返回结果。cache是读缓存,buffer是写缓存。
  8)Engines,存储引擎
  SQL语句执行过程:
  1)请求与mysql的connectors进行交互,请求到达后会暂时存放在链接池(connection pool)中,并由处理器(management services&utilities)管理。当请求从等待队列进入处理队列后,管理器会将请求交给SQL接口(SQL interface)。
  2)SQL接口接收到请求后,会将请求进行hash处理并和缓存(cache&buffer)中的结果进行比较,若是彻底匹配,则直接返回缓存数据。
  3)若是缓存未命中,由SQL接口将请求交给解析器(parser),解析器将sql语言解析成数据结构
  4)解析器处理完毕,请求便来到优化器(optimizer),优化器会产生多个执行计划,数据库会选择一个最优方案来执行
  5)肯定最优方案以后,sql语句即可以由存储引擎处理(engines),存储引擎将会到后端的存储设备中获取数据并原路返回
三、索引
  mysql中的索引包括主键索引(默认自动为主键添加)、普通索引、惟一索引(字段的值不能重复)、组合索引和全文索引(不建议使用,并且Innodb也不支持,建议使用solr等代替)。其中组合索引须要额外说明一下,组合索引知足最左原则,即假如在A、B、C三列上添加索引,实际上会额外在A和A,B上建立索引,至关于建立了三个索引。另外能够经过show index from tableName查询该表上的索引。索引的算法包括B-Tree和Hash两种,在此强调一下Innodb不支持Hash,即便设置成Hash,索引依然使用B-Tree。
  一般咱们会在常用的查询语句的where和join字段上添加索引,这里须要注意的是join的两个字段必须类型一致,若是是字符串类型,编码格式也要同样,不然将没法使用索引,另外,在like中,以_%通配符开头的查询没法使用索引,如:
select * from tableName where name like '_zhang'
select * from tableName where name like '%zhang'

  上述两个sql没法使用name列上的索引缓存

select * from tableName where name like 'zhang_'
select * from tableName where name like 'zhang%'

  上述两个sql可使用name列上的索引

  还有一点须要注意的是,对于变化较少的字段不建议添加索引,如性别的列,一般的值是0和1或者true和false,此列添加索引不会有太大的速度提高。一个表的索引个数也不建议过多,增删改数据的同时还要维护索引,过多的索引会下降数据库的效率。

四、mysql优化

  mysql的优化从三个方面入手,包括建立表时的优化,索引的建立以及sql的优化

  1)建立表时的优化

    a)为表添加主键ID,最好使用无符号的int类型,设置成自增(注意分表时id重复的状况)

    b)针对字典表能够考虑使用ENUM类型代替字符串,若是插入的值不在ENUM规定值内,则自动使用''空字符串代替

    c)尽可能使用NOT NULL,使用NULL须要额外的空间,并且NULL没法使用索引

    d)使用PROCEDURE ANALYSE()函数取得建议,根据表中数据进行分析,因此须要数据库中有必定的数据作基础,如:

SELECT * FROM sys_user PROCEDURE ANALYSE();

    越小的列越快,在考虑往后数据扩展的前提下,尽可能使用较小存储单元的类型,如字典表中数据较少时,主键能够放弃使用INT,用MEDIUMINT、SMALLINT来代替,甚至使用更小的TINYINT,若是不须要记录时间,可使用DATE代替DATETIME

    e)使用固定长度的表,若是表中全部的列都是固定长度的,表会被认为是“static”的,会加快查询速度,若是列中包含varchar、text或blog之一,则表不是固定长度的。固定长度的表因为定长,能够根据偏移量计算下一条数据的位置,而变长的表只能经过寻找下一条数据的主键。固定长度的表的缺点就是会形成空间浪费,由于不管存储数据大小,都会分配定长的空间。注:mysql字段占用空间与类型有关,如int(11)和int(3)都占用四个字节的长度,区别是根据存储数据的长度自动补全零位的个数,存储1111时,因为长度是4,int(3)不须要补零,int(11)会自动补全7个0

    f)表分割,表分割能够分为水平分割和垂直分割。水平分割就是创建结构相同可是表名不一样的表,将数据按照hash运算以后存储在对应的表中,如sys_user_1,sys_user_2等;垂直分割是将表中一些不经常使用的或者会常常更新致使查询缓存失效的列分割出来,如家庭住址,最后登陆时间等字段。注:被分割的字段不能常常被JOIN,不然会极大下降性能

    g)数据库读写分离

  2)索引的建立

    索引的建立就是在适合的列上添加索引,从而达到加快查询速度的效果,上面已经说起,这里再也不累述。

  3)SQL的优化

    a)使用explain关键字解析sql语句,如:

EXPLAIN SELECT * FROM (SELECT user_sex,COUNT(*) AS counts FROM sys_user u GROUP BY u.user_sex) count_t WHERE count_t.counts > 1

    结果以下所示:

    一般咱们关注的是type这一列,这里不要求记住全部,只须要记住几个典型的,而且了解哪一个更优便可,如system、const、eq_ref、ref、range、index、all等。这里有一篇文章,你们能够参考了解一下:《mysql explain 的type解释》

    b)在查询结果明确只有一条的状况下,且该列上没有索引,使用LIMIT 1能够在查询到数据以后直接返回,避免全表扫描;判断一条数据是否存在时,使用SELECT 1能够提升查询速度,SELECT 1 > SELECT any column > SELECT *

    c)避免SELECT *,用什么数据取什么列,减小网络数据传输

    d)尽可能少用having、in、not in、is null等关键字或判断,对于having,可使用子查询来代替;in和not in可使用exists和not exists代替,若是数据连续,也可使用between and代替。

五、Innodb文件结构

  InnoDB表由共享表空间或独立表空间、日志文件组和表结构文件组成。可使用show variables like 'innodb_file_per_table'查看是否开启了独立表空间,结果为ON时表示开启独立表空间;OFF时表示使用共享共享表空间。

  1)表结构文件(.frm)mysql会为每一个表在其数据目录下建立一个tablename.frm文件来存储表结构定义,与引擎无关,用来恢复表结构
  2)表空间文件,表空间(tablespace)由分散的段(segment)组成,一个段包含多个区(extent),一个区由64个连续的页(page)组成,每一个页的大小为16K,因此一个区的大小为1M,区包含行(row)。
  3)共享表空间将全部的数据存储在一个单独的表空间里面;独立表空间为每个表建立一个表空间文件(.ibd),存储表的数据、索引等数据,撤销(undo)信息、系统事务信息等存放在原来的共享表空间中。在mysql5.6.5及以前默认是共享表空间,以后默认是独立表空间。可使用 SHOW VARIABLES like 'innodb_data%'命令来查看共享表空间文件信息,文件默认的名称是ibdata1,初始大小为10M,可自动扩展,如:ibdata1:10M:autoextend
  4)共享表空间的优劣势
    优点:能够将表空间分红多个文件存储在不一样的磁盘上,一个表的数据能够存放在不一样的表空间文件上,表空间文件大小不受表大小限制;数据和文件放在一块儿,方便管理
    劣势:大量删除数据时,表空间会出现空隙
  5)独立表空间的优劣势
    优点:每一个表有独立的表空间,表数据和索引存储在独立的表空间中,能够实现单表在数据库中的转移(数据文件复制);大量删除数据的时候,能够压缩表空间文件,回收空间
    劣势:单个表空间文件很大
六、事务隔离级别
  说到数据库就不得不说一下事务,简单的ACID原则你们都知道,讲的是原子性、隔离性、一致性和永久性,但愿你能用实际状况描述一下这四种特性。另外就是事务的隔离级别,以下:
    1)Read uncommitted,读取未提交内容,最低级别,任何状况均可能发生
    2)Read committed,读取已提交内容,可避免脏读
    3)Repeatable read,可重复读,可避免脏读、不可重复读
    4)Serializable,串行化,避免脏读、不可重复读、幻读
  以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,固然级别越高,执行效率就越低。像Serializable这样的级别,就是以锁表的方式(相似于Java多线程中的锁)使得其余的线程只能在锁外等待,因此平时选用何种隔离级别应该根据实际状况。在MySQL数据库中,支持上面四种隔离级别,默认的为Repeatable read (可重复读);而在Oracle数据库中,只支持Serializable (串行化)级别和Read committed (读已提交)这两种级别,其中默认的为Read committed级别。
  顺带提一下数据异常的状况:
    1)脏读,一个事务在执行过程当中读取了另外一个事务未提交的数据。
    2)不可重复读,一个事务范围内的屡次查询返回不一样结果,因为在查询间隔中,数据被其余事务修改并提交了。
    3)幻读,一个事务对一批数据进行修改,另外一个事务插入一条新数据,此时新插入的数据并未被第一个事务修改,产生幻读。
   脏读是读取另外一个事务未提交的数据产生的,而不可重复读和幻读是读取另外一个事务已提交的数据产生的;不可重复读是针对一条数据产生的,幻读是针对一批数据产生的。
七、Innodb锁
  针对锁的粒度大小不一样,mysql分为行级锁、表锁、页锁,这里咱们只讨论行级锁和表锁。Innodb支持行级锁,MyISAM使用的是表锁。根据锁的性质不一样,又可分为读锁(共享锁)、写锁(排它锁)和意向锁。只有读锁与读锁是兼容的,也就是说多个线程能够同时读取同一数据,可是当有一个线程写数据时,其余线程不管是读取仍是写该数据均被阻塞。意向锁是一种虚拟的锁,当一个线程对表结构进行修改时,须要对整个表进行加锁,再获取到表锁以后还须要判断是否存在行级锁,传统的方式就是一行一行的判断,这样是极其低效的方法。意向锁的思想是,在添加行级锁时,对表添加意向锁,当有其余线程对表加锁以后,只须要判断是否存在乎向锁就能够知道是否存在行级锁了。
  添加读锁的方式为:
select * from tableName where id =1 lock in share mode
  添加写锁的方式为:
select * from tableName where id =1 for update
  这里须要说明一下,添加写锁时,必须明确id且id存在,不然将添加表锁。
  死锁只会出如今行级锁的状况下,即两个进程都持有一部分数据的锁,可是再释放锁以前又想获取对方的持有的锁,从而形成无限等待下去的状况。这里有一篇文章,你们能够参考一下: 《Mysql并发时经典常见的死锁缘由及解决方法》
关于mysql的总结大体就这么,还有不少东西等待咱们去探索和学习,但愿这篇文章能帮助你们对mysql有一个简单的了解。

本文版权归做者和博客园共有,欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面明显位置给出原文链接,不然保留追究法律责任的权利。

原文连接:http://www.cnblogs.com/1ning/p/6705129.html