MySQL面经

# 数据库基础知识

## 为什么要使用数据库

### 数据保存在内存

优点:存取速度快

缺点:数据不能永久保存

### 数据保存在文件

优点:数据永久保存

缺点:1)速度比内存操作慢,频繁的IO操作。

​            2)查询数据不方便

### 数据保存在数据库

1)数据永久保存

2)使用SQL语句,查询方便效率高。

3)管理数据方便

## 什么是SQL?

结构化查询语言(StructuredQueryLanguage)简称SQL,是一种数据库查询语言。

作用:用于存取数据、查询、更新和管理关系数据库系统。

## 什么是MySQL?

MySQL是一个关系型数据库管理系统,由瑞典MySQLAB公司开发,属于Oracle旗下产品。MySQL是最流行的关系型数据库管理系统之一,在WEB应用方面,MySQL是最好的RDBMS(RelationalDatabaseManagementSystem,关系数据库管理系统)应用软件之一。在Java企业级开发中非常常用,因为MySQL是开源免费的,并且方便扩展。

## 数据库三大范式是什么

第一范式:每个列都不可以再拆分。

第二范式:在第一范式的基础上,非主键列完全依赖于主键,而不能是依赖于主键的一部分。

第三范式:在第二范式的基础上,非主键列只依赖于主键,不依赖于其他非主键。

在设计数据库结构的时候,要尽量遵守三范式,如果不遵守,必须有足够的理由。比如性能。事实上我们经常会为了性能而妥协数据库的设计。

## mysql有关权限的表都有哪几个

MySQL服务器通过权限表来控制用户对数据库的访问,权限表存放在mysql数据库里,由mysql_install_db脚本初始化。这些权限表分别user,db,table_priv,columns_priv和host。下面分别介绍一下这些表的结构和内容:

user权限表:记录允许连接到服务器的用户帐号信息,里面的权限是全局级的。

db权限表:记录各个帐号在各个数据库上的操作权限。

table_priv权限表:记录数据表级的操作权限。

columns_priv权限表:记录数据列级的操作权限。

host权限表:配合db权限表对给定主机上数据库级操作权限作更细致的控制。这个权限表不受GRANT和REVOKE语句的影响。

## MySQL的binlog有有几种录入格式?分别有什么区别?

有三种格式,statement,row和mixed。

- statement模式下,每一条会修改数据的sql都会记录在binlog中。不需要记录每一行的变化,减少了binlog日志量,节约了IO,提高性能。由于sql的执行是有上下文的,因此在保存的时候需要保存相关的信息,同时还有一些使用了函数之类的语句无法被记录复制。
- row级别下,不记录sql语句上下文相关信息,仅保存哪条记录被修改。记录单元为每一行的改动,基本是可以全部记下来但是由于很多操作,会导致大量行的改动(比如altertable),因此这种模式的文件保存的信息太多,日志量太大。
- mixed,一种折中的方案,普通操作使用statement记录,当无法使用statement的时候使用row。

此外,新版的MySQL中对row级别也做了一些优化,当表结构发生变化的时候,会记录语句而不是逐行记录。

# 数据类型

## mysql有哪些数据类型

