FOURTEEN------MySQL

236 阅读24分钟

**1、数据库的三范式是什么? **
• 第一范式:

1NF 是对属性的原子性约束!	

强调的是列的原子性(字段是最小的的单元不可再分,学生信息组成学生信息表,有年龄、性别、学号等信息组成。
这些字段都不可再分,所以它是满足第一范式的)

• 第二范式:

2NF 是对记录的惟一性约束!

表中的字段必须完全依赖于全部主键(学号为1024的同学,姓名为Java3y,年龄是22岁,
姓名和年龄字段都依赖着学号主键)

• 第三范式:

3NF 是对字段冗余性的约束!

非主键外的所有字段必须互不依赖。(比如,我们大学分了很多系(中文系、英语系、计算机系……),
这个系别管理表信息有以下字段组成:系编号,系主任,系简介,系架构。那我们能不能在学生信息表
添加系编号,系主任,系简介,系架构字段呢?不行的,因为这样就冗余了,
非主键外的字段形成了依赖关系(依赖到学生信息表了)!正确的做法是:学生表就只能增加一个系编号字段。)

**2、什么是视图?以及视图的使用场景有哪些? **
视图是一种基于数据表的一种虚拟的表。也就是说,视图可以将查询出来的数据进行封装。。。那么我们在使用的时候就会变得非常方便。(使用视图可以让我们专注于逻辑,但不提高查询效率)

3、 MySQL 中有哪些表类型?
共有 5 种类型的表格:

MyISAM  
INNODB  
Heap  
Merge  
ISAM

4、一张表,里面有 ID 自增主键,当 insert 了 17 条记录之后,删除了第 15,16,17 条记录, 再把 Mysql 重启,再 insert 一条记录,这条记录的 ID 是 18 还是 15 ?
(1)如果表的类型是 MyISAM

那么是 18,因为 MyISAM 表会把自增主键的最大 ID 记录到数据文件里,重启 MySQL 自增主键的最大
ID 也不会丢失

(2)如果表的类型是 InnoDB

那么是 15,InnoDB 表只是把自增主键的最大 ID 记录到内存中,所以重启数据库或者是对表进行
OPTIMIZE 操作,都会导致最大ID丢失

**5、MySQL服务器默认端口是多少? **

3306

6、如何获取当前数据库版本?
使用 select version() 获取当前 MySQL 数据库版本。

7、数据库中的事务是什么
事务(Transaction)是作为一组有序的数据库操作,一个支持事务的数据库系统,必需要具有ACID四种特性。

如果组中的所有操作都成功,则认为事务成功,事务则提交。
即使只有一个操作失败,事务也不成功则事务将回滚。  

8、ACID是什么?可以详细说一下吗?
• Atomicity(原子性)[ˌætəˈmɪsəti]

一个事务中的所有操作,或者全部成功,或者全部失败。

• Consistency(一致性)[kənˈsɪstənsi]

数据库总是从一个一致性状态转换到另一个一致性状态。比如AB转账100元,假设中间sql执行过程系统崩溃,
A也不会损失100元,因为事务没有提交,修改也就不会保存到数据库中。

• Isolation(隔离性)[ˌaɪsəˈleɪʃn]

一个事务的修改在最终提交前,对其他事务是不可见的。  
事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、
可重复读(repeatable read)和串行化(Serializable)

• Durability(持久性) [djʊərəˈbɪləti]

事务一旦提交,对数据的修改会永久保存到数据库中,即便系统故障也不会丢失。  

9、事务不考虑隔离性可能会引发的问题,同时有多个事务在进行会怎么样呢?
多事务的并发进行一般会造成以下几个问题:

脏读: 在事务A修改数据之后提交数据之前,这时另一个事务B来读取数据,如果不加控制,
事务B读取到A修改过数据,之后A又对数据做了修改再提交,则B读到的数据是脏数据,此过程称为脏读
(例如:AB转账,A执行了转账语句,但A还没有提交事务,B读取数据,发现自己账户钱变多了!
BA说,我已经收到钱了。A回滚事务【rollback】,等B再查看账户的钱时,发现钱并没有多。)

不可重复读: 事务A首先读取了一条数据,然后执行逻辑的时候,事务B将这条数据改变了,
然后事务A再次读取的时候,发现数据不匹配了,就是所谓的不可重复读。

幻读: 事务A在按查询条件读取某个范围的记录时,事务B又在该范围内插入了新的满足条件的记录,
当事务A再次按条件查询记录时,会产生新的满足条件的记录

