数据库面试总结

1. 什么是MySQL?

MySQL是一个关系型数据库管理系统,MySQL是开源免费的,并且方便扩展。默认端口3306。
关系型数据库:Oracle、DB2、Microsoft SQL Server、MySQL
关系型数据库,是指采用了关系模型来组织数据的数据库;关系型数据库的最大特点就是事务的一致性;支持SQL,可用于复杂的查询。
非关系型数据库:NoSql、Cloudant、MongoDb、redis、HBase
使用键值对存储数据;分布式;一般不支持ACID特性;基于键值对,数据没有耦合性,容易扩展;不提供sql支持,学习和使用成本较高

2. 数据库三大范式是什么

第一范式:每个列都不可以再拆分。
第二范式:在第一范式的基础上,非主键列完全依赖于主键,而不能是依赖于主键的一部分。
第三范式:在第二范式的基础上,非主键列只依赖于主键,不依赖于其他非主键。

设计数据库结构要尽量遵守三范式,如果不遵守,必须有足够的理由。比如为了性能而妥协数据库的设计。

3. mysql有关权限的表

权限表用来控制用户对数据库的访问。放在mysql数据库里,由mysql_install_db脚本初始化

  • user权限表:记录允许连接到服务器的用户帐号信息,权限是全局级的。
  • db权限表:记录各个帐号在各个数据库上的操作权限。
  • table_priv权限表:记录数据表级的操作权限。
  • columns_priv权限表:记录数据列级的操作权限。
  • host权限表:配合db权限表对给定主机上数据库级操作权限作更细致的控制。这个权限表不受GRANT和REVOKE语句的影响。

4. MySQL存储引擎

MySQL 当前默认的存储引擎是InnoDB,所有的存储引擎中只有 InnoDB 是事务性存储引擎。MyISAM不支持事务和行级锁,而且最大的缺陷就是崩溃后无法安全恢复。
MySOL存储引擎和MyISAM区别:

  1. 是否支持行级锁 : MyISAM 只有表级锁,而InnoDB 支持行级锁和表级锁,默认为行级锁
  2. 是否支持事务和崩溃后的安全恢复: MyISAM 强调性能,每次查询具有原子性,执行速度更快,但不提供事务支持。
    InnoDB 支持事务,外部键等高级数据库功能。 具有事务(commit)、回滚(rollback)和崩溃修复能力的事务安全型表,有ACID的特性。
  3. 是否支持外键: MyISAM不支持,而InnoDB支持。
  4. 是否支持MVCC :仅 InnoDB 支持。应对高并发事务, MVCC比单纯的加锁更高效;MVCC只在 READ COMMITTED 和 REPEATABLE READ 两个隔离级别下工作;MVCC可以使用 乐观(optimistic)锁 和 悲观(pessimistic)锁来实现

MyISAM索引与InnoDB索引的区别?

  1. InnoDB索引是聚簇索引,MyISAM索引是非聚簇索引。
  2. InnoDB的主键索引的叶子节点存储着行数据,因此主键索引非常高效。
  3. MyISAM索引的叶子节点存储的是行数据地址,需要再寻址一次才能得到数据。
  4. InnoDB非主键索引的叶子节点存储的是主键或其他带索引的列数据,在根据主索引搜索时,直接找到key所在的节点即可取出数据;在根据辅助索引查找时,则需要先取出主键的值,再走一遍主索引。 因此,在设计表的时候,不建议使用过长的字段作为主键,做到覆盖索引会非常高效。
    (覆盖索引:查询的字段都建立过索引,那直接在索引表中一次查询(只要有一个字段没有建立索引就会做全表扫描))

存储引擎选择
如果没有特别的需求,使用默认的Innodb即可。
MyISAM:做很多count的计算,读密集,没有事务。比如博客系统、新闻门户网站。
Innodb:要求事务和外键,写密集,高并发。比如OA自动化办公系统。

