Java 面试知识点解析(六)——数据库篇

 
 
  • 前言:

在遨游了一番 Java Web 的世界以后,发现了本身的一些缺失,因此就着一篇深度好文:知名互联网公司校招 Java 开发岗面试知识点解析 ,来好好的对 Java 知识点进行复习和学习一番,大部份内容参照自这一篇文章,有一些本身补充的,也算是从新学习一下 Java 吧。html

前序文章连接:java

Java 面试知识点解析(一)——基础知识篇mysql

Java 面试知识点解析(二)——高并发编程篇面试

Java 面试知识点解析(三)——JVM篇sql

Java 面试知识点解析(四)——版本特性篇数据库

Java 面试知识点解析(五)——网络协议篇编程


前排引用说明及好文推荐:面试/笔试第三弹 —— 数据库面试问题集锦数据库常见面试题(开发者篇)segmentfault

1)什么是存储过程?有哪些优缺点?

存储过程就像是编程语言中的函数同样,封装了咱们的代码(PLSQL,T-SQL)缓存

例如:安全

-------------建立名为GetUserAccount的存储过程---------------- create Procedure GetUserAccount as select * from UserAccount go -------------执行上面的存储过程---------------- exec GetUserAccount 

存储过程的优势:

  • 可以将代码封装起来
  • 保存在数据库之中
  • 让编程语言进行调用
  • 存储过程是一个预编译的代码块,执行效率比较高
  • 一个存储过程替代大量T_SQL语句 ,能够下降网络通讯量,提升通讯速率

存储过程的缺点:

  • 每一个数据库的存储过程语法几乎都不同,十分难以维护(不通用)
  • 业务逻辑放在数据库上,难以迭代

2)三大范式

  • 思考这样的一个例子:

咱们如今须要创建一个描述学校教务的数据库,该数据库涉及的对象包括学生的学号(Sno)、所在系(Sdept)、系主任姓名(Mname)、课程号(Cno)和成绩(Grade),假设咱们使用单一的关系模式 Student 来表示,那么根据现实世界已知的信息,会描述成如下这个样子:

 
 

可是,这个关系模式存在如下问题:

(1) 数据冗余
好比,每个系的系主任姓名重复出现,重复次数与该系全部学生的全部课程成绩出现次数相同,这将浪费大量的存储空间。
(2)更新异常(update anomalies)
因为数据冗余,当更新数据库中的数据时,系统要付出很大的代价来维护数据库的完整性,不然会面临数据不一致的危险。好比,某系更换系主任后,必须修改与该系学生有关的每个元组。
(3)插入异常(insertion anomalies)
若是一个系刚成立,尚无学生,则没法把这个系及其系主任的信息存入数据库。
(4)删除异常(deletion anomalies)
若是某个系的学生所有毕业了,则在删除该系学生信息的同时,这个系及其系主任的信息也丢失了。

  • 总结: 因此,咱们在设计数据库的时候,就须要知足必定的规范要求,而知足不一样程度要求的就是不一样的范式。
  • 第一范式: 列不可分

1NF(第一范式)是对属性具备原子性的要求,不可再分,例如:

 
 

若是认为最后一列还能够再分红出生年,出生月,出生日,则它就不知足第一范式的要求。

  • 第二范式: 消除非主属性对码的部分函数依赖

2NF(第二范式)是对记录有惟一性的要求,即实体的惟一性,不存在部分依赖,每一列与主键都相关,例如:

 
 

该代表显说明了两个事物:学生信息和课程信息;正常的依赖应该是:学分依赖课程号,姓名依赖学号,但这里存在非主键字段对码的部分依赖,即与主键不相关,不知足第二范式的要求。

可能存在的问题:

  • 数据冗余:每条记录都含有相同信息;
  • 删除异常:删除全部学生成绩,就把课程信息全删除了;
  • 插入异常:学生未选课,没法记录进数据库;
  • 更新异常:调整课程学分,全部行都调整。

正确的作法:

 
 
  • 第三范式: 消除非主属性对码的传递函数依赖

3NF(第三范式)对字段有冗余性的要求,任何字段不能由其余字段派生出来,它要求字段没有冗余,即不存在依赖传递,例如:

 
 