9.1、不可重复读与幻读有什么区别?
不可重复读的重点是修改:在同一事务中,同样的条件,第一次读的数据和第二次读的「数据不一样」。(因为中间有其他事务提交了修改)
幻读的重点在于新增或者删除:在同一事务中,同样的条件,第一次和第二次读出来的「记录数不一样」。(因为中间有其他事务提交了插入/删除)

10、MySQL的事务隔离级别了解吗?解决了什么问题
多个线程开启各自事务操作数据库中数据时,数据库系统要负责隔离操作,以保证各个线程在获取数据时的准确性。数据库定义了4个隔离级别:

Read uncommitted【什么都避免不了】
Read committed【可避免脏读】
Repeatable read【可避免脏读,不可重复读】
Serializable【可避免脏读,不可重复读,虚读】

各个隔离级别可以不同程度的解决脏读、不可重复读、幻读。

MySQL数据库查询当前事务隔离级别:select @@tx_isolation
MySQL数据库默认的事务隔离级别是:Repeatable read(可重复读)
MySQL 的事务隔离是在 MySQL. ini 配置文件里添加的,
在文件的最后添加:transaction-isolation = REPEATABLE-READ

11、char 和 varchar 的区别是什么?
char最多可以存放255个字符,varchar的最大长度为65535个字节
从空间上考虑 varcahr 比较合适;从效率上考虑 char 比较合适
**12、float 和 double 的区别是什么? **

float 最多可以存储 8 位的十进制数,并在内存中占 4 字节。
double 最可可以存储 16 位的十进制数,并在内存中占 8 字节

13、MySQL的内连接、左连接、右连接有什么区别?
内连接关键字:inner join;左连接:left join;右连接:right join
内连接是把匹配的关联数据显示出来;左连接是左边的表全部显示出来,右边的表显示出符合条件的数据;右连接正好相反。

**14、MySQL索引是怎么实现的? **
索引是一种高效获取数据的存储结构,索引可以大大提高 MySQL 的检索速 度。MySQL 中的索引,不同的数据引擎实现有所不同,但目前主流的数据库引擎的索引都是 B+ 树实现的。

15、说一下MySQL常用的引擎?
存储引擎也称为表类型。
• MyISAM 引擎是 my-z[ei]m

MyISAM 引擎是MySQL 5.1版本前的默认引擎,但不提供事务的支持,也不支持行级锁和外键。
因此当执行插入和更新语句时,即执行写操作的时候需要锁定这个表,所以会导致效率会降低。
不过和 InnoDB 不同的是,MyISAM 引擎是保存了表的行数,于是当进行
select count(*) from table 语句时,可以直接的读取已经保存的值而不需要进行扫描全表。
所以,如果表的读操作远远多于写操作时,并且不需要事务的支持的,可以将 MyISAM 作为数据库引擎的首选。

• InnoDB 引擎:

InnoDB 引擎提供了对数据库 acid 事务的支持,并且还提供了行级锁和外键的约束,
它的设计的目标就是处理大数据容量的数据库系统。MySQL 运行的时候,InnoDB 会在内存中建立缓冲池,
用于缓冲数据和索引。但是该引擎是不支持全文搜索,同时启动也比较的慢,它是不会保存表的行数的,
所以当进行 select count(*) from table 指令的时候,需要进行扫描全表。
由于锁的粒度小,写操作是不会锁定全表的,所以在并发度较高的场景下使用会提升效率的。

16、对MySQL的锁了解吗? Mysql数据库是否发生死锁? 死锁的解决办法?
MySQL有三种锁的级别:表级、行级、页级

表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。

行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般  

Mysql存储引擎为MyISAM时

MyISAM中不会出现死锁。
在MyISAM中只用到表锁,不会有死锁的问题,锁的开销也很小,但是相应的并发能力很差。

Mysql存储引擎为InnoDB时

InnoDB中会出现死锁,InnoDB中实用了行锁和表锁

死锁的解决办法

1.查出死锁进程,并杀掉进程
2.设置锁的超时时间
3.指定获取锁的顺序

**17、说一下 MySQL 的行锁和表锁? **
MyISAM 只支持表锁,InnoDB 支持表锁和行锁,默认为行锁。

表级锁:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发量最低。

行级锁:开销大,加锁慢,会出现死锁。锁力度小,发生锁冲突的概率小,并发度最高。

18、说一下MySQL乐观锁和悲观锁以及实现方式?
MyISAM引擎不支持事务,所以不考虑它有乐观锁和悲观锁概念。MyISAM只有表锁,锁又分为读锁和写锁。在这里我们只讨论InnoDB引擎

乐观锁:每次去拿数据的时候都认为别人不会修改,所以不会上锁,
但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。