5. mysql有哪些数据类型

  1. 整数类型:TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT,分别表示1字节、2字节、3字节、4字节、8字节整数。
  2. 实数类型:包括FLOAT、DOUBLE、DECIMAL。DECIMAL能存储精确的小数,存储比BIGINT还大的整型
  3. 字符串类型:包括VARCHAR、CHAR、TEXT、BLOB
    CHAR是定长的,根据长度分配足够的空间,合存储很短的字符串,内容超出设置的长度时,内容会被截断。
    VARCHAR用于存储可变长字符串,它比定长类型更节省空间,内容超出设置的长度时,内容同样会被截断。
  4. 日期和时间类型,尽量使用timestamp,空间效率高于datetime。

6. InnoDB引擎的4大特性

插入缓冲(insert buffer)

二次写(double write)

自适应哈希索引(ahi)

预读(read ahead)

7. 什么是索引?

索引是一种特殊的文件,包含数据表里所有记录的引用指针,占据物理存储空间。
索引是一种排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用B树及其变种B+树。

索引优缺点
(1) 优点:加快检索速度
(2)缺点:(a)创建索引和维护索引需要耗费时间(b)索引需要占用空间 ©进行数据的增删改时候需要动态维护索引

索引的数据结构主要有BTree索引哈希索引
哈希索引底层的数据结构就是哈希表,绝大多数需求为单条记录查询的时候,可以选择哈希索引,查询性能最快;但是存在一些缺点
1、不能使用范围查询和模糊查询。2、无法避免任何排序运算;3、不支持多列联合索引的最左匹配规则;4、任何时候都不能避免表扫描。5、存在所谓的哈希碰撞问题。

其余大部分场景,建议选择BTree索引
1、B+树的层级更少:相较于B树,B+每个非叶子节点存储的关键字数更多,树的层级更少所以查询数据更快;
2、B+树查询速度更稳定:B+所有关键字数据地址都存在叶子节点上,所以每次查找的次数都相同所以查询速度要比B树更稳定;
3、B+树具备排序功能:B+树所有的叶子节点数据构成了一个有序链表,在查询区间数据时更方便,缓存的命中率也会比B树高。
4、B+树全节点遍历更快:B+树遍历整棵树只需要遍历所有的叶子节点即可,而不需要像B树一样需要对每一层进行遍历,这有利于数据库做全表扫描。B树相对于B+树的优点是,如果经常访问的数据离根节点很近,而B树的非叶子节点存有关键字数据,这时会要比B+树快。

8. 索引有哪几种类型?

  1. 主键索引: 数据列不允许重复,不允许为NULL,一个表只能有一个主键。

  2. 唯一索引: 数据列不允许重复,允许为NULL值,一个表允许多个列创建唯一索引。
    可以通过 ALTER TABLE table_name ADD UNIQUE (column); 创建唯一索引
    可以通过 ALTER TABLE table_name ADD UNIQUE (column1,column2); 创建唯一组合索引

  3. 普通索引: 基本的索引类型,没有唯一性的限制,允许为NULL值。
    可以通过ALTER TABLE table_name ADD INDEX index_name (column);创建普通索引
    可以通过ALTER TABLE table_name ADD INDEX index_name(column1, column2, column3);创建组合索引

  4. 全文索引: 是目前搜索引擎使用的一种关键技术。
    可以通过ALTER TABLE table_name ADD FULLTEXT (column);创建全文索引

9. 索引原理

把无序的数据变成有序的查询:

  1. 把创建了索引的列的内容进行排序
  2. 对排序结果生成倒排表
  3. 在倒排表内容上拼上数据地址链
  4. 在查询的时候,先拿到倒排表内容,再取出数据地址链,从而拿到具体数据

10. 索引设计的原则?

  1. 适合索引的列是出现在where子句中的列,或者连接子句中指定的列
  2. 基数较小的类,索引效果较差,没有必要在此列建立索引
  3. 使用短索引,如果对长字符串列进行索引,应该指定一个前缀长度
  4. 不要过度索引。索引需要额外的磁盘空间,并降低写操作的性能。在增删改表内容的时候,索引会进行更新甚至重构。

11. 创建索引的原则(重中之重)

索引虽好,但也不是无限制的使用,最好符合一下几个原则

