进了互联网公司,整天也就是搬砖,等到了面试的时候,发现数据库方面,忘得一塌糊涂,抽时间整理了一些数据库方面的题。欢迎大家向我推荐你在面试过程中遇到的问题,我会把大家推荐的问题添加到下面的常用面试题清单中供大家参考。

  1. 事务四大特性(ACID)原子性、一致性、隔离性、持久性?
  2. 事务的并发?事务隔离级别,每个级别会引发什么问题,MySQL默认是哪个级别?
  3. MySQL常见的三种存储引擎(InnoDB、MyISAM、MEMORY)的区别?
  4. MySQL的MyISAM与InnoDB两种存储引擎在,事务、锁级别,各自的适用场景?
  5. 查询语句不同元素(where、jion、limit、group by、having等等)执行先后顺序?
  6. 什么是临时表,临时表什么时候删除?
  7. MySQL B+Tree索引和Hash索引的区别?
  8. sql查询语句确定创建哪种类型的索引?如何优化查询?
  9. 聚集索引和非聚集索引区别?
  10. 有哪些锁(乐观锁悲观锁),select 时怎么加排它锁?
  11. 非关系型数据库和关系型数据库区别,优势比较?
  12. 数据库三范式,根据某个场景设计数据表?
  13. 数据库的读写分离、主从复制,主从复制分析的 7 个问题?
  14. 使用explain优化sql和索引?
  15. MySQL慢查询怎么解决?
  16. 什么是 内连接、外连接、交叉连接、笛卡尔积等?
  17. mysql都有什么锁,死锁判定原理和具体场景,死锁怎么解决?
  18. varchar和char的使用场景?
  19. mysql 高并发环境解决方案?
  20. 数据库崩溃时事务的恢复机制(REDO日志和UNDO日志)?

1、事务四大特性(ACID)原子性、一致性、隔离性、持久性?

原子性(Atomicity)

  • 原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。

一致性(Consistency)

  • 事务开始前和结束后,数据库的完整性约束没有被破坏。比如A向B转账,不可能A扣了钱,B却没收到

隔离性(Isolation)

  • 隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离

同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。

关于事务的隔离性数据库提供了多种隔离级别,稍后会介绍到持久性(Durability)

  • 持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作

2、事务的并发?事务隔离级别,每个级别会引发什么问题,MySQL默认是哪个级别?

从理论上来说, 事务应该彼此完全隔离, 以避免并发事务所导致的问题,然而, 那样会对性能产生极大的影响, 因为事务必须按顺序运行, 在实际开发中, 为了提升性能, 事务会以较低的隔离级别运行, 事务的隔离级别可以通过隔离事务属性指定

2.1 事务的并发问题

(1)脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

(2)不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果因此本事务先后两次读到的数据结果会不一致。

(3)幻读:幻读解决了不重复读,保证了同一个事务里,查询的结果都是事务开始时的状态(一致性)。

例如:事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作 这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。 而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有跟没有修改一样,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。

小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表。

2.2 事务的隔离级别

事务隔离级别 脏读 不可重复读 幻读

读未提交 read-uncommitted 是 是 是

不可重复读 read-committed 否 是 是

可重复读 repeatable-read 否 否 是

串行化 serializable 否 否 否

  • 读未提交:另一个事务修改了数据,但尚未提交,而本事务中的SELECT会读到这些未被提交的数据脏读
  • 不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果因此本事务先后两次读到的数据结果会不一致。
  • 可重复读:在同一个事务里,SELECT的结果是事务开始时时间点的状态,因此,同样的SELECT操作读到的结果会是一致的。但是,会有幻读现象
  • 串行化:最高的隔离级别,在这个隔离级别下,不会产生任何异常。并发的事务,就像事务是在一个个按照顺序执行一样

2.3 MySQL默认的事务隔离级别为repeatable-read

  • MySQL 支持 4 中事务隔离级别.
  • 事务的隔离级别要得到底层数据库引擎的支持, 而不是应用程序或者框架的支持.
  • Oracle 支持的 2 种事务隔离级别:READ_COMMITED , SERIALIZABLE