| 分类                 | 类型名称                                                   | 说明                  |
| -------------------- | ---------------------------------------------------------- | --------------------- |
| **整数类型**         | tinyInt                                                    | 很小的整数(8位二进制) |
| smallint             | 小的整数(16位二进制)                                       |                       |
| mediumint            | 中等大小的整数(24位二进制)                                 |                       |
| int(integer)         | 普通大小的整数(32位二进制)                                 |                       |
| **小数类型**         | float                                                      | 单精度浮点数          |
| double               | 双精度浮点数                                               |                       |
| decimal(m,d)         | 压缩严格的定点数                                           |                       |
| **日期类型**         | year                                                       | YYYY1901~2155         |
| time                 | HH:MM:SS-838:59:59~838:59:59                               |                       |
| date                 | YYYYMM-DD1000-01-01~9999-12-3                              |                       |
| datetime             | YYYYMM-DDHH:MM:SS1000-01-0100:00:00~9999-12-3123:59:59     |                       |
| timestamp            | YYYYMM-DDHH:MM:SS1970010100:00:01UTC~2038-01-1903:14:07UTC |                       |
| **文本、二进制类型** | **CHAR(M)**                                                | M为0~65535之间的整数  |
| VARCHAR(M)           | M为0~65535之间的整数                                       |                       |
| TINYBLOB             | 允许长度0~255字节                                          |                       |
| BLOB                 | 允许长度0~65535字节                                        |                       |
| MEDIUMBLOB           | 允许长度0~167772150字节                                    |                       |
| LONGBLOB             | 允许长度0~4294967295字节                                   |                       |
| TINYTEXT             | 允许长度0~255字节                                          |                       |
| TEXT                 | 允许长度0~65535字节                                        |                       |
| MEDIUMTEXT           | 允许长度0~167772150字节                                    |                       |
| LONGTEXT             | 允许长度0~4294967295字节                                   |                       |
| VARBINARY(M)         | 允许长度0~M个字节的变长字节字符串                          |                       |
| BINARY(M)            | 允许长度0~M个字节的定长字节字符串                          |                       |

**整数类型**,包括TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT,分别表示1字节、2字节、3字节、4字节、8字节整数。任何整数类型都可以加上UNSIGNED属性,表示数据是无符号的,即非负整数。

长度:整数类型可以被指定长度,例如:INT(11)表示长度为11的INT类型。长度在大多数场景是没有意义的,它不会限制值的合法范围,只会影响显示字符的个数,而且需要和UNSIGNEDZEROFILL属性配合使用才有意义。

例子,假定类型设定为INT(5),属性为UNSIGNEDZEROFILL,如果用户插入的数据为12的话,那么数据库实际存储数据为00012。

**实数类型**,包括FLOAT、DOUBLE、DECIMAL。DECIMAL可以用于存储比BIGINT还大的整型,能存储精确的小数。而FLOAT和DOUBLE是有取值范围的,并支持使用标准的浮点进行近似计算。
计算时FLOAT和DOUBLE相比DECIMAL效率更高一些,DECIMAL你可以理解成是用字符串进行处理。

**字符串类型**,包括VARCHAR、CHAR、TEXT、BLOBVARCHAR用于存储可变长字符串,它比定长类型更节省空间。
VARCHAR使用额外1或2个字节存储字符串长度。列长度小于255字节时,使用1字节表示,否则使用2字节表示。
VARCHAR存储的内容超出设置的长度时,内容会被截断。
CHAR是定长的,根据定义的字符串长度分配足够的空间。
CHAR会根据需要使用空格进行填充方便比较。
CHAR适合存储很短的字符串,或者所有值都接近同一个长度。
CHAR存储的内容超出设置的长度时,内容同样会被截断。

**使用策略:**

对于经常变更的数据来说,CHAR比VARCHAR更好,因为CHAR不容易产生碎片。

对于非常短的列,CHAR比VARCHAR在存储空间上更有效率。

使用时要注意只分配需要的空间,更长的列排序时会消耗更多内存。尽量避免使用TEXT/BLOB类型,查询时会使用临时表,导致严重的性能开销。

**枚举类型(ENUM)**,把不重复的数据存储为一个预定义的集合。有时可以使用ENUM代替常用的字符串类型。ENUM存储非常紧凑,会把列表值压缩到一个或两个字节。ENUM在内部存储时,其实存的是整数。尽量避免使用数字作为ENUM枚举的常量,因为容易混乱。排序是按照内部存储的整数

**日期和时间类型**,尽量使用timestamp,空间效率高于datetime,用整数保存时间戳通常不方便处理。
如果需要存储微妙,可以使用bigint存储。

看到这里,这道真题是不是就比较容易回答了。