1) 最左前缀匹配原则。mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
2)较频繁作为查询条件的字段才去创建索引,更新频繁字段不适合创建索引,重复值比较多的列不要建立索引。
3)若是不能有效区分数据的列不适合做索引列(如性别,男女未知,最多也就三种,区分度实在太低)
5)尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。
6)定义有外键的数据列一定要建立索引。
7)对于定义为text、image和bit的数据类型的列不要建立索引。

12. 创建索引的三种方式,以及删除索引

第一种方式:在执行CREATE TABLE时创建索引
第二种方式:使用ALTER TABLE命令去增加索引
第三种方式:使用CREATE INDEX命令创建

CREATE TABLE user_index2 (
	id INT auto_increment PRIMARY KEY,
	first_name VARCHAR (16),
	last_name VARCHAR (16),
	id_card VARCHAR (18),
	information text,
	KEY name (first_name, last_name),
	FULLTEXT KEY (information),
	UNIQUE KEY (id_card)
);
#ALTER TABLE用来创建普通索引、UNIQUE索引或PRIMARY KEY索引。
ALTER TABLE table_name ADD INDEX index_name (column_list);

#CREATE INDEX可对表增加普通索引或UNIQUE索引。(但是,不能创建PRIMARY KEY索引)
CREATE INDEX index_name ON table_name (column_list);

删除索引
根据索引名删除普通索引、唯一索引、全文索引:alter table 表名 drop KEY 索引名

13 .百万级别或以上的数据如何删除

关于索引:对数据增删改都会产生额外的对索引文件的操作,这些操作需要消耗额外的IO,会降低增/改/删的执行效率。所以,在我们删除数据库百万级别数据的时候,查询MySQL官方手册得知删除数据的速度和创建的索引数量是成正比的。

所以我们想要删除百万数据的时候可以先删除索引(此时大概耗时三分多钟)
然后删除其中无用数据(此过程需要不到两分钟)
删除完成后重新创建索引(此时数据较少了)创建索引也非常快,约十分钟左右。
与之前的直接删除绝对是要快速很多,更别说万一删除中断,一切删除会回滚。

14. 什么是最左前缀匹配原则?

  • 创建多列索引时,要根据业务需求,where子句中使用最频繁的一列放在最左边。

  • 最左前缀匹配原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。

  • =和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式

15. B树和B+树的区别

  • 在B树中,在内部节点同时存储键和值,把频繁访问的数据放在靠近根节点的地方大大提高热点数据的查询效率。在特定数据重复多次查询的场景中更加高效。全数据遍历时,B树则需要对树的每一层进行遍历,也就需要花费更多的时间。
  • 但在B+树中,内部节点只存放键,不存放值,一次读取,可以在内存页中获取更多的键,有利于更快地缩小查找范围,减少磁盘IO的操作数,B+树的叶节点由一条链相连,当需要进行一次全数据遍历的时通过链进行O(N)的顺序遍历即可。

16. 聚簇索引和非聚簇索引

聚簇索引:将数据存储与索引放到了一块,找到索引也就找到了数据
非聚簇索引:将数据和索引分开存储,索引结构的叶子节点为数据的引用地址,myisam通过key_buffer把索引先缓存到内存中,当需要访问数据时,在内存中直接搜索索引,然后通过索引找到磁盘相应数据,这也就是为什么索引不在key buffer命中时,速度慢的原因

  • innodb中,在聚簇索引之上创建的索引称之为辅助索引,辅助索引访问数据总是需要二次查找,非聚簇索引都是辅助索引,像复合索引、前缀索引、唯一索引,辅助索引叶子节点存储的不再是数据的地址,而是主键值。
  • 满足聚簇索引和覆盖索引的时候不需要回表查询数据,查询语句所要求的字段如果全部命中了索引,那么就不必再进行回表查询

17. 事务

事务是逻辑上的一组操作,要么都执行,要么都不执行。
比如转账就是一个事务操作。
假如小明要给小红转账1000元,**涉及到两个关键操作就是:将小明的余额减少1000元,将小红的余额增加1000元。**万一在这两个操作之间突然出现错误比如银行系统崩溃,导致小明余额减少而小红的余额没有增加,这样就不对了。事务就是保证这两个关键操作要么都成功,要么都要失败。