悲观锁:每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,
这样别人想拿这个数据就会阻止,直到这个锁被释放。

乐观锁是从应用系统层面上做并发控制,去加锁。
乐观锁实现方式:版本号version

在表里面添加一个 version 字段,每次修改成功值加 1,这样每次修改的时候先对比一下,
自己拥有的 version 和数据库现在的 version 是否一致,如果相同,则说明该条数据没有被修改过,
执行更新。如果比对的结果是不一致的,则说明该条数据已经被其他人修改过了,则不更新,这样就实现了乐观锁。

悲观锁是从数据库层面上做并发控制,去加锁。
悲观锁的实现方式有两种:共享锁(读锁)和排它锁(写锁)

共享锁(IS锁),实现方式是在sql后加LOCK IN SHARE MODE,
比如SELECT ... LOCK IN SHARE MODE,即在符合条件的rows上都加了共享锁,
这样的话,其他session可以读取这些记录

排它锁(IX锁),实现方式是在sql后加FOR UPDATE,比如SELECT ... FOR UPDATE ,
即在符合条件的rows上都加了排它锁,其他session也就无法在这些记录上添加任何的S锁或X锁。

19、MyIASM和InnoDB两种引擎所使用的索引的数据结构是什么?
都是B+\color{green}{都是B+树}

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

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

20、什么是索引? 索引是个什么样的数据结构呢?
索引是一种数据结构,可以帮助我们快速的进行数据的查找。
索引的数据结构和具体存储引擎的实现有关, 在MySQL中使用较多的索引有Hash索引,B+树索引等,而我们经常使用的InnoDB存储引擎的默认索引实现为:B+树索引

21、MySQL 的B+Tree索引和Hash索引的区别?
首先要知道Hash索引和B+树索引的底层实现原理:

hash索引底层就是hash表,进行查找时,调用一次hash函数就可以获取到相应的键值,之后进行回表查询获得实际数据。
B+树底层实现是多路平衡查找树.对于每一次的查询都是从根节点出发,查找到叶子节点方可以获得所查键值,查询数据。

那么可以看出它们有以下的不同:

hash索引进行等值查询更快(一般情况下),但是却无法进行范围查询;

同理,hash索引也没办法利用索引完成排序,以及like 这样的部分模糊查询
(这种部分模糊查询,其实本质上也是范围查询); 

hash索引任何时候都避免不了回表查询数据,
而B+树在符合某些条件(聚簇索引,覆盖索引等)的时候可以只通过索引完成查询。

因此,在大多数情况下,直接选择B+树索引可以获得稳定且较好的查询速度,而不需要使用hash索引。

22、上面提到了B+树在满足聚簇索引和覆盖索引的时候不需要回表查询数据,什么是聚簇索引?以及和非聚簇索引的区别
聚簇索引就是按照每张表的主键构造一颗B+树,同时叶子节点中存放的就是整张表的行记录数据,每张表只能拥有一个聚簇索引。

聚集索引一个表只能有一个,而非聚集索引一个表可以存在多个

聚集索引存储记录是物理上连续存在,而非聚集索引是逻辑上的连续,物理存储并不连续  

聚集索引和非聚集索引的根本区别是表记录的排列顺序和与索引的排列顺序是否一致:
聚集索引表记录的排列顺序和索引的排列顺序一致,所以查询效率快,
只要找到第一个索引值记录,其余就连续性的记录在物理也一样连续存放。
非聚集索引制定了表中记录的逻辑顺序,但是记录的物理和索引不一定一致

23、在建立索引的时候,都有哪些需要考虑的因素呢?
建立索引的时候一般要考虑到字段的使用频率,经常作为条件进行查询的字段比较适合,如果需要建立联合索引的话,还需要考虑联合索引中的顺序。

24、如何优化查询

为搜索字段创建索引(可以考虑使用索引的主要有两种类型的列:在where子句中出现的列,在join子句中出现的列)

SELECT子句中避免使用‘*’:

垂直分割分表。

尽量多使用COMMIT

25、非关系型数据库和关系型数据库区别,优势比较?

当前主流的关系型数据库有

关系型数据库是采用关系模型来组织数据结构的数据库(二维表)

非关系型数据库有
NoSql的分类:

1.键值型数据库  (Redis)  
2.文档型数据库  (MongoDB)  
3.列存储数据库  (HBase)  
4.图形数据库  

关系型数据库和非关系型数据库比较:

• 查询速度:非关系型数据库将数据存储于缓存之中,关系型数据库将数据存储在硬盘中,
           查询速度远不及非关系型数据库。