# 引擎

## MySQL存储引擎MyISAM与InnoDB区别

存储引擎Storageengine:MySQL中的数据、索引以及其他对象是如何存储的,是一套文件系统的实现。

常用的存储引擎有以下:

**Innodb引擎:**Innodb引擎提供了对数据库ACID事务的支持。并且还提供了行级锁和外键的约束。它的设计的目标就是处理大数据容量的数据库系统。

**MyIASM引擎(原本Mysql的默认引擎):**不提供事务的支持,也不支持行级锁和外键。

**MEMORY引擎:**所有的数据都在内存中,数据的处理速度快,但是安全性不高。

**MyISAM与InnoDB区别**

| MyISAM                                                       | Innodb                                                       |                                                              |
| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| 存储结构                                                     | 每张表被存放在三个文件:frm-表格定义、MYD(MYData)-数据文件、MYI(MYIndex)-索引文件 | 所有的表都保存在同一个数据文件中(也可能是多个文件,或者是独立的表空间文件),InnoDB表的大小只受限于操作系统文件的大小,一般为2GB |
| 存储空间                                                     | MyISAM可被压缩,存储空间较小                                 | InnoDB的表需要更多的内存和存储,它会在主内存中建立其专用的缓冲池用于高速缓冲数据和索引 |
| 可移植性、备份及恢复                                         | 由于MyISAM的数据是以文件的形式存储,所以在跨平台的数据转移中会很方便。在备份和恢复时可单独针对某个表进行操作 | 免费的方案可以是拷贝数据文件、备份binlog,或者用mysqldump,在数据量达到几十G的时候就相对痛苦了 |
| 文件格式                                                     | 数据和索引是分别存储的,数据.MYD,索引.MYI                   | 数据和索引是集中存储的,.ibd                                 |
| 记录存储顺序                                                 | 按记录插入顺序保存                                           | 按主键大小有序插入                                           |
| 外键                                                         | 不支持                                                       | 支持                                                         |
| 事务                                                         | 不支持                                                       | 支持                                                         |
| 锁支持(锁是避免资源争用的一个机制,MySQL锁对用户几乎是透明的) | 表级锁定                                                     | 行级锁定、表级锁定,锁定力度小并发能力高                     |
| SELECT                                                       | MyISAM更优                                                   |                                                              |
| INSERT、UPDATE、DELETE                                       | InnoDB更优                                                   |                                                              |
| selectcount(*)                                               | myisam更快,因为myisam内部维护了一个计数器,可以直接调取。   |                                                              |
| 索引的实现方式                                               | B+树索引,myisam是堆表                                       | B+树索引,Innodb是索引组织表                                 |
| 哈希索引                                                     | 不支持                                                       | 支持                                                         |
| 全文索引                                                     | 支持                                                         | 不支持                                                       |

## **MyISAM索引与InnoDB索引的区别?**

- InnoDB索引是聚簇索引,MyISAM索引是非聚簇索引。
- InnoDB的主键索引的叶子节点存储着行数据,因此主键索引非常高效。
- MyISAM索引的叶子节点存储的是行数据地址,需要再寻址一次才能得到数据。
- InnoDB非主键索引的叶子节点存储的是主键和其他带索引的列数据,因此查询时做到覆盖索引会非常高效。

## **InnoDB引擎的4大特性**

- 插入缓冲(insertbuffer)
- 二次写(doublewrite)
- 自适应哈希索引(ahi)
- 预读(readahead)

## 存储引擎选择

如果没有特别的需求,使用默认的Innodb即可。
MyISAM:以读写插入为主的应用程序,比如博客系统、新闻门户网站。
Innodb:更新(删除)操作频率也高,或者要保证数据的完整性;并发量高,
支持事务和外键。比如OA自动化办公系统。

# 索引

## 什么是索引?