事物的四大特性(ACID)
原子性: 事务是最小的执行单位,不允许分割。确保动作要么全部完成,要么都不完成;
一致性: 执行事务前后,数据保持一致,多个事务对同一个数据读取的结果是相同的;
隔离性: 并发访问数据库时,一个事务不被其他事务所干扰,各并发事务之间数据库是独立的;
持久性: 事务提交后对数据库的改变是持久的,即使数据库发生故障也不应该对其有任何影响。

什么是脏读?幻读?不可重复读?
脏读:一个事务读取了另一个事务未提交的数据。 某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。
不可重复读:在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间数据被另一事务修改。
幻读: 在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入或删除几列数据。

事务的隔离级别?MySQL的默认隔离级别是什么?

  • READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
  • READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
  • REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
  • SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。

Mysql 默认采用的 REPEATABLE_READ隔离级别
Oracle 默认采用的 READ_COMMITTED隔离级别

18. 锁

数据库有并发事务的时候,可能会产生数据的不一致,这时候需要一些机制来保证访问的次序

隔离级别与锁的关系

  • 在Read Uncommitted级别下,读取数据不需要加共享锁,这样就不会跟被修改的数据上的排他锁冲突(加了共享锁,其他事务就不能获得排它锁对数据进行修改)

  • 在Read Committed级别下,读操作需要加共享锁,但是在语句执行完以后释放共享锁(保证事务在读数据的时候,其他事务不能修改数据)

  • 在Repeatable Read级别下,读操作需要加共享锁,但是在事务提交之前并不释放共享锁,也就是必须等待事务执行完毕以后才释放共享锁。(保证事务提交前后保持一致)

  • SERIALIZABLE 是限制性最强的隔离级别,因为该级别锁定整个范围的键,并一直持有锁,直到事务完成。

19. 锁的分类

锁的粒度把数据库锁分为行级锁(INNODB引擎)、表级锁(MYISAM引擎)和页级锁(BDB引擎 )。

  • MyISAM采用表级锁(table-level locking)。
  • InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁

行级锁:
行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁 和 排他锁
特点:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

表级锁
表级锁是MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。最常使用的MYISAM与INNODB都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)。
特点:开销小,加锁快;不会出现死锁;锁定粒度大,发出锁冲突的概率最高,并发度最低。

页级锁
页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。
特点:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般

锁的类别上,有共享锁和排他锁。

共享锁:
又叫读锁。 是读取操作的锁。其他用户可以并发读取数据,但任何事务都不能对数据进行修改(获取数据上的排他锁),直到已释放所有共享锁。

排他锁:
又叫写锁。 ,如果事务T对数据A加上排他锁后,则其他事务不能再对A加任任何类型的封锁。获准排他锁的事务既能读数据,又能修改数据。

20. InnoDB存储引擎的锁的算法

  • Record lock(记录锁):单个行记录上的锁,锁住某一行,如果表存在索引,那么记录锁是锁在索引上的,如果表没有索引,那么 InnoDB 会创建一个隐藏的聚簇索引加锁。
  • Gap lock(间隙锁):对索引项之间的“间隙”加锁,锁定记录的范围,不包含索引项本身。其他事务不能在锁范围内插入数据,这样就防止了别的事务新增幻影行。
  • Next-key lock:record+gap ,是一种记录锁和间隙锁的组合锁。既锁住行也锁住间隙。

21. 三种并发控制机制:悲观并发控制、乐观并发控制和多版本并发控制。

乐观锁:
在访问数据之前,默认去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。
实现方式:版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是CAS实现的。

悲观锁:
假定会发生并发冲突,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)
实现方式:使用数据库中的锁机制,Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。

  1. 版本号机制
    一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。

  2. CAS算法
    即compare and swap(比较与交换),是一种有名的无锁算法。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。
    CAS算法涉及到三个操作数
    1)需要读写的内存值 V
    2) 进行比较的值 A
    3)拟写入的新值 B
    当且仅当 V 的值等于 A时,CAS通过原子方式用新值B来更新V的值,否则不会执行任何操作(比较和替换是一个原子操作)。一般情况下是一个自旋操作,即不断的重试。

乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。
但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。

22. SQL语句主要分为哪几类