很明显,学院电话是一个冗余字段,由于存在依赖传递:(学号)→(学生)→(学院)→(学院电话)

可能会存在的问题:

  • 数据冗余:有重复值;
  • 更新异常:有重复的冗余信息,修改时须要同时修改多条记录,不然会出现数据不一致的状况 。

正确的作法:

 
 

3)数据库索引

  • 什么是索引?

索引是对数据库表中一个或多个列的值进行排序的数据结构,以协助快速查询、更新数据库表中数据。

你也能够这样理解:索引就是加快检索表中数据的方法。数据库的索引相似于书籍的索引。在书籍中,索引容许用户没必要翻阅完整个书就能迅速地找到所须要的信息。在数据库中,索引也容许数据库程序迅速地找到表中的数据,而没必要扫描整个数据库。

  • 底层数据结构是什么,为何使用这种数据结构?

(1)底层数据结构是B+树:
在数据结构中,咱们最为常见的搜索结构就是二叉搜索树和AVL树(高度平衡的二叉搜索树,为了提升二叉搜索树的效率,减小树的平均搜索长度)了。然而,不管二叉搜索树仍是AVL树,当数据量比较大时,都会因为树的深度过大而形成I/O读写过于频繁,进而致使查询效率低下,所以对于索引而言,多叉树结构成为不二选择。特别地,B-Tree的各类操做能使B树保持较低的高度,从而保证高效的查找效率。

(2)使用B+树的缘由:
查找速度快、效率高,在查找的过程当中,每次都能抛弃掉一部分节点,减小遍历个数。(此时,你应该在白纸上画出什么是B+树)

  • 索引的分类?
  • 惟一索引:惟一索引不容许两行具备相同的索引值
  • 主键索引:为表定义一个主键将自动建立主键索引,主键索引是惟一索引的特殊类型。主键索引要求主键中的每一个值是惟一的,而且不能为空
  • 汇集索引(Clustered):表中各行的物理顺序与键值的逻辑(索引)顺序相同,每一个表只能有一个
  • 非汇集索引(Non-clustered):非汇集索引指定表的逻辑顺序。数据存储在一个位置,索引存储在另外一个位置,索引中包含指向数据存储位置的指针。能够有多个,小于249个
  • 索引的优缺点?

(1)优势:

  • 大大加快数据的检索速度,这也是建立索引的最主要的缘由;
  • 加速表和表之间的链接;
  • 在使用分组和排序子句进行数据检索时,一样能够显著减小查询中分组和排序的时间;
  • 经过建立惟一性索引,能够保证数据库表中每一行数据的惟一性;

(2)缺点:

  • 时间方面:建立索引和维护索引要耗费时间,具体地,当对表中的数据进行增长、删除和修改的时候,索引也要动态的维护,这样就下降了数据的维护速度;
  • 空间方面:索引须要占物理空间。
  • 什么样的字段适合建立索引?
  • 常常做查询选择的字段
  • 常常做表链接的字段
  • 常常出如今order by, group by, distinct 后面的字段
  • 建立索引时须要注意什么?
  • 非空字段:应该指定列为NOT NULL,除非你想存储NULL。在mysql中,含有空值的列很难进行查询优化,由于它们使得索引、索引的统计信息以及比较运算更加复杂。你应该用0、一个特殊的值或者一个空串代替空值;

  • 取值离散大的字段:(变量各个取值之间的差别程度)的列放到联合索引的前面,能够经过count()函数查看字段的差别值,返回值越大说明字段的惟一值越多字段的离散程度高;

  • 索引字段越小越好:数据库的数据存储以页为单位一页存储的数据越多一次IO操做获取的数据越大效率越高。


4)据说过事务吗?(必考)

事务简单来讲:一个 Session 中所进行全部的操做,要么同时成功,要么同时失败;做为单个逻辑工做单元执行的一系列操做,知足四大特性:

  1. 原子性(Atomicity):事务做为一个总体被执行 ,要么所有执行,要么所有不执行
  2. 一致性(Consistency):保证数据库状态从一个一致状态转变为另外一个一致状态
  3. 隔离性(Isolation):多个事务并发执行时,一个事务的执行不该影响其余事务的执行
  4. 持久性(Durability):一个事务一旦提交,对数据库的修改应该永久保存
  • 实例说明:
/* * 咱们来模拟A向B帐号转帐的场景 * A和B帐户都有1000块,如今我让A帐户向B帐号转500块钱 * **/ //JDBC默认的状况下是关闭事务的,下面咱们看看关闭事务去操做转帐操做有什么问题 //A帐户减去500块 String sql = "UPDATE a SET money=money-500 "; preparedStatement = connection.prepareStatement(sql); preparedStatement.executeUpdate(); //B帐户多了500块 String sql2 = "UPDATE b SET money=money+500"; preparedStatement = connection.prepareStatement(sql2); preparedStatement.executeUpdate(); 

从上面看,咱们的确能够发现A向B转帐,成功了。但是若是A向B转帐的过程当中出现了问题呢?下面模拟一下

// A帐户减去500块 String sql = "UPDATE a SET money=money-500 "; preparedStatement = connection.prepareStatement(sql); preparedStatement.executeUpdate(); // 这里模拟出现问题 int a = 3 / 0; String sql2 = "UPDATE b SET money=money+500"; preparedStatement = connection.prepareStatement(sql2); preparedStatement.executeUpdate(); 

显然,上面代码是会抛出异常的,咱们再来查询一下数据。A帐户少了500块钱,B帐户的钱没有增长。这明显是不合理的。

咱们能够经过事务来解决上面出现的问题:

// 开启事务,对数据的操做就不会当即生效。 connection.setAutoCommit(false); // A帐户减去500块 String sql = "UPDATE a SET money=money-500 "; preparedStatement = connection.prepareStatement(sql); preparedStatement.executeUpdate(); // 在转帐过程当中出现问题 int a = 3 / 0; // B帐户多500块 String sql2 = "UPDATE b SET money=money+500"; preparedStatement = connection.prepareStatement(sql2); preparedStatement.executeUpdate(); // 若是程序能执行到这里,没有抛出异常,咱们就提交数据 connection.commit(); // 关闭事务【自动提交】 connection.setAutoCommit(true); } catch(SQLException e) { try { // 若是出现了异常,就会进到这里来,咱们就把事务回滚【将数据变成原来那样】 connection.rollback(); // 关闭事务【自动提交】 connection.setAutoCommit(true); } catch (SQLException e1) { e1.printStackTrace(); } } 

上面的程序也同样抛出了异常,A帐户钱没有减小,B帐户的钱也没有增长。

  • 注意:当Connection遇到一个未处理的SQLException时,系统会非正常退出,事务也会自动回滚,但若是程序捕获到了异常,是须要在catch中显式回滚事务的。

5)事务的并发问题有哪几种?

  1. 丢失更新:一个事务的更新覆盖了另外一个事务的更新;
  2. 脏读:一个事务读取了另外一个事务未提交的数据;
  3. 不可重复读:不可重复读的重点是修改,一样条件下两次读取结果不一样,也就是说,被读取的数据能够被其它事务修改;
  4. 幻读:幻读的重点在于新增或者删除,一样条件下两次读出来的记录数不同。

6)事务的隔离级别有哪几种?

隔离级别决定了一个session中的事务可能对另外一个session中的事务的影响。ANSI标准定义了4个隔离级别,MySQL的InnoDB都支持,分别是:

  1. 读未提交(READ UNCOMMITTED):最低级别的隔离,一般又称为dirty read,它容许一个事务读取另外一个事务还没 commit 的数据,这样可能会提升性能,可是会致使脏读问题;

  2. 读已提交(READ COMMITTED):在一个事务中只容许对其它事务已经 commit 的记录可见,该隔离级别不能避免不可重复读问题;

  3. 可重复读(REPEATABLE READ):在一个事务开始后,其余事务对数据库的修改在本事务中不可见,直到本事务 commit 或 rollback。可是,其余事务的 insert/delete 操做对该事务是可见的,也就是说,该隔离级别并不能避免幻读问题。在一个事务中重复 select 的结果同样,除非本事务中 update 数据库。

  4. 序列化(SERIALIZABLE):最高级别的隔离,只容许事务串行执行。