索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它
们包含着对数据表里所有记录的引用指针。
索引是一种数据结构。数据库索引,是数据库管理系统中一个排序的数据结构,
以协助快速查询、更新数据库表中数据。索引的实现通常使用B树及其变种
B+树。
更通俗的说,索引就相当于目录。为了方便查找书中的内容,通过对内容建立索
引形成目录。索引是一个文件,它是要占据物理空间的。

## 索引有哪些优缺点?

## 索引使用场景(重点)

![image-20201111145020510](09-MySQL数据库面试题(2020最新版)-重点.assets/image-20201111145020510.png)

上图中,根据id查询记录,因为id字段仅建立了主键索引,因此此SQL执行可选
的索引只有主键索引,如果有多个,最终会选一个较优的作为检索的依据。

```
1‐‐增加一个没有建立索引的字段
2altertableinnodb1addsexchar(1);
3‐‐按sex检索时可选的索引为null
4EXPLAINSELECT*frominnodb1wheresex='男';
```

![09-MySQL数据库面试题(2020最新版)-重点](09-MySQL数据库面试题(2020最新版)-重点.assets/09-MySQL数据库面试题(2020最新版)-重点.jpg)

> 可以尝试在一个字段未建立索引时,根据该字段查询的效率,然后对该字段建立索引
> (altertable表名addindex(字段名)),同样的SQL执行的效率,你会发现查询效率
> 会有明显的提升(数据量越大越明显)。

orderby
当我们使用orderby将查询结果按照某个字段排序时,如果该字段没有建立索
引,那么执行计划会将查询出的所有数据使用外部排序(将数据从硬盘分批读取
到内存使用内部排序,最后合并排序结果),这个操作是很影响性能的,因为需
要将查询涉及到的所有数据从磁盘中读到内存(如果单条数据过大或者数据量过
多都会降低效率),更无论读到内存之后的排序了。
但是如果我们对该字段建立索引altertable表名addindex(字段名),那么由于索引
本身是有序的,因此直接按照索引的顺序和映射关系逐条取出数据即可。而且如
果分页的,那么只用取出索引表某个范围内的索引对应的数据,而不用像上述那

取出所有数据进行排序再返回某个范围内的数据。(从磁盘取数据是最影响性能
的)
join
对join语句匹配关系(on)涉及的字段建立索引能够提高效率
索引覆盖
如果要查询的字段都建立过索引,那么引擎会直接在索引表中查询而不会访问原
始数据(否则只要有一个字段没有建立索引就会做全表扫描),这叫索引覆盖。
因此我们需要尽可能的在select后只写必要的查询字段,以增加索引覆盖的几
率。
这里值得注意的是不要想着为每个字段建立索引,因为优先使用索引的优势就在
于其体积小。

## 索引有哪几种类型?

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

**唯一索引:**数据列不允许重复,允许为NULL值,
一个表允许多个列创建唯一索引。

- 可以通过ALTERTABLEtable_nameADDUNIQUE(column);
  创建唯一索引
- 可以通过ALTERTABLEtable_nameADDUNIQUE(column1,column2);
  创建唯一组合索引

**普通索引:**基本的索引类型,没有唯一性的限制,允许为NULL值。

- 可以通过ALTERTABLEtable_nameADDINDEXindex_name(column);
  创建普通索引
- 可以通过ALTERTABLEtable_nameADDINDEXindex_name(column1,column2,column3);
  创建组合索引

- **全文索引:**是目前搜索引擎使用的一种关键技术。
  可以通过ALTERTABLEtable_nameADDFULLTEXT(column);
  创建全文索引

## 索引的数据结构(b树,hash)

索引的数据结构和具体存储引擎的实现有关,在MySQL中使用较多的索引有

Hash索引,B+树索引等,而我们经常使用的InnoDB存储引擎的默认索引实现为:B+树索引。对于哈希索引来说,底层的数据结构就是哈希表,因此在绝大多数需求为单条记录查询的时候,可以选择哈希索引,查询性能快;其余大部分场景,建议选择BTree索引。

