1、事务四大特性
- 原子性: 根据定义,原子性是指一个事务是一个不可分割的工作单位,其中的操作要么都做,要么都不做。即要么转账成功,要么转账失败,是不存在中间的状态!
MySQL
的InnoDB
引擎是靠undo log
(回滚日志)来实现的,undo log
能够保证在事务回滚时,能够撤销所有已经执行成功的SQL
。 - 一致性: 根据定义,一致性是指事务执行前后,数据处于一种合法的状态,这种状态是语义上的而不是语法上的。通过原子性、隔离性、持久性是为了保证一致性所做的措施。
- 隔离性: 根据定义,隔离性是指多个事务并发执行的时候,事务内部的操作与其他事务是隔离的,并发执行的各个事务之间不能互相干扰。通过
MVCC
机制和锁解决。 - 持久性: 根据定义,持久性是指事务一旦提交,它对数据库的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。
MySQL
事务的持久性是通过redo log
来实现的。
binlog
的作用:(1)是用于复制,在主从复制中,从库利用主库上的binlog
进行重播,实现主从同步。(2)用于数据库的基于时间点的还原。
1.1、redo log
和bin log
的区别
-
redo log
是在InnoDB
存储引擎层产生,而bin log
是MySQL
数据库的上层产生的,并且二进制日志不仅仅针对INNODB
存储引擎,MySQL
数据库中的任何存储引擎对于数据库的更改都会产生二进制日志。 -
两种日志记录的内容形式不同。
MySQL
的binlog
是逻辑日志,其记录是对应的SQL
语句。而INNODB
存储引擎层面的重做日志是物理日志。 -
两种日志与记录写入磁盘的时间点不同,二进制日志只在事务提交完成后进行一次写入。而
INNODB
存储引擎的重做日志在事务进行中不断地被写入,并日志不是随事务提交的顺序进行写入的。二进制日志仅在事务提交时记录,并且对于每一个事务,仅在事务提交时记录,并且对于每一个事务,仅包含对应事务的一个日志。而对于
INNODB
存储引擎的重做日志,由于其记录是物理操作日志,因此每个事务对应多个日志条目,并且事务的重做日志写入是并发的,并非在事务提交时写入,其在文件中记录的顺序并非是事务开始的顺序。 -
bin log
不是循环使用,在写满或者重启之后,会生成新的bin log
文件,redo log
是循环使用。 -
bin log
可以作为恢复数据使用,主从复制搭建,redo log
作为异常宕机或者介质故障后的数据恢复使用。
1.2、三大范式
- 第一范式: 数据库中所有的属性字段都是不可分解的,即我们创建的属性在此字段中一定是你设计表的最小的字段值,遵循数据的原子性;
- 第二范式: 表中的属性字段必须依赖于表的主键;
- 第三范式: 不能出现传递依赖。
第一范式规定表中的每个列都应该是不可分割的最小单元。第二范式是在满足第一范式的基础上,规定表中的非主键列不存在对主键的部分依赖。第三范式是在满足第一范式和第二范式的基础上,规定表中的列不存在对非主键列的传递依赖。使用数据库三范式的优势是:表的结构更简单、优雅,表的逻辑和条理性更强,并且使用三范式可以很大程度的减少表中的冗余数据,很好的节省了数据库的存储资源。
2、事务的并发?事务隔离级别,每个级别会引发什么问题,MySQL
默认是哪个级别?
ISOLATION_DEFAULT
:用底层数据库的设置隔离级别,数据库设置的是什么我就用什么;ISOLATION_READ_UNCOMMITTED
: 未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读);ISOLATION_READ_COMMITTED
:提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读),SQL Server
的默认级别;ISOLATION_REPEATABLE_READ
: 可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读),MySQL
的默认级别;ISOLATION_SERIALIZABLE
:串行化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。
隔离级别 | 脏读 | 不可重复读 | 幻读 |
读未提交(Read Uncommitted ) | √ | √ | √ |
读已提交(Read committed ) | × | √ | √ |
可重复读(Repeatable read ) | × | × | √ |
可串行化(Serializable ) | × | × | × |
如何设置隔离级别,即隔离级别的命令?
// 设置read uncommitted级别:
set session transaction isolation level read uncommitted;
// 设置read committed级别:
set session transaction isolation level read committed;
// 设置repeatable read级别:
set session transaction isolation level repeatable read;
// 设置serializable级别:
set session transaction isolation level serializable;
3、什么是脏读、幻读和不可重复度?
答: 不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表。
- 脏读: 事务
A
读取事务B
更新的数据,然后B
回滚操作,那么A
读取到的数据是脏数据。 - 不可重复读: 事务
A
多次读取同一数据,事务B
在事务A
多次读取的过程中,对数据作了更新并提交,导致事务A
多次读取同一数据时,结果不一致。 - 幻读: 事务
A
,读取所有工资为1000的员工,共读取10条记录,事务B
向employee
表插入了一条员工记录,工资也为1000,事务A
再次读取所有工资为1000的员工,共读取到了11条记录,这就产生了幻读。
4、MySQL
常见的三种存储引擎的区别?
InnoDB
: 支持事务处理,支持外键,支持崩溃修复能力和并发控制。如果需要对事务的完整性要求比较高(比如银行),要求实现并发控制(比如售票),那选择InnoDB
有很大的优势。如果需要频繁的更新、删除操作的数据库,也可以选择InnoDB
,因为支持事务的提交(commit
)和回滚(rollback)
。MyISAM
:插入数据快,空间和内存使用比较低。如果表主要是用于插入新记录和读出记录,那么选择MyISAM
能实现处理高效率。如果应用的完整性、并发性要求比较低,也可以使用。MEMORY
:所有的数据都在内存中,数据的处理速度快,但是安全性不高。如果需要很快的读写速度,对数据的安全性要求较低,可以选择MEMOEY
。它对表的大小有要求,不能建立太大的表。所以,这类数据库只使用在相对较小的数据库表。
5、MySQL
的MyISAM
与InnoDB
两种存储引擎在,事务、锁级别,各自的适用场景?
5.1、MyISAM
特点
- 不支持行锁(
MyISAM
只有表锁),读取时对需要读到的所有表加锁,写入时则对表加排他锁; - 不支持事务
- 不支持外键
- 不支持崩溃后的安全恢复
- 在表有读取查询的同时,支持往表中插入新纪录
- 支持
BLOB
和TEXT
的前500个字符索引,支持全文索引 - 支持延迟更新索引,极大地提升了写入性能
- 对于不会进行修改的表,支持压缩表,极大地减少了磁盘空间的占用
5.2、InnoDB
特点
- 支持行锁,采用
MVCC
来支持高并发,有可能死锁 - 支持事务
- 支持外键
- 支持崩溃后的安全恢复
- 不支持全文索引
5.3、InnoDB
四大特性
- 插入缓冲
(insert buffer)
- 二次写
(double write)
- 自适应哈希索引
(ahi)
- 预读
(read ahead)
5.4、MyISAM
和 InnoDB
两者的应用场景
MyISAM
管理非事务表。它提供高速存储和检索,以及全文搜索能力。如果应用中需要执行大量的SELECT
查询,那么MyISAM
是更好的选择。InnoDB
用于事务处理应用程序,具有众多特性,包括ACID
事务支持。如果应用中需要执行大量的INSERT
或UPDATE
操作,则应该使用InnoDB
,这样可以提高多用户并发操作的性能。
6、查询语句不同元素(where
、join
、limit
、group by
、having
等等)执行先后顺序?
- 执行
where xx
对全表数据做筛选,返回第1个结果集。 - 针对第1个结果集使用
group by
分组,返回第2个结果集。 - 针对第2个结果集中的每1组数据执行
select xx
,有几组就执行几次,返回第3个结果集。 - 针对第3个结集执行
having xx
进行筛选,返回第4个结果集。 - 针对第4个结果集排序。
通过一个顺口溜总结下顺序:我(
W
)哥(G
)是(SH
)偶(O
)像。按照执行顺序的关键词首字母分别是W(where)->G(Group)->S(Select)->H(Having)->O(Order)
,对应汉语首字母可以编成容易记忆的顺口溜:我(W
)哥(G
)是(SH
)偶(O
)像
7、什么是临时表,临时表什么时候删除?
答: MySQL
用于存储一些中间结果集的表,临时表只在当前连接可见,当关闭连接时,Mysql
会自动删除表并释放所有空间。为什么会产生临时表:一般是由于复杂的SQL
导致临时表被大量创建。临时表分为两种,一种是内存临时表,一种是磁盘临时表。
- 内存临时表采用的是
memory
存储引擎; - 磁盘临时表采用的是
myisam
存储引擎(磁盘临时表也可以使用InnoDB
存储引擎,通internal_tmp_disk_storage_engine
参数来控制使用哪种存储引擎,从mysql5.7.6
之后默认为InnoDB
存储引擎,之前版本默认为myisam
存储引擎)。分别通过Created_tmp_disk_tables
和Created_tmp_tables
两个参数来查看产生了多少磁盘临时表和所有产生的临时表(内存和磁盘)。
内存临时表空间的大小由两个参数控制:
tmp_table_size
和max_heap_table_size
。一般来说是通过两个参数中较小的数来控制内存临时表空间的最大值,而对于开始在内存中创建的临时表,后来由于数据太大转移到磁盘上的临时表,只由max_heap_table_size
参数控制。针对直接在磁盘上产生的临时表,没有大小控制。
哪些操作会使用到临时表?
UNION
查询;- 用到
TEMPTABLE
算法或者是UNION
查询中的视图; ORDER BY
和GROUP BY
的子句不一样时或者单独ORDER BY
;- 表连接中,
ORDER BY
的列不是驱动表中的;(指定了联接条件时,满足查询条件的记录行数少的表为[驱动表],未指定联接条件时,行数少的表为[驱动表],多表联合查询时) DISTINCT
查询并且加上ORDER BY
时或者单独DISTINCT
时候;SQL
中用到SQL_SMALL_RESULT
选项时;FROM
中的子查询;- 子查询或者
SEMI-JOIN
时创建的表。
8、非关系型数据库和关系型数据库区别,优势比较?
8.1、关系型数据库和非关系型数据库的区别
- 关系型数据库:
Oracle
、DB2
、Microsoft SQL Server
、Microsoft Access
、MySQL
等。 - 非关系型数据库:
NoSql
、Cloudant
。临时性键值存储(memcached
、Redis
)、永久性键值存储(ROMA
、Redis
)、面向文档的数据库(MongoDB
、CouchDB
)、面向列的数据库(Cassandra
、HBase
)
8.2、非关系型数据库的优势
- 格式灵活: 存储数据的格式可以是
key,value
形式、文档形式、图片形式等等,使用灵活,应用场景广泛,而关系型数据库则只支持基础类型。 - 速度快:
nosql
可以使用硬盘或者随机存储器作为载体,而关系型数据库只能使用硬盘; - 高扩展性: 基于键值对,数据之间没有耦合性,所以非常容易水平扩展。
- 成本低:
nosql
数据库部署简单,基本都是开源软件。 - 易于数据的分散,分布式数据库
8.3、非关系型数据库的缺点
答: 不提供关系型数据库对事务的处理。NoSQL
数据库只应用在特定领域,基本上不进行复杂的处理,但它恰恰弥补了之前所列举的关系型数据库的不足之处。
8.4、关系型数据库的优势
- 易于维护: 都是使用表结构,格式一致;
- 使用方便:
SQL
语言通用,可用于复杂查询; - 复杂操作: 支持
SQL
,可以进行Join
等复杂查询,可用于一个表以及多个表之间非常复杂的查询; - 事务支持:使得对于安全性能很高的数据访问要求得以实现;
- 由于以标准化为前提,数据更新的开销很小(相同的字段基本上都只有一处)。
8.5、关系型数据库的缺点
- 读写性能比较差,尤其是海量数据的高效率读写;
- 固定的表结构,灵活度欠缺;
- 高并发读写需求,传统关系型数据库来说,硬盘
I/O
是一个很大的瓶颈。
9、什么是存储过程?
答: 存储过程是将一个预编译的 SQL
语句存储在数据库中,再次调用不需要编译。优点是:允许模块化的设计,就是说只需要创建一次,以后在该程序中就可以调用多次。如果某次操作需要执行多次SQL
,使用存储过程比单纯SQL
语句执行要快。
10、存储过程的优点(不推荐)
- 效率高: 存储过程编译一次后,就会存到数据库,每次调用时都直接执行。而普通的
SQL
语句我们要保存到其他地方(例如:记事本上),都要先分析编译才会执行。所以想对而言存储过程效率更高; - 降低网络流量: 存储过程编译好会放在数据库,我们在远程调用时,不会传输大量的字符串类型的
SQL
语句; - 复用性高: 存储过程往往是针对一个特定的功能编写的,当再需要完成这个特定的功能时,可以再次调用该存储过程;
- 可维护性高: 当功能要求发生小的变化时,修改之前的存储过程比较容易,花费精力少;
- 安全性高: 完成某个特定功能的存储过程一般只有特定的用户可以使用,具有使用身份限制,更安全。
11、存储过程和函数的区别?
- 返回值的区别:函数有1个返回值,而存储过程是通过参数返回的,可以有多个或者没有。
- 调用的区别:函数可以在查询语句中直接调用,而存储过程必须单独调用。
11、SQL 关键字的执行顺序?
12、MySQL
的页有多大
答: 可以看出 InnoDB
默认的一页大小为 16384B = 16384/1024 = 16kb
。
在计算机中磁盘存储数据最小单元是扇区,一个扇区的大小是512字节,而文件系统(例如 XFS/EXT4
)他的最小单元是块,一个块的大小是 4k,而对于我们的InnoDB
存储引擎也有自己的最小储存单元——页(Page),一个页的大小是 16K
。
show global status like 'innodb_page_size';
12、数据库是如何实现分页的,假设有100万条数据如何优化分页查询?
12.1、方法1:直接使用数据库提供的 SQL
语句
- 语句样式:
MySQL
中,可用如下方法:SELECT * FROM 表名称 LIMIT M,N
- 适应场景: 适用于数据量较少的情况(元组百/千级)
- 原因/缺点:全表扫描,速度会很慢;有的数据库结果集返回不稳定(如某次返回1,2,3,另外的一次返回2,1,3).。
Limit
限制的是从结果集的M位置处取出N条输出,其余抛弃.
12.2、方法2:建立主键或唯一索引, 利用索引(假设每页10条)
- 语句样式:
MySQL
中,可用如下方法:SELECT * FROM 表名称 WHERE id_pk > (pageNum*10) LIMIT M
; - 适应场景:适用于数据量多的情况(元组数上万);
- 原因:索引扫描,速度会很快。有朋友提出:因为数据查询出来并不是按照
id_pk
排序的,所以会有漏掉数据的情况,只能方法3。
12.3、方法3:基于索引再排序
- 语句样式:
MySQL
中,可用如下方法:SELECT * FROM 表名称 WHERE id_pk > (pageNum*10) ORDER BY id_pk ASC LIMIT M
; - 适应场景: 适用于数据量多的情况(元组数上万). 最好
ORDER BY
后的列对象是主键或唯一所以,使得ORDER BY
操作能利用索引被消除但结果集是稳定的(稳定的含义,参见方法1); - 原因: 索引扫描,速度会很快。 但
MySQL
的排序操作,只有ASC
没有DESC(DESC
是假的,未来会做真正的DESC
,期待…)。
12.4、方法4:基于索引使用 prepare
答: 第一个问号表示,第二个?
表示每页元组数。
- 语句样式:
MySQL
中,可用如下方法:PREPARE stmt_name FROM SELECT * FROM 表名称 WHERE id_pk > (pageNum * 10) ORDER BY id_pk ASC LIMIT M
; - 适应场景: 大数据量;
- 原因: 索引扫描,速度会很快。
prepare
语句又比一般的查询语句快一点。
12.5、方法5:利用 MySQL
支持 ORDER
操作可以利用索引快速定位部分元组,避免全表扫描
答: 比如: 读第1000到1019行元组(pk
是主键/唯一键)。
SELECT * FROM your_table WHERE pk>=1000 ORDER BY pk ASC LIMIT 0,20
12.6、方法6: 利用"子查询/连接+索引"快速定位元组的位置,然后再读取元组
比如(id
是主键/唯一键,蓝色字体时变量)。
利用子查询示例:
SELECT * FROM your_table WHERE id <= (SELECT id FROM your_table ORDER BY id desc
LIMIT (page-1)*pagesize ORDER BY id desc LIMIT $pagesize
利用连接示例:
SELECT * FROM your_table AS t1 JOIN (SELECT id FROM your_table ORDER BY id desc
LIMIT (page-1)*pagesize AS t2 WHERE t1.id <= t2.id ORDER BY t1.id desc LIMIT $pagesize
`