MySQL默认的隔离级别是可重复读(REPEATABLE READ)

  • MySql 的事务支持

MySQL的事务支持不是绑定在MySQL服务器自己,而是与存储引擎相关:

  • MyISAM:不支持事务,用于只读程序提升性能;
  • InnoDB:支持ACID事务、行级锁、并发;
  • Berkeley DB:支持事务。

7)什么是视图?以及视图的使用场景有哪些?

视图是一种虚拟的表,具备和物理表相同的功能。能够对视图进行增,改,查,操做,试图一般是有一个表或者多个表的行或列的子集。对视图的修改不影响基本表。它使得咱们获取数据更容易,相比多表查询。

以下两种场景通常会使用到视图:

  1. 不但愿访问者获取整个表的信息,只暴露部分字段给访问者,因此就建一个虚表,就是视图。
  2. 查询的数据来源于不一样的表,而查询者但愿以统一的方式查询,这样也能够创建一个视图,把多个表查询结果联合起来,查询者只须要直接从视图中获取数据,没必要考虑数据来源于不一样表所带来的差别。

注意:这个视图是在数据库中建立的 而不是用代码建立的。


8)drop,delete与truncate的区别?

drop 直接删除表;truncate 删除表中数据,再插入时自增加id又从1开始 ;delete 删除表中数据,能够加where字句。

  • drop table:
  • 属于DDL(Data Definition Language,数据库定义语言)
  • 不可回滚
  • 不可带 where
  • 表内容和结构删除
  • 删除速度快
  • truncate table:
  • 属于DDL(Data Definition Language,数据库定义语言)
  • 不可回滚
  • 不可带 where
  • 表内容删除
  • 删除速度快
  • delete from:
  • 属于DML
  • 可回滚
  • 可带where
  • 表结构在,表内容要看where执行的状况
  • 删除速度慢,须要逐行删除
  • 使用简要说明:
  • 再也不须要一张表的时候,用drop
  • 想删除部分数据行时候,用delete,而且带上where子句
  • 保留表而删除全部数据的时候用truncate

9)触发器的做用?

触发器是与表相关的数据库对象,在知足定义条件时触发,并执行触发器中定义的语句集合。触发器的这种特性能够协助应用在数据库端确保数据库的完整性。


10)数据库的乐观锁和悲观锁是什么?

数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。

乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。

  • 悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操做

悲观锁是一种利用数据库内部机制提供的锁的方式,也就是对更新的数据加锁,这样在并发期间一旦有一个事务持有了数据库记录的锁,其余的线程将不能再对数据进行更新了,这就是悲观锁的实现方式。

MySQL InnoDB中使用悲观锁:

要使用悲观锁,咱们必须关闭mysql数据库的自动提交属性,由于MySQL默认使用autocommit模式,也就是说,当你执行一个更新操做后,MySQL会马上将结果进行提交。 set autocommit=0;

//0.开始事务
begin;/begin work;/start transaction; (三者选一就能够) //1.查询出商品信息 select status from t_goods where id=1 for update; //2.根据商品信息生成订单 insert into t_orders (id,goods_id) values (null,1); //3.修改商品status为2 update t_goods set status=2; //4.提交事务 commit;/commit work; 

上面的查询语句中,咱们使用了 select…for update 的方式,这样就经过开启排他锁的方式实现了悲观锁。此时在t_goods表中,id为1的 那条数据就被咱们锁定了,其它的事务必须等本次事务提交以后才能执行。这样咱们能够保证当前的数据不会被其它事务修改。

上面咱们提到,使用 select…for update 会把数据给锁住,不过咱们须要注意一些锁的级别,MySQL InnoDB默认行级锁。行级锁都是基于索引的,若是一条SQL语句用不到索引是不会使用行级锁的,会使用表级锁把整张表锁住,这点须要注意。

优势与不足:

悲观并发控制其实是“先取锁再访问”的保守策略,为数据处理的安全提供了保证。可是在效率方面,处理加锁的机制会让数据库产生额外的开销,还有增长产生死锁的机会;另外,在只读型事务处理中因为不会产生冲突,也不必使用锁,这样作只能增长系统负载;还有会下降了并行性,一个事务若是锁定了某行数据,其余事务就必须等待该事务处理完才能够处理那行数

  • 乐观锁:假设不会发生并发冲突,只在提交操做时检查是否违反数据完整性。

乐观锁是一种不会阻塞其余线程并发的控制,它不会使用数据库的锁进行实现,它的设计里面因为不阻塞其余线程,因此并不会引发线程频繁挂起和恢复,这样便可以提升并发能力,因此也有人把它称为非阻塞锁。通常的实现乐观锁的方式就是记录数据版本。

数据版本,为数据增长的一个版本标识。当读取数据时,将版本标识的值一同读出,数据每更新一次,同时对版本标识进行更新。当咱们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的版本标识进行比对,若是数据库表当前版本号与第一次取出来的版本标识值相等,则予以更新,不然认为是过时数据。

实现数据版本有两种方式,第一种是使用版本号,第二种是使用时间戳。

使用版本号实现乐观锁:

使用版本号时,能够在数据初始化时指定一个版本号,每次对数据的更新操做都对版本号执行+1操做。并判断当前版本号是否是该数据的最新的版本号。

1.查询出商品信息
select (status,status,version) from t_goods where id=#{id} 2.根据商品信息生成订单 3.修改商品status为2 update t_goods set status=2,version=version+1 where id=#{id} and version=#{version}; 

优势与不足:

乐观并发控制相信事务之间的数据竞争(data race)的几率是比较小的,所以尽量直接作下去,直到提交的时候才去锁定,因此不会产生任何锁和死锁。但若是直接简单这么作,仍是有可能会遇到不可预期的结果,例如两个事务都读取了数据库的某一行,通过修改之后写回数据库,这时就遇到了问题。

参考文章:深刻理解乐观锁与悲观锁


11)超键、候选键、主键、外键分别是什么?

  • 超键:在关系中能惟一标识元组的属性集称为关系模式的超键。一个属性能够为做为一个超键,多个属性组合在一块儿也能够做为一个超键。超键包含候选键和主键。

  • 候选键(候选码):是最小超键,即没有冗余元素的超键。

  • 主键(主码):数据库表中对储存数据对象予以惟一和完整标识的数据列或属性的组合。一个数据列只能有一个主键,且主键的取值不能缺失,即不能为空值(Null)。

  • 外键:在一个表中存在的另外一个表的主键称此表的外键。

候选码和主码:

例子:邮寄地址(城市名,街道名,邮政编码,单位名,收件人)

  • 它有两个候选键:{城市名,街道名} 和 {街道名,邮政编码}
  • 若是我选取{城市名,街道名}做为惟一标识实体的属性,那么{城市名,街道名} 就是主码(主键)

12)SQL 约束有哪几种?

  • NOT NULL: 用于控制字段的内容必定不能为空(NULL)。
  • UNIQUE: 控件字段内容不能重复,一个表容许有多个 Unique 约束。
  • PRIMARY KEY: 也是用于控件字段内容不能重复,但它在一个表只容许出现一个。
  • FOREIGN KEY: 用于预防破坏表之间链接的动做,也能防止非法数据插入外键列,由于它必须是它指向的那个表中的值之一。
  • CHECK: 用于控制字段的值范围。

13)MySQL存储引擎中的MyISAM和InnoDB区别详解

在MySQL 5.5以前,MyISAM是mysql的默认数据库引擎,其由早期的ISAM(Indexed Sequential Access Method:有索引的顺序访问方法)所改良。虽然MyISAM性能极佳,但却有一个显著的缺点: 不支持事务处理。不过,MySQL也导入了另外一种数据库引擎InnoDB,以强化参考完整性与并发违规处理机制,后来就逐渐取代MyISAM。