1)B树索引mysql通过存储引擎取数据,基本上90%的人用的就是InnoDB了,按照实现方式分,InnoDB的索引类型目前只有两种:BTREE(B树)索引和HASH索引。B树索引是Mysql数据库中使用频繁的索引类型,基本所有存储引擎都支持

BTree索引。通常我们说的索引不出意外指的就是(B树)索引(实际是用B+树实现的,因为在查看表索引时,mysql一律打印BTREE,所以简称为B树索引)

![B树](09-MySQL数据库面试题(2020最新版)-重点.assets/B树.jpg)

查询方式:

主键索引区:PI(关联保存的时数据的地址)按主键查询,

普通索引区:si(关联的id的地址,然后再到达上面的地址)。所以按主键查询,速度快

B+tree性质:

1.)n棵子tree的节点包含n个关键字,不用来保存数据而是保存数据的索引。

2.)所有的叶子结点中包含了全部关键字的信息,及指向含这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。

3.)所有的非终端结点可以看成是索引部分,结点中仅含其子树中的大(或小)关键字。

4.)B+树中,数据对象的插入和删除仅在叶节点上进行。

5.)B+树有2个头指针,一个是树的根节点,一个是小关键码的叶节点。2)哈希索引简要说下,类似于数据结构中简单实现的HASH表(散列表)一样,当我们在

mysql中用哈希索引时,主要就是通过Hash算法(常见的Hash算法有直接定址法、平方取中法、折叠法、除数取余法、随机数法),将数据库字段数据转换成定长的Hash值,与这条数据的行指针一并存入Hash表的对应位置;如果发生

Hash碰撞(两个不同关键字的Hash值相同),则在对应Hash键下以链表形式存储。当然这只是简略模拟图。

![哈希索引](09-MySQL数据库面试题(2020最新版)-重点.assets/哈希索引.jpg)

### 索引的基本原理

索引用来快速地寻找那些具有特定值的记录。如果没有索引,一般来说执行查询时遍历整张表。

索引的原理很简单,就是把无序的数据变成有序的查询

1. 把创建了索引的列的内容进行排序

2. 对排序结果生成倒排表

3. 在倒排表内容上拼上数据地址链

4. 在查询的时候,先拿到倒排表内容,再取出数据地址链,从而拿到具体数据

### 索引算法有哪些?

索引算法有BTree算法和Hash算法

BTree算法

BTree是常用的mysql数据库索引算法,也是mysql默认的算法。因为它不仅可以被用在=,>,>=,<,<=和between这些比较操作符上,而且还可以用于like操作符,只要它的查询条件是一个不以通配符开头的常量,例如:

```
1    ‐‐只要它的查询条件是一个不以通配符开头的常量
2    select*fromuserwherenamelike'jack%';
3    ‐‐如果一通配符开头,或者没有使用常量,则不会使用索引,例如:
4    select*fromuserwherenamelike'%jack';
```

Hash算法

HashHash索引只能用于对等比较,例如=,<=>(相当于=)操作符。由于是一次定位数据,不像BTree索引需要从根节点到枝节点,后才能访问到页节点这样多次IO访问,所以检索效率远高于BTree索引。

### 索引设计的原则?

\1.适合索引的列是出现在where子句中的列,或者连接子句中指定的列

\2.基数较小的类,索引效果较差,没有必要在此列建立索引

\3.使用短索引,如果对长字符串列进行索引,应该指定一个前缀长度,这样能够节省大量索引空间

\4.不要过度索引。索引需要额外的磁盘空间,并降低写操作的性能。在修改表内容的时候,索引会进行更新甚至重构,索引列越多,这个时间就会越长。所以只保持需要的索引有利于查询即可。

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

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

1)左前缀匹配原则,组合索引非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a=1andb=2andc>3andd=4如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立

(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。

2)较频繁作为查询条件的字段才去创建索引

3)更新频繁字段不适合创建索引