数据定义语言DDL(Data Ddefinition Language) CREATE,DROP,ALTER

数据查询语言DQL(Data Query Language) SELECT

数据操纵语言DML(Data Manipulation Language) INSERT,UPDATE,DELETE

数据控制功能DCL(Data Control Language) GRANT,REVOKE,COMMIT,ROLLBACK

23. mysql中int(10)和char(10)以及varchar(10)的区别

  • int(10) 的10表示显示的数据的长度,不是存储数据的大小;
    chart(10)和varchar(10) 的10表示存储数据的大小,即表示存储多少个字符。

  • int(10) 10位的数据长度 9999999999,占32个字节,int型4位
    char(10) 10位固定字符串,不足补空格 最多10个字符
    varchar(10) 10位可变字符串,不足补空格 最多10个字符

  • char(10)表示存储定长的10个字符,不足10个就用空格补齐,占用更多的存储空间,但空格不算一个字符
    varchar(10)表示存储10个变长的字符,存储多少个就是多少个,空格也按一个字符存储,这一点是和char(10)的空格不同的,char(10)的空格表示占位不算一个字符

24. Explain有哪些信息

Explain 包含字段信息如下: id、select_type、table、partitions、type、possible_keys、key、key_len、ref、rows、filtered、Extra 12个字段。
在这里插入图片描述

  1. id
    表示查询中执行select子句或者操作表的顺序,id的值越大,代表优先级越高,越先执行。

  2. select_type:
    表示 select 查询的类型,主要是用于区分各种复杂的查询,例如:普通查询、联合查询、子查询
    1、SIMPLE
    表示最简单的 select 查询语句,在查询中不包含子查询或者 union交并差集等操作。
    2、PRIMARY
    当查询语句中包含任何复杂的子部分,最外层查询则被标记为PRIMARY。
    3、SUBQUERY
    当 select 或 where 列表中包含了子查询,该子查询被标记为:SUBQUERY 。
    4、DERIVED
    表示包含在from子句中的子查询的select,在我们的 from 列表中包含的子查询
    5、UNION
    如果union后边又出现的select 语句,则会被标记为union;若 union 包含在 from 子句的子查询中,外层 select 将被标记为 derived。
    6、UNION RESULT
    UNION RESULT:代表从union的临时表中读取数据,而table列的表示用第一个和第四个select的结果进行union操作。

  3. table
    查询的表名,并不一定是真实存在的表,有别名显示别名,也可能为临时表,例如上边的DERIVED、 等。

  4. partitions
    查询时匹配到的分区信息,对于非分区表值为NULL,当查询的是分区表时,partitions显示分区表命中的分区情况。

  5. type
    查询使用了何种类型,在表中找到所需行的方式。它在 SQL优化中是一个非常重要的指标,以下性能从好到坏依次是:system > const > eq_ref > ref > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
    1、system
    当表仅有一行记录时(系统表),数据量很少,往往不需要进行磁盘IO,速度非常快。
    2、const
    表示查询时命中 primary key 主键或者 unique 唯一索引,或者被连接的部分是一个常量(const)值。这类扫描效率极高,返回数据量少,速度非常快。
    3、eq_ref
    查询时命中主键primary key 或者 unique key索引,就是 eq_ref。
    4、ref
    区别于eq_ref ,ref表示使用非唯一性索引,会找到很多个符合条件的行。
    5、ref_or_null
    这种连接类型类似于 ref,区别在于 MySQL会额外搜索包含NULL值的行。
    6、index_merge
    使用了索引合并优化方法,查询使用了两个以上的索引。
    7、unique_subquery
    替换下面的 IN子查询,子查询返回不重复的集合。
    8、index_subquery
    区别于unique_subquery,用于非唯一索引,可以返回重复值。
    9、range
    使用索引选择行,仅检索给定范围内的行。简单点说就是针对一个有索引的字段,给定范围检索数据。在where语句中使用 bettween…and、<、>、<=、in 等条件查询 type 都是 range。
    10、index
    Index 与ALL 其实都是读全表,区别在于index是遍历索引树读取,而ALL是从硬盘中读取。
    11、ALL
    将遍历全表以找到匹配的行,性能最差。

  6. possible_keys
    指出MySQL能使用哪个索引在表中找到记录,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用

  7. Key
    显示MySQL实际决定使用的键(索引),必然包含在possible_keys中

  8. key_len
    表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的)

  9. ref
    列与索引的比较,表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
    常见的有:const,func,null,字段名。

    当使用常量等值查询,显示const,

    当关联查询时,会显示相应关联表的关联字段

    如果查询条件使用了表达式、函数,或者条件列发生内部隐式转换,可能显示为func

    其他情况null

  10. rows
    估算出结果集行数,表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数、

  11. extra 的信息非常丰富,常见的有:
    Using index 使用覆盖索引
    Using where 使用了用where子句来过滤结果集
    Using filesort 使用文件排序,使用非索引列进行排序时出现,非常消耗性能,尽量优化。
    Using temporary 使用了临时表 sql优化的目标可以参考阿里开发手册