InnoDB是MySQL的数据库引擎之一,其由Innobase oy公司所开发,2006年五月由甲骨文公司并购。与传统的ISAM、MyISAM相比,InnoDB的最大特点就是支持ACID兼容的事务功能,相似于PostgreSQL。目前InnoDB采用双轨制受权,一是GPL受权,另外一是专有软件受权。具体地,MyISAM与InnoDB做为MySQL的两大存储引擎的差别主要包括:

  • 存储结构:每一个MyISAM在磁盘上存储成三个文件:第一个文件的名字以表的名字开始,扩展名指出文件类型。.frm文件存储表定义,数据文件的扩展名为.MYD (MYData),索引文件的扩展名是.MYI (MYIndex)。InnoDB全部的表都保存在同一个数据文件中(也多是多个文件,或者是独立的表空间文件),InnoDB表的大小只受限于操做系统文件的大小,通常为2GB。

  • 存储空间:MyISAM可被压缩,占据的存储空间较小,支持静态表、动态表、压缩表三种不一样的存储格式。InnoDB须要更多的内存和存储,它会在主内存中创建其专用的缓冲池用于高速缓冲数据和索引。

  • 可移植性、备份及恢复:MyISAM的数据是以文件的形式存储,因此在跨平台的数据转移中会很方便,同时在备份和恢复时也可单独针对某个表进行操做。InnoDB免费的方案能够是拷贝数据文件、备份 binlog,或者用 mysqldump,在数据量达到几十G的时候就相对痛苦了。

  • 事务支持:MyISAM强调的是性能,每次查询具备原子性,其执行数度比InnoDB类型更快,可是不提供事务支持。InnoDB提供事务、外键等高级数据库功能,具备事务提交、回滚和崩溃修复能力。

  • AUTO_INCREMENT:在MyISAM中,能够和其余字段一块儿创建联合索引。引擎的自动增加列必须是索引,若是是组合索引,自动增加能够不是第一列,它能够根据前面几列进行排序后递增。InnoDB中必须包含只有该字段的索引,而且引擎的自动增加列必须是索引,若是是组合索引也必须是组合索引的第一列。

  • 表锁差别:MyISAM只支持表级锁,用户在操做MyISAM表时,select、update、delete和insert语句都会给表自动加锁,若是加锁之后的表知足insert并发的状况下,能够在表的尾部插入新的数据。InnoDB支持事务和行级锁。行锁大幅度提升了多用户并发操做的新能,可是InnoDB的行锁,只是在WHERE的主键是有效的,非主键的WHERE都会锁全表的。

  • 全文索引:MyISAM支持 FULLTEXT类型的全文索引;InnoDB不支持FULLTEXT类型的全文索引,可是innodb可使用sphinx插件支持全文索引,而且效果更好。

  • 表主键:MyISAM容许没有任何索引和主键的表存在,索引都是保存行的地址。对于InnoDB,若是没有设定主键或者非空惟一索引,就会自动生成一个6字节的主键(用户不可见),数据是主索引的一部分,附加索引保存的是主索引的值。

  • 表的具体行数:MyISAM保存表的总行数,select count() from table;会直接取出出该值;而InnoDB没有保存表的总行数,若是使用select count() from table;就会遍历整个表,消耗至关大,可是在加了wehre条件后,myisam和innodb处理的方式都同样。

  • CURD操做:在MyISAM中,若是执行大量的SELECT,MyISAM是更好的选择。对于InnoDB,若是你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB表。DELETE从性能上InnoDB更优,但DELETE FROM table时,InnoDB不会从新创建表,而是一行一行的删除,在innodb上若是要清空保存有大量数据的表,最好使用truncate table这个命令。

  • 外键:MyISAM不支持外键,而InnoDB支持外键。

经过上述的分析,基本上能够考虑使用InnoDB来替代MyISAM引擎了,缘由是InnoDB自身不少良好的特色,好比事务支持、存储过程、视图、行级锁、外键等等。尤为在并发不少的状况下,相信InnoDB的表现确定要比MyISAM强不少。另外,必须须要注意的是,任何一种表都不是万能的,合适的才是最好的,才能最大的发挥MySQL的性能优点。若是是不复杂的、非关键的Web应用,仍是能够继续考虑MyISAM的,这个具体状况具体考虑。


14)MyIASM和Innodb两种引擎所使用的索引的数据结构是什么?

答案:都是B+树!