• 存储数据的格式:非关系型数据库的存储格式是key-value形式、文档形式、图片形式等等,所以可以存储基础类型
                以及对象或者是集合等各种格式,而关系型数据库则只支持基础类型。

• 数据一致性:非关系型数据库一般强调的是数据最终一致性,而不没有像关系型数据库ACID一样强调数据的强一致性。
            所以如果你的业务对于数据的一致性要求很高,那么关系型数据库是很好的选择。

26、谈一谈MySQL数据库的读写分离、主从复制问题?

在实际的生产环境中,对数据库的读和写都在同一个数据库服务器中,是不能满足实际需求的。因此,通过主从复制的方式来同步数据,再通过读写分离来提升数据库的并发负载能力。 一、主从复制
主(Master)从(Slave)复制的工作过程: 主从复制的几种方式:

• 同步复制: master 的变化,必须等待 slave-1,slave-2,…,slave-n 完成后才能返回。 这样,显然不可取。
           比如,在 WEB 前端页面上,用户增加了条记录,需要等待很长时间。

• 异步复制:如同 AJAX 请求一样。master 只需要完成自己的数据库操作即可。至于 slaves 是否收到二进制日志,
          是否完成操作,不用关心,MySQL 的默认设置。

• 半同步复制:master 只保证 slaves 中的一个操作成功,就返回,其他 slave 不管。

随着应用的日益增长,读操作很多,我们可以扩展 slave,但是如果 master 满足不了写操作了,怎么办呢?
------可以分库【垂直拆分】,分表【水平拆分】。

二、读写分离

读写分离就是在主服务器上修改,数据会同步到从服务器,从服务器只能提供读取数据,不能写入。实现备份的同时,也实现了数据库性能的优化,以及提升了服务器安全。

27、MySQL慢查询怎么解决?

常见的慢查询优化:
1.索引没起作用的情况

使用LIKE关键字的查询语句:在使用LIKE关键字进行查询的查询语句中,如果匹配字符串的第一个字符为“%”,
索引不会起作用。只有“%”不在第一个位置索引才会起作用。

2.优化数据库结构

将字段很多的表分解成多个表:对于字段比较多的表,如果有些字段的使用频率很低,可以将这些字段分离出来形成新表。
因为当一个表的数据量很大时,会由于使用频率低的字段的存在而变慢。

3.分解关联查询

将一个大的查询分解为多个小查询是很有必要的。

4.优化LIMIT分页

分页的操作通常会使用limit加上偏移量的方法实现,同时加上合适的order by 子句。如果有对应的索引,
通常效率会不错。一个非常令人头疼问题就是当偏移量非常大的时候,例如可能是limit 10000,20这样的查询,
这是MySQL需要查询10020条然后只返回最后20条,前面的10000条记录都将被舍弃,这样的代价很高。

优化此类查询的一个最简单的方法是尽可能的使用索引覆盖扫描,而不是查询所有的列。然后根据需要做一次关联操作
再返回所需的列。select id,title from collect limit 90000,10;

28、MySQL高并发环境解决方案?

解决方式:

水平分库分表:由单点分布到多点数据库中,从而降低单点数据库压力。

引入集群方案:解决数据库宕机带来的单点数据库不能访问的问题。

读写分离策略:极大限度提高了应用中读数据的速度和并发量。无法解决高写入压力

29、查询语句不同元素(where、jion、limit、group by、having等等)执行先后顺序?

一个查询语句同时出现了where,group by,having,order by的时候,执行顺序和编写顺序是:
通过一个顺口溜总结下顺序:我(W)哥(G)是(SH)偶(O)像。按照执行顺序的关键词首字母分别是W(Where,指定搜索条件)->G(Group,分组)->S(Select)->H(Having,对记录进行筛选)->O(Order,排序检索)

30、MySQL 问题排查都有哪些手段?

使用 show processlist 命令查看当前所有连接信息。
使用 explain 命令查询 SQL 语句执行计划。
开启慢查询日志,查看慢查询的 SQL

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

超键(super key): 在关系中能唯一标识元组的属性集称为超键

候选键(candidate key):不含有多余属性的超键称为候选键。也就是在候选键中,若再删除属性,就不是键了!

主键(primary key): 用户选作元组标识的一个候选键称为主键

外键(foreign key):如果关系模式R中属性K是其它模式的主键,那么K在模式R中称为外键

对于学生信息表(学号 身份证号 性别 年龄 身高 体重 宿舍号)
以及宿舍信息表(宿舍号 楼号)

超键:只要含有“学号”或者“身份证号”两个属性的集合就叫超键