SQL性能优化的目标:至少要达到 range 级别,要求是ref级别,如果可以是consts最好。
说明:
1) consts 单表中最多只有一个匹配行(主键或者唯一索引),在优化阶段即可读取到数据。
2) ref 指的是使用普通的索引(normal index)。
3) range 对索引进行范围检索。
反例:explain表的结果,type=index,索引物理文件全扫描,速度非常慢,这个index级别比较range还低,与全表扫描是小巫见大巫。

25. 大表数据查询,怎么优化

  1. 优化shema、sql语句+索引;
  2. 第二加缓存,memcached, redis;
  3. 主从复制,读写分离;
  4. 垂直拆分,根据你模块的耦合度,将一个大的系统分为多个小的系统,也就是分布式系统;
  5. 水平切分,针对数据量大的表,这一步最麻烦,最能考验技术水平,要选择一个合理的sharding key, 为了有好的查询效率,表结构也要改动,做一定的冗余,应用也要改,sql中尽量带sharding key,将数据定位到限定的表上去查,而不是扫描全部的表;

利用延迟关联或者子查询优化超多分页场景。
说明:MySQL并不是跳过offset行,而是取offset+N行,然后返回放弃前offset行,返回N行,那当offset特别大的时候,效率就非常的低下,要么控制返回的总页数,要么对超过特定阈值的页数进行SQL改写。

正例:先快速定位需要获取的id段,然后再关联:

SELECT a.* FROM1 a, (select id from1 where 条件 LIMIT 100000,20 ) b where a.id=b.id

26. 慢查询日志

用于记录执行时间超过某个临界值的SQL日志,用于快速定位慢查询,为我们的优化做参考。

  • 开启慢查询日志
    配置项:slow_query_log

可以使用show variables like ‘slow_query_log’查看是否开启,如果状态值为OFF,可以使用set GLOBAL slow_query_log = on来开启,它会在datadir下产生一个xxx-slow.log的文件。

  • 设置临界时间
    配置项:long_query_time
    查看:show VARIABLES like ‘long_query_time’,单位秒
    设置:set long_query_time=0.5

实操时应该从长时间设置到短的时间,即将最慢的SQL优化掉
查看日志,一旦SQL超过了我们设置的临界时间就会被记录到xxx-slow.log中

27. 统计过慢查询吗?对慢查询都怎么优化过?

慢查询的优化首先要搞明白慢的原因是什么? 是查询条件没有命中索引?是load了不需要的数据列?还是数据量太大

所以优化也是针对这三个方向来的,

  1. 首先分析语句,看看是否load了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写。
  2. 分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中索引。
  3. 如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表。

28. 尽量设定一个主键?且主键使用自增ID?

  • 主键是数据库确保数据行唯一性的保障。设定了主键之后,在后续的删改查的时候可能更加快速以及确保操作数据范围安全

  • 主键使用自增ID,不要使用UUID。
    在InnoDB存储引擎中,主键索引是作为聚簇索引存在的,B+树叶子节点上存储了主键索引以及全部的数据(按照顺序),如果主键索引是自增ID,那么只需要不断向后排列即可,如果是UUID,由于到来的ID与原来的大小不确定,会造成非常多的插入,移动操作,然后导致产生很多的内存碎片,造成性能的下降。
    关于主键是聚簇索引,如果没有主键,InnoDB会选择一个唯一键来作为聚簇索引,如果没有唯一键,会生成一个隐式的主键。