2.3 补充

  1. SQL规范所规定的标准,不同的数据库具体的实现可能会有些差异
  2. MySQL中默认事务隔离级别是“可重复读”时并不会锁住读取到的行
  • 事务隔离级别未提交读时,写数据只会锁住相应的行。
  • 事务隔离级别为可重复读时,写数据会锁住整张表。
  • 事务隔离级别为串行化时,读写数据都会锁住整张表。

隔离级别越高越能保证数据的完整性和一致性,但是对并发性能的影响也越大,鱼和熊掌不可兼得啊。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed,它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。

3、MySQL常见的三种存储引擎(InnoDB、MyISAM、MEMORY)的区别?

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

blog.csdn.net/lc0817/arti…

MySQL存储引擎之MyISAM和Innodb总结性梳理

www.cnblogs.com/kevingrace/…

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

MySQL有多种存储引擎,每种存储引擎有各自的优缺点,可以择优选择使用:MyISAM、InnoDB、MERGE、MEMORY(HEAP)、BDB(BerkeleyDB)、EXAMPLE、FEDERATED、ARCHIVE、CSV、BLACKHOLE。

虽然MySQL里的存储引擎不只是MyISAM与InnoDB这两个,但常用的就是两个

两种存储引擎的大致区别表现在

  • InnoDB支持事务,MyISAM不支持,这一点是非常之重要。事务是一种高级的处理方式,如在一些列增删改中只要哪个出错还可以回滚还原,而MyISAM就不可以了。
  • MyISAM适合查询以及插入为主的应用
  • InnoDB适合频繁修改以及涉及到安全性较高的应用
  • InnoDB支持外键,MyISAM不支持。
  • 从MySQL5.5.5以后,InnoDB是默认引擎
  • InnoDB不支持FULLTEXT类型的索引。
  • InnoDB中不保存表的行数,如select count() from table时,InnoDB需要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count()语句包含where条件时MyISAM也需要扫描整个表。
  • 对于自增长的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中可以和其他字段一起建立联合索引。
  • DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的 删除,效率非常慢MyISAM则会重建表
  • InnoDB支持行锁(某些情况下还是锁整表,如 update table set a=1 where user like '%lee%'。

3.2 关于MySQL数据库提供的两种存储引擎,MyISAM与InnoDB选择使用:

  • INNODB会支持一些关系数据库的高级功能如事务功能和行级锁,MyISAM不支持
  • MyISAM的性能更优,占用的存储空间少,所以,选择何种存储引擎,视具体应用而定。
  • 如果你的应用程序一定要使用事务,毫无疑问你要选择INNODB引擎。但要注意,INNODB的行级锁是有条件的。在where条件没有使用主键时,照样会锁全表。比如DELETE FROM mytable这样的删除语句。
  • 如果你的应用程序对查询性能要求较高,就要使用MyISAM了MyISAM索引和数据是分开的,而且其索引是压缩的,可以更好地利用内存。所以它的查询性能明显优于INNODB。压缩后的索引也能节约一些磁盘空间。MyISAM拥有全文索引的功能,这可以极大地优化LIKE查询的效率

有人说MyISAM只能用于小型应用,其实这只是一种偏见。如果数据量比较大,这是需要通过升级架构来解决,比如分表分库,而不是单纯地依赖存储引擎。

现在一般都是选用innodb了,主要是MyISAM的全表锁,读写串行问题,并发效率锁表,效率低,MyISAM对于读写密集型应用一般是不会去选用的。

3.3 MEMORY存储引擎

MEMORY是MySQL中一类特殊的存储引擎。它使用存储在内存中的内容来创建表,而且数据全部放在内存中。这些特性与前面的两个很不同。

每个基于MEMORY存储引擎的表实际对应一个磁盘文件。该文件的文件名与表名相同,类型为frm类型。该文件中只存储表的结构。而其数据文件,都是存储在内存中,这样有利于数据的快速处理,提高整个表的效率。值得注意的是,服务器需要有足够的内存来维持MEMORY存储引擎的表的使用。如果不需要了,可以释放内存,甚至删除不需要的表。

MEMORY默认使用哈希索引。速度比使用B型树索引快。当然如果你想用B型树索引,可以在创建索引时指定。

注意,MEMORY用到的很少,因为它是把数据存到内存中,如果内存出现异常就会影响数据。如果重启或者关机,所有数据都会消失。因此,基于MEMORY的表的生命周期很短,一般是一次性的

4、MySQL的MyISAM与InnoDB两种存储引擎在,事务、锁级别,各自的适用场景?

事务处理上方面

  • MyISAM强调的是性能,每次查询具有原子性,其执行数度比InnoDB类型更快,但是不提供事务支持
  • InnoDB提供事务支持事务,外部键等高级数据库功能。 具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。

锁级别

  • MyISAM只支持表级锁,用户在操作MyISAM表时,select,update,delete,insert语句都会给表自动加锁,如果加锁以后的表满足insert并发的情况下,可以在表的尾部插入新的数据。
  • InnoDB:支持事务和行级锁,是innodb的最大特色。行锁大幅度提高了多用户并发操作的新能。但是InnoDB的行锁,只是在WHERE的主键是有效的,非主键的WHERE都会锁全表的。

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

(1)查询中用到的关键词主要包含六个,并且他们的顺序依次为 select--from--where--group by--having--order by

其中select和from是必须的,其他关键词是可选的,这六个关键词的执行顺序 与sql语句的书写顺序并不是一样的,而是按照下面的顺序来执行

  • from:需要从哪个数据表检索数据
  • where:过滤表中数据的条件
  • group by:如何将上面过滤出的数据分组
  • having:对上面已经分组的数据进行过滤的条件
  • select:查看结果集中的哪个列,或列的计算结果
  • order by :按照什么样的顺序来查看返回的数据

(2)from后面的表关联,是自右向左解析 而where条件的解析顺序是自下而上的。

也就是说,在写SQL文的时候,尽量把数据量小的表放在最右边来进行关联(用小表去匹配大表),而把能筛选出小量数据的条件放在where语句的最左边 (用小表去匹配大表)

6**、什么是临时表,临时表什么时候删除?**

时表可以手动删除:

DROP TEMPORARY TABLE IF EXISTS temp_tb;

复制代码

临时表只在当前连接可见,当关闭连接时,MySQL会自动删除表并释放所有空间。因此在不同的连接中可以创建同名的临时表,并且操作属于本连接的临时表

创建临时表的语法与创建表语法类似,不同之处是增加关键字TEMPORARY,如:

CREATE TEMPORARY TABLE tmp_table (

NAME VARCHAR (10) NOT NULL,

time date NOT NULL

);

select * from tmp_table;

7**、MySQL B+Tree索引和Hash索引的区别?**

  • Hash索引结构的特殊性,其检索效率非常高,索引的检索可以一次定位;
  • B+树索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问;

那为什么大家不都用Hash索引而还要使用B+树索引呢?

7.1 Hash**索引**

(1)Hash索引仅仅能满足"=","IN"和""查询,不能使用范围查询,因为经过相应的Hash算法处理之后的Hash值的大小关系,并不能保证和Hash运算前完全一样;

(2)Hash索引无法被用来避免数据的排序操作,因为Hash值的大小关系并不一定和Hash运算前的键值完全一样;

(3)Hash索引不能利用部分索引键查询,对于组合索引,Hash索引在计算Hash值的时候是组合索引键合并后再一起计算Hash值,而不是单独计算Hash值,所以通过组合索引的前面一个或几个索引键进行查询的时候,Hash索引也无法被利用;

(4)Hash索引在任何时候都不能避免表扫描,由于不同索引键存在相同Hash值,所以即使取满足某个Hash键值的数据的记录条数,也无法从Hash索引中直接完成查询,还是要回表查询数据;

(5)Hash索引遇到大量Hash值相等的情况后性能并不一定就会比B+树索引高。

7.2 B+Tree**索引**

MySQL**中,只有HEAP/MEMORY引擎才显示支持Hash索引**。

常用的InnoDB引擎中默认使用的是B+树索引,它会实时监控表上索引的使用情况,如果认为建立哈希索引可以提高查询效率,则自动在内存中的“自适应哈希索引缓冲区”建立哈希索引(在InnoDB中默认开启自适应哈希索引),通过观察搜索模式,MySQL会利用index key的前缀建立哈希索引,如果一个表几乎大部分都在缓冲池中,那么建立一个哈希索引能够加快等值查询。

7.3 B+**树索引和哈希索引的明显区别是:**

如果是等值查询,那么哈希索引明显有绝对优势因为只需要经过一次算法即可找到相应的键值;当然了,这个前提是,键值都是唯一的。如果键值不是唯一的,就需要先找到该键所在位置,然后再根据链表往后扫描,直到找到相应的数据

如果是范围查询检索,这时候哈希索引就毫无用武之地了,因为原先是有序的键值,经过哈希算法后,有可能变成不连续的了,就没办法再利用索引完成范围查询检索;

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

哈希索引也不支持多列联合索引的最左匹配规则

B+树索引的关键字检索效率比较平均,不像B树那样波动幅度大,在有大量重复键值情况下,哈希索引的效率也是极低的,因为存在所谓的哈希碰撞问题

在大多数场景下,都会有范围查询、排序、分组等查询特征,用B+树索引就可以了

8**、sql查询语句确定创建哪种类型的索引?如何优化查询?**

  • 性能优化过程中,选择在哪个列上创建索引是最重要的步骤之一,可以考虑使用索引的主要有两种类型的列:在where子句中出现的列,在join子句中出现的列。
  • 考虑列中值的分布,索引的列的基数越大,索引的效果越好。
  • 使用短索引,如果对字符串列进行索引,应该指定一个前缀长度,可节省大量索引空间,提升查询速度。
  • 利用最左前缀,顾名思义,就是最左优先,在多列索引,有体现:(ALTER TABLE people ADD INDEX lname_fname_age (lame,fname,age);),所谓最左前缀原则就是先要看第一列,在第一列满足的条件下再看左边第二列,以此类推
  • 不要过度建索引,只保持所需的索引。每个额外的索引都要占用额外的磁盘空间,并降低写操作的性能
  • 在修改表的内容时,索引必须进行更新,有时可能需要重构,因此,索引越多,所花的时间越长
  • MySQL**只对一下操作符才使用索引**:,>=,between,in
  • 以及某些时候的like(不以通配符%或_开头的情形)。

9**、聚集索引和非聚集索引区别?**

聚合索引(clustered index) / 非聚合索引(nonclustered index)

根本区别

聚集索引和非聚集索引的根本区别是表记录的排列顺序和与索引的排列顺序是否一致

9.1**聚集索引**

聚集索引表记录的排列顺序和索引的排列顺序一致,所以查询效率快,只要找到第一个索引值记录,其余就连续性的记录在物理也一样连续存放。聚集索引对应的缺点就是修改慢,因为为了保证表中记录的物理和索引顺序一致,在记录插入的时候,会对数据页重新排序

聚集索引类似于新华字典中用拼音去查找汉字,拼音检索表于书记顺序都是按照a~z排列的,就像相同的逻辑顺序于物理顺序一样,当你需要查找a,ai两个读音的字,或是想一次寻找多个傻(sha)的同音字时,也许向后翻几页,或紧接着下一行就得到结果了。

9.2**非聚集索引**

非聚集索引制定了表中记录的逻辑顺序,但是记录的物理和索引不一定一致,两种索引都采用B+树结构,非聚集索引的叶子层并不和实际数据页相重叠,而采用叶子层包含一个指向表中的记录在数据页中的指针方式。非聚集索引层次多,不会造成数据重排

非聚集索引类似在新华字典上通过偏旁部首来查询汉字,检索表也许是按照横、竖、撇来排列的,但是由于正文中是a~z的拼音顺序,所以就类似于逻辑地址于物理地址的不对应。同时适用的情况就在于分组,大数目的不同值,频繁更新的列中,这些情况即不适合聚集索引。

10**、有哪些锁(乐观锁悲观锁),select 时怎么加排它锁?**

10.1**悲观锁(Pessimistic Lock)**

悲观锁的特点是先获取锁,再进行业务操作,即“悲观”的认为获取锁是非常有可能失败的,因此要先确保获取锁成功再进行业务操作。通常所说的“一锁二查三更新”即指的是使用悲观锁。通常来讲在数据库上的悲观锁需要数据库本身提供支持,即通过常用的select … for update操作来实现悲观锁。当数据库执行select for update时会获取被select中的数据行的行锁,因此其他并发执行的select for update如果试图选中同一行则会发生排斥(需要等待行锁被释放),因此达到锁的效果。select for update获取的行锁会在当前事务结束时自动释放,因此必须在事务中使用。

这里需要注意的一点是不同的数据库对select for update的实现和支持都是有所区别的,例如oracle支持select for update no wait,表示如果拿不到锁立刻报错,而不是等待,MySQL就没有no wait这个选项。另外MySQL还有个问题是select for update语句执行中所有扫描过的行都会被锁上,这一点很容易造成问题。因此如果在MySQL中用悲观锁务必要确定走了索引,而不是全表扫描

10.2**乐观锁(Optimistic Lock)**

乐观锁,也叫乐观并发控制,它假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,每个事务会先检查在该事务读取数据后,有没有其他事务又修改了该数据。如果其他事务有更新的话,那么当前正在提交的事务会进行回滚

乐观锁的特点先进行业务操作,不到万不得已不去拿锁。即“乐观”的认为拿锁多半是会成功的,因此在进行完业务操作需要实际更新数据的最后一步再去拿一下锁就好。

乐观锁在数据库上的实现完全是逻辑的,不需要数据库提供特殊的支持一般的做法是在需要锁的数据上增加一个版本号,或者时间戳,然后按照如下方式实现:

乐观锁(给表加一个版本号字段) 这个并不是乐观锁的定义,给表加版本号,是数据库实现乐观锁的一种方式

(1) SELECT data AS old_data, version AS old_version FROM …;

(2)根据获取的数据进行业务操作,得到new_data和new_version

(3)UPDATE SET data = new_data, version = new_version WHERE version = old_version

if (updated row > 0) {

// 乐观锁获取成功,操作完成

} else {

// 乐观锁获取失败,回滚并重试

}

乐观锁在不发生取锁失败的情况下开销比悲观锁小,但是一旦发生失败回滚开销则比较大,因此适合用在取锁失败概率比较小的场景,可以提升系统并发性能

乐观锁还适用于一些比较特殊的场景,例如在业务操作过程中无法和数据库保持连接等悲观锁无法适用的地方

10.3**总结**

悲观锁和乐观锁是数据库用来保证数据并发安全防止更新丢失的两种方法,例子在select ... for update前加个事务就可以防止更新丢失。悲观锁和乐观锁大部分场景下差异不大,一些独特场景下有一些差别,一般我们可以从如下几个方面来判断。

  • 响应速度:如果需要非常高的响应速度,建议采用乐观锁方案,成功就执行,不成功就失败,不需要等待其他并发去释放锁。
  • 冲突频率:如果冲突频率非常高,建议采用悲观锁,保证成功率,如果冲突频率大,乐观锁会需要多次重试才能成功,代价比较大。
  • 重试代价:如果重试代价大,建议采用悲观锁。

原件下载地址