候选键:不含有多余的属性的超键,比如(学号)、(身份证号)都是候选键

主键:就是用户从很多候选键选出来的一个键就是主键,比如你要求学号是主键,那么身份证号就不可以是主键了!

外键:宿舍号就是学生信息表的外键

32、SQL 约束有哪几种?

SQL约束(Constraints)主要用于规定表中的数据规则,在SQL中,有如下约束:

NOT NULL -用于控制字段的内容一定不能为空(NULL)
• UNIQUE-控件字段内容不能重复,一个表允许有多个 Unique 约束
• PRIMARY KEY-也是用于控件字段内容不能重复,但它在一个表只允许出现一个
• FOREIGN KRY-保证一个表中的数据匹配另一个表中的值的参照完整性。
• CHECK-保证字段内容符合指定的条件
• DEFAULT-规定没有给字段内容赋值时的默认值。

33、drop、delete与truncate分别在什么场景之下使用?

相同点:

1.truncate和不带where子句的delete、以及drop都会删除表内的数据。[trʌŋˈkeɪt]
2.droptruncate都是DDL语句(数据定义语言),执行后会自动提交。

不同点:

1. truncatedelete 只删除数据不删除表的结构(定义)
   drop 语句将删除表的结构被依赖的约束(constrain)、触发器(trigger)、索引(index);
   
2.delete 语句是数据库操作语言(DML),这个操作会放到 rollback segement 中,事务提交之后才生效;
如果有相应的 trigger,执行的时候将被触发。  
truncatedrop 是数据库定义语言(DDL),操作立即生效,原数据不放到 rollback segment 中,不能回滚,
操作不触发 trigger3.速度,一般来说: drop> truncate > delete

34、MySQL 支持事务吗?

在缺省模式下,MySQL 是 autocommit 模式的,所有的数据库更新操作都会即时提交,
所以在缺省情况下,MySQL 是不支持事务的。

但是如果你的 MySQL 表类型是使用 InnoDB Tables 或 BDB tables 的话,你的MySQL 就可以使用事务处理,使用 SET AUTOCOMMIT=0 就可以使 MySQL 允许在非 autocommit 模式,在非autocommit 模式下,你必须使用 COMMIT 来提交你的更改,或者用 ROLLBACK来回滚你的更改。

35、说一说 MySQL 的水平分割和垂直分割

垂直分割和水平分割的区别就是;水平分割是分割记录,以一条记录/行为单位。垂直分割则是以列为单位,将列分割出去。

• 水平分割:

例:QQ的登录表。假设QQ的用户有100亿,如果只有一张表,每个用户登录的时候数据库都要从这100亿中查找,
会很慢很慢。如果将这一张表分成100份,每张表有1亿条,就小了很多,比如qq0,qq1,qq1...qq99表。  
用户登录的时候,可以将用户的id%100,那么会得到0-99的数,查询表的时候,将表名qq跟取模的数连接起来,
就构建了表名。比如123456789用户,取模的89,那么就到qq89表查询,查询的时间将会大大缩短。

• 垂直分割:

表的记录并不多,但是字段却很长,表占用空间很大,检索表的时候需要执行大量的IO,严重降低了性能。
这时需要把大的字段拆分到另一个表,并且该表与原表是一对一的关系。
例如学生答题表tt:有如下字段:Id name 分数 题目 回答。其中题目和回答是比较大的字段,id name 分数比较小。
如果我们只想查询id为8的学生的分数:select 分数 from tt where id = 8;虽然知识查询分数,
但是题目和回答这两个大字段也是要被扫描的,很消耗性能。但是我们只关心分数,并不想查询题目和回答。
这就可以使用垂直分割。我们可以把题目单独放到一张表中,通过id与tt表建立一对一的关系,
同样将回答单独放到一张表中。这样我们插叙tt中的分数的时候就不会扫描题目和回答了。

36、手撕SQL语句

1.如何显示前 50 行
SELECT*FROM LIMIT 0,50;

2.用一条 SQL 语句查询出每门课都大于 80 分的学生姓名 A:SELECT DISTINCT name FROM score WHERE name NOT IN (SELECT DISTINCT name FROM score WHERE score <=80 )

3.查询平均分大于80的学生的姓名
A.SELECT name FROM score group by name having AVG(score)>80; B.SELECT name, avg(score) as sc from score group by name having AVG(score)>80; 4.如下为某公司8月份的员工薪资表。请根据各小题的需求,用Sql代码实现

(1)输出第一个名字(First_name)包含‘o’的所有雇员信息,并按薪资降序排列;

(2)输出总支出工资大于1500000 的部门和对应的支出,按降序排序