MyIASM引擎,B+树的数据结构中存储的内容其实是实际数据的地址值。也就是说它的索引和实际数据是分开的,只不过使用索引指向了实际数据。这种索引的模式被称为非汇集索引。

Innodb引擎的索引的数据结构也是B+树,只不过数据结构中存储的都是实际的数据,这种索引有被称为汇集索引。


15)varchar和char的区别

char是一种固定长度的类型,varchar是一种可变长度的类型,例如:

定义一个char[10]和varchar[10],若是存进去的是 'test',那么char所占的长度依然为10,除了字符 'test' 外,后面跟六个空格,varchar就立马把长度变为4了,取数据的时候,char类型的要用trim()去掉多余的空格,而varchar是不须要的

char的存取速度仍是要比varchar要快得多,由于其长度固定,方便程序的存储于查找

char也为此付出的是空间的代价,由于其长度固定,因此不免会有多余的空格占位符占据空间,可谓是以空间换取时间效率。

varchar是以空间效率为首位。

char的存储方式是:对英文字符(ASCII)占用1个字节,对一个汉字占用两个字节。

varchar的存储方式是:对每一个英文字符占用2个字节,汉字也占用2个字节。
二者的存储数据都非unicode的字符数据。


16)主键、自增主键、主键索引与惟一索引概念区别

  1. 主键:指字段 惟1、不为空值 的列;

  2. 主键索引:指的就是主键,主键是索引的一种,是惟一索引的特殊类型。建立主键的时候,数据库默认会为主键建立一个惟一索引;

  3. 自增主键:字段类型为数字、自增、而且是主键;

  4. 惟一索引:索引列的值必须惟一,但容许有空值。主键是惟一索引,这样说没错;但反过来讲,惟一索引也是主键就错误了,由于惟一索引容许空值,主键不容许有空值,因此不能说惟一索引也是主键。


17)主键就是汇集索引吗?主键和索引有什么区别?

主键是一种特殊的惟一性索引,其能够是汇集索引,也能够是非汇集索引。在SQLServer中,主键的建立必须依赖于索引,默认建立的是汇集索引,但也能够显式指定为非汇集索引。InnoDB做为MySQL存储引擎时,默认按照主键进行汇集,若是没有定义主键,InnoDB会试着使用惟一的非空索引来代替。若是没有这种索引,InnoDB就会定义隐藏的主键而后在上面进行汇集。因此,对于汇集索引来讲,你建立主键的时候,自动就建立了主键的汇集索引。


18)实践中如何优化MySQL

实践中,MySQL的优化主要涉及SQL语句及索引的优化、数据表结构的优化、系统配置的优化和硬件的优化四个方面,以下图所示:

 
 

⑴ SQL语句优化:

SQL语句的优化主要包括三个问题,即如何发现有问题的SQL、如何分析SQL的执行计划以及如何优化SQL,下面将逐一解释。

① 怎么发现有问题的SQL?(经过MySQL慢查询日志对有效率问题的SQL进行监控)

MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阀值的语句,具体指运行时间超过long_query_time值的SQL,则会被记录到慢查询日志中。long_query_time的默认值为10,意思是运行10s以上的语句。慢查询日志的相关参数以下所示:

 
 

经过MySQL的慢查询日志,咱们能够查询出执行的次数多占用的时间长的SQL、能够经过pt_query_disgest(一种mysql慢日志分析工具)分析Rows examine(MySQL执行器须要检查的行数)项去找出IO大的SQL以及发现未命中索引的SQL,对于这些SQL,都是咱们优化的对象。

② 经过explain查询和分析SQL的执行计划:

使用 EXPLAIN 关键字能够知道MySQL是如何处理你的SQL语句的,以便分析查询语句或是表结构的性能瓶颈。经过explain命令能够获得表的读取顺序、数据读取操做的操做类型、哪些索引可使用、哪些索引被实际使用、表之间的引用以及每张表有多少行被优化器查询等问题。当扩展列extra出现Using filesort和Using temporay,则每每表示SQL须要优化了。

③ SQL语句的优化:

⒈优化insert语句:一次插入多值;

⒉应尽可能避免在 where 子句中使用!=或<>操做符,不然将引擎放弃使用索引而进行全表扫描;