4)若是不能有效区分数据的列不适合做索引列(如性别,男女未知,多也就三种,区分度实在太低)

5)尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。

6)定义有外键的数据列一定要建立索引。

7)对于那些查询中很少涉及的列,重复值比较多的列不要建立索引。8)对于定义为text、image和bit的数据类型的列不要建立索引。创建索引的三种方式,删除索引

第一种方式:在执行CREATETABLE时创建索引

```
1    CREATETABLEuser_index2(
2    idINTauto_incrementPRIMARYKEY,
3    first_nameVARCHAR(16),
4    last_nameVARCHAR(16),
5    id_cardVARCHAR(18),
6    informationtext,
7    KEYname(first_name,last_name),
8    FULLTEXTKEY(information),
9    UNIQUEKEY(id_card));
```

第二种方式:使用ALTERTABLE命令去增加索引

`1ALTERTABLEtable_nameADDINDEXindex_name(column_list);`

ALTERTABLE用来创建普通索引、UNIQUE索引或PRIMARYKEY索引。

其中table_name是要增加索引的表名,column_list指出对哪些列进行索引,多列时各列之间用逗号分隔。

索引名index_name可自己命名,缺省时,MySQL将根据第一个索引列赋一个名称。另外,ALTERTABLE允许在单个语句中更改多个表,因此可以在同时创建多个索引。

第三种方式:使用CREATEINDEX命令创建

`1CREATEINDEXindex_nameONtable_name(column_list);`

CREATEINDEX可对表增加普通索引或UNIQUE索引。(但是,不能创建PRIMARYKEY索引)

删除索引

根据索引名删除普通索引、唯一索引、全文索引:altertable表名dropKEY索引名

```
1    altertableuser_indexdropKEYname;
2    altertableuser_indexdropKEYid_card;
3    altertableuser_indexdropKEYinformation;
```

删除主键索引:altertable表名dropprimarykey(因为主键只有一个)。这里值得注意的是,如果主键自增长,那么不能直接执行此操作(自增长依赖于主键索引):

![删除主键索引](09-MySQL数据库面试题(2020最新版)-重点.assets/删除主键索引.jpg)

需要取消自增长再行删除:

```
1    altertableuser_index
2    ‐‐重新定义字段
3    MODIFYidint,
4    dropPRIMARYKEY
```

但通常不会删除主键,因为设计主键一定与业务逻辑无关。

### 创建索引时需要注意什么?

- 非空字段:应该指定列为NOTNULL,除非你想存储NULL。在mysql中,含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较运算更加复杂。你应该用0、一个特殊的值或者一个空串代替空值;
- 取值离散大的字段:(变量各个取值之间的差异程度)的列放到联合索引的前面,可以通过count()函数查看字段的差异值,返回值越大说明字段的唯一值越多字段的离散程度高;
- 索引字段越小越好:数据库的数据存储以页为单位一页存储的数据越多一次IO操作获取的数据越大效率越高。

### 使用索引查询一定能提高查询的性能吗?为什么

通常,通过索引查询数据比全表扫描要快。但是我们也必须注意到它的代价。

索引需要空间来存储,也需要定期维护,每当有记录在表中增减或索引列被修改时,索引本身也会被修改。这意味着每条记录的INSERT,DELETE,UPDATE将为此多付出4,5次的磁盘I/O。因为索引需要额外的存储空间和处理,那些不必要的索引反而会使查询反应时间变慢。使用索引查询不一定能提高查询性能,索引范围查询(INDEXRANGESCAN)适用于两种情况:

基于一个范围的检索,一般查询返回结果集小于表中记录数的30%

基于非唯一性索引的检索

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

关于索引:由于索引需要额外的维护成本,因为索引文件是单独存在的文件,所以当我们对数据的增加,修改,删除,都会产生额外的对索引文件的操作,这些操作需要消耗额外的IO,会降低增/改/删的执行效率。所以,在我们删除数据库百万级别数据的时候ÿ

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值