29. 优化查询过程中的数据访问

  1. 访问数据太多导致查询性能下降
  2. 确定是否在检索大量超过需要的数据,确认是否在分析大量不必要的数据行或列
  3. 查询不需要的数据。解决办法:使用limit解决
  4. 多表关联返回全部列。解决办法:指定列名
  5. 总是返回全部列。解决办法:避免使用SELECT *
  6. 重复查询相同的数据。解决办法:可以缓存数据,下次直接读取缓存
  7. 是否在扫描额外的记录。解决办法
    使用explain进行分析,如果发现查询需要扫描大量的数据,但只返回少数的行,可以通过如下技巧去优化:
    使用索引覆盖扫描,把所有的列都放到索引中,这样存储引擎不需要回表获取
  8. 改变数据库和表的结构,修改数据表范式
  9. 重写SQL语句,让优化器可以以更优的方式执行查询。

30. 优化关联查询

确定ON或者USING子句中是否有索引。
确保GROUP BY和ORDER BY只有一个表中的列,这样MySQL才有可能使用索引。

31. 优化子查询

用关联查询替代
优化GROUP BY和DISTINCT
这两种查询据可以使用索引来优化,是最有效的优化方法
关联查询中,使用标识列分组的效率更高
如果不需要ORDER BY,进行GROUP BY时加ORDER BY NULL,MySQL不会再进行文件排序。
WITH ROLLUP超级聚合,可以挪到应用程序处理

32. 优化LIMIT分页

LIMIT偏移量大的时候,查询效率较低
可以记录上次查询的最大ID,下次查询时直接根据该ID来查询
优化UNION查询
UNION ALL的效率高于UNION

33. SQL where 语句优化的一些方法?

1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:

select id from t where num is null
-- 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
select id from t where num=

3.应尽量避免在 where 子句中使用!=或<>操作符,否则引擎将放弃使用索引而进行全表扫描。
4.应尽量避免在 where 子句中使用or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:

select id from t where num=10 or num=20
-- 可以这样查询:
select id from t where num=10 union all select id from t where num=20

5.in 和 not in 也要慎用,否则会导致全表扫描,如:

select id from t where num in(1,2,3) 
-- 对于连续的数值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3

7.如果在 where 子句中使用参数,也会导致全表扫描。
6.下面的查询也将导致全表扫描:select id from t where name like ‘%李%’若要提高效率,可以考虑全文检索。
8.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
9.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:
10.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。

34. 什么时候要使用索引?

  1. 主键自动建立唯一索引;
  2. 经常作为查询条件在WHERE或者ORDER BY 语句中出现的列要建立索引;
  3. 作为排序的列要建立索引;(单纯的order by 不会用到索引,但如果在where中出现,就可以用索引了。)
  4. 查询中与其他表关联的字段,外键关系建立索引
  5. 高并发条件下倾向组合索引;
  6. 用于聚合函数的列可以建立索引,例如使用了max(column_1)或者count(column_1)时的column_1就需要建立索引

35. 什么时候不要使用索引?

  1. 经常增删改的列不要建立索引;
  2. 有大量重复的列不建立索引;
  3. 表记录太少不要建立索引。只有当 数据库里已经有了足够多的测试数据时,它的性能测试结果才有实际参考价值。如果在测试数据库里只有几百条数据记录,它们往往在执行完第一条查询命令之后就被全部加载到内存里,这将使后续的查询命令都执行得非常快–不管有没有使用索引。只有当数据库里的记录超过了1000条、数据总量也超过了MySQL服务器上的内存总量时,数据库的性能测试结果才有意义。

36. 索引优化:

1、根据最左前缀原则,我们一般把排序分组频率最高的列放在最左边
2、模糊查询以%为开始的查询,只能使用全文索引来进行优化。
3、使用短索引。如果可能应该指定一个前缀长度。

group by语法可以根据给定数据列的每个成员对查询结果进行分组统计,最终得到一个分组汇总表。