⒊应尽可能避免在 where 子句中对字段进行null值判断,不然将致使引擎放弃使用索引而进行全表扫描;

⒋优化嵌套查询:子查询能够被更有效率的链接(Join)替代;

⒌不少时候用 exists 代替 in 是一个好的选择。

⒍选择最有效率的表名顺序:数据库的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表将被最早处理

在FROM子句中包含多个表的状况下:

  • 若是三个表是彻底无关系的话,将记录和列名最少的表,写在最后,而后依次类推
  • 也就是说:选择记录条数最少的表放在最后

若是有3个以上的表链接查询:

  • 若是三个表是有关系的话,将引用最多的表,放在最后,而后依次类推。
  • 也就是说:被其余表所引用的表放在最后

⒎用IN代替OR:

select * from emp where sal = 1500 or sal = 3000 or sal = 800; select * from emp where sal in (1500,3000,800); 

⒏SELECT子句中避免使用*号:

咱们最开始接触 SQL 的时候,“*” 号是能够获取表中所有的字段数据的,可是它要经过查询数据字典完成,这意味着将消耗更多的时间,并且使用 “*” 号写出来的 SQL 语句也不够直观。


⑵ 索引优化:

建议在常常做查询选择的字段、常常做表链接的字段以及常常出如今 order by、group by、distinct 后面的字段中创建索引。但必须注意如下几种可能会引发索引失效的情形:

  • 以 “%(表示任意0个或多个字符)” 开头的 LIKE 语句,模糊匹配;

  • OR语句先后没有同时使用索引;

  • 数据类型出现隐式转化(如varchar不加单引号的话可能会自动转换为int型);

  • 对于多列索引,必须知足最左匹配原则(eg,多列索引col一、col2和col3,则 索引生效的情形包括col1或col1,col2或col1,col2,col3)。


⑶ 数据库表结构的优化:

① 选择合适数据类型:

  • 使用较小的数据类型解决问题;
  • 使用简单的数据类型(mysql处理int要比varchar容易);
  • 尽量的使用not null 定义字段;
  • 尽可能避免使用text类型,非用不可时最好考虑分表;

② 表的范式的优化:

通常状况下,表的设计应该遵循三大范式。

③ 表的垂直拆分:

把含有多个列的表拆分红多个表,解决表宽度问题,具体包括如下几种拆分手段:

  • 把不经常使用的字段单独放在同一个表中;
  • 把大字段独立放入一个表中;
  • 把常用的字段放在一块儿;

这样作的好处是很是明显的,具体包括:拆分后业务清晰,拆分规则明确、系统之间整合或扩展容易、数据维护简单

④ 表的水平拆分:

表的水平拆分用于解决数据表中数据过大的问题,水平拆分每个表的结构都是彻底一致的。通常地,将数据平分到N张表中的经常使用方法包括如下两种:

  • 对ID进行hash运算,若是要拆分红5个表,mod(id,5)取出0~4个值;
  • 针对不一样的hashID将数据存入不一样的表中;

表的水平拆分会带来一些问题和挑战,包括跨分区表的数据查询、统计及后台报表的操做等问题,但也带来了一些切实的好处:

  • 表分割后能够下降在查询时须要读的数据和索引的页数,同时也下降了索引的层数,提升查询速度;
  • 表中的数据原本就有独立性,例如表中分别记录各个地区的数据或不一样时期的数据,特别是有些数据经常使用,而另一些数据不经常使用。
  • 须要把数据存放到多个数据库中,提升系统的整体可用性(分库,鸡蛋不能放在同一个篮子里)。

⑷ 系统配置的优化:

  • 操做系统配置的优化:增长TCP支持的队列数

  • mysql配置文件优化:Innodb缓存池设置(innodb_buffer_pool_size,推荐总内存的75%)和缓存池的个数(innodb_buffer_pool_instances)


⑸ 硬件的优化:

  • CPU:核心数多而且主频高的
  • 内存:增大内存
  • 磁盘配置和选择:磁盘性能

欢迎转载,转载请注明出处!转载自@我没有三颗心脏

相关文章
相关标签/搜索