SELECT DEPT, MAX(SALARY) AS MAXIMUM FROM STAFF GROUP BY DEPT :每个部分的最高薪水
SELECT DEPT, sum( SALARY ) AS total FROM STAFF GROUP BY DEPT,每个部门的总薪水

having字句可以让我们筛选成组后的各种数据,where字句在聚合前先筛选记录,也就是说作用在group by和having字句前而 having子句在聚合后对组记录进行筛选。我的理解就是真实表中没有此数据,这些数据是通过一些函数生成。

SELECT region, SUM(population), SUM(area) FROM bbc GROUP BY region HAVING SUM(area)>1000000

SELECT DEPT, MAX( SALARY ) AS MAXIMUM, MIN( SALARY ) AS MINIMUM FROM staff GROUP BY DEPT
HAVING COUNT( * ) >2  ORDER BY DEPT

查询最近N天(不超过30天)某一款产品的订单。从第10条开始取5条,ID从大到小倒序。

select * from table limit 9,5;#从0开始

写代码 创建索引

CREATE (UNIQUE/FULLTEXT/) INDEX indexName ON mytable(username(length)); 

ALTER table tableName ADD INDEX indexName(columnName);

CREATE TABLE mytable(  
ID INT NOT NULL,   
username VARCHAR(16) NOT NULL,  
INDEX [indexName] (username(length)) );
  

36. MySQL的复制原理以及流程

主从复制:将主数据库中的DDL和DML操作通过二进制日志(BINLOG)传输到从数据库上,然后将这些日志重新执行(重做);从而使得从数据库的数据与主数据库保持一致。

主从复制的作用

  1. 主数据库出现问题,可以切换到从数据库。
  2. 可以进行数据库层面的读写分离。
  3. 可以在从数据库上进行日常备份。

MySQL主从复制解决的问题

数据分布:随意开始或停止复制,并在不同地理位置分布数据备份
负载均衡:降低单个服务器的压力
高可用和故障切换:帮助应用程序避免单点失败
升级测试:可以用更高版本的MySQL作为从库

MySQL主从复制工作原理

  • 在主库上把数据记录到二进制日志
  • 从库将主库的日志复制到自己的中继日志
  • 从库读取中继日志的事件,将其重放到从库数据中

基本原理流程,3个线程以及之间的关联

主:binlog线程——记录下所有改变了数据库数据的语句,放进master上的binlog中;

从:io线程——在使用start slave 之后,负责从master上拉取 binlog 内容,放进自己的relay log中;

从:sql执行线程——执行relay log中的语句;

数据库面试总结_第1张图片
复制过程:
1、主节点log dump线程:当从节点连接主节点时,主节点会创建一个log dump 线程,用于发送bin-log的内容。在读取bin-log中的操作时,此线程会对主节点上的bin-log加锁,当读取完成,甚至在发动给从节点之前,锁会被释放。
2、从节点I/O线程:当从节点上执行start slave命令之后,从节点会创建一个I/O线程用来连接主节点,请求主库中更新的bin-log。I/O线程接收到主节点bin log dump 进程发来的更新之后,保存在本地relay-log中。
3、从节点SQL线程:SQL线程负责读取relay log中的内容,解析成具体的操作并执行,最终保证主从数据的一致性。

37. MySQL 主从复制默认是异步的模式:

异步复制:主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理;主节点不会主动push bin log到从节点;
半同步模式:这种模式下主节点只需要接收到其中一台从节点的返回信息,就会commit;否则需要等待直到超时时间然后切换成异步模式再提交;这样做的目的可以使主从数据库的数据延迟缩小,可以提高数据安全性。半同步模式不是mysql内置的,需要装插件开启半同步模式。
全同步模式:全同步模式是指主节点和从节点全部执行了commit并确认才会向客户端返回成功。

38. mysql主从复制存在的问题

  1. 主库宕机后,数据可能丢失
  2. 从库只有一个sql Thread,主库写压力大,复制很可能延时

解决方法:
半同步复制—解决数据丢失的问题
并行复制—-解决从库复制延迟的问题(并行是指从库多线程apply binlog库级别并行应用binlog,同一个库数据更改还是串行的(5.7版并行复制基于事务组)设置)

你可能感兴趣的:(数据库面试总结)