MySQL是一款开源关系型数据库管理系统,它利用结构化查询语言(SQL)来存储、检索和管理数据。
以MySQL递进的形式逐步理解MySQL面试题,是什么,怎么用,为什么用。
MySQL存储引擎
1、InnoDB存储引擎(默认的MySQL存储引擎)
特点
DML操作遵循ACID模型,支持事务;
行级锁,提高并发访问性能;
支持外键FOREIGN KEY约束,保证数据的完整性和正确性。
使用场景
如果应用对事务的完整性有比较高的要求,在并发条件下要求数据的一致性,数据操作除了插入和查询之外,还包含了很多的更新、删除操作,那么InnoDB存储引擎是合适的。
2、MyISAM
不支持事务,不支持外键
支持表锁,不支持行锁
访问速度快
使用场景
如果应用是以读操作和插入操作为主,只有很少的更新和删除操作,并且对事务的完整性、并发性要求不是很高,那么选择这个存储引擎是合适的。
CREATE TABLE your_table_name (id INT PRIMARY KEY,name VARCHAR(100)
) ENGINE=InnoDB;
3、Memory存储引擎
表数据时存储在内存中,由于受到硬件问题、或断电问题的影响,只能将这些表作为临时表或缓存使用。
特点
内存存放
hash索引(默认)
使用场景
将所有数据保存在内存中,访问速度快,通常用于临时表及缓存
存储过程定义
存储过程是事先经过编译并存储在数据库中的一段SQL语句的集合,用户可以指定存储过程的名字并给定参数(需要时)来调用执行。
delimiter//
create procedure CalculateSquare(in num int,out result int)
beginset result = num * num;
end //
delimiter;
delimiter用于更改命令结束符,以便在存储过程中使用begin...end语句,通过使用//作为新的结束符,并在存储过程中定义结束后将其改回;。
create procedure用于创建新的存储过程。
CalculateSquare是存储过程的名称。
(In num int,out result int)定义了输入和输出参数。在这个例子中,num是输入参数,result是输出参数。
begin... end之间的部分是存储过程的主体,即要执行的SQL语句。
调用存储过程
要调用上述存储过程并获取结果,需要使用CALL语句,并指定一个变量来接收输出参数的值。
SET @input = 5;
SET @output = 0;
CALL CalculateSquare(@input,@output);
SELECT @output;
MySQL语句的执行顺序
FROM子句->on->join->where->group by->having->select->distinct->union(all)->order by ->limit
数据约束
主键(primary key):物理上存储的顺序
非空(not null):此字段不允许填写空值
唯一(unique):此字段值不允许重复
默认值(default):当不填写此值时会使用默认值
外键(foreign key):维护两个表之间的联系
操作数据库SQL语句
操作数据库命令
查看所有数据库:show databases;
使用数据库:use 数据库名;
查看当前使用的数据库:select database();
创建数据库:create database 数据库名 charset=utf8;
删除数据库:drop database 数据库名;
操作数据表
(操作数据表之前要通过use打开对应的数据库)
常见数据表操作命令:查看当前数据库所有的表:show tables;
查看表结构:desc 表名;
查看表的创建语句:show create table 表名;
创建数据库表:格式:create table 表名(字段名1 类型 约束,字段名2 类型 约束,
);
删除数据库表
drop table 表名;
drop table if exists 表名;
在数据表中添加一行/多行数据
insert into 表名 values (),();
insert into 表名 (字段1,字段2,...)values (值1,值2,...)(值1,值2,...)
简单查询
select * from 表名;
修改数据
update 表名 set 字段名1=值1,字段名2=值2 where 条件
删除数据
delete from 表名 where 条件
truncate table 表名 (只删除数据)
drop table 表名 (删除所有数据和表结构)
说明:
delete --删除数据时,若新增数据,新增的id是删除的id号的后一个
truncate --删除数据后,若新增数据,是从id=1开始的
操作数据库联合查询
内连接
语法一:
select * from 表1 inner join 表2 on 表1.字段 = 表2.字段
语法二:(隐式内连接)
select * from 表1,表2 where 表1.字段=表2.字段
左连接
语法:select * from 表1 left join 表2 on 表1.字段=表2.字段;
右连接
select * from 表1 right join 表2 on 表1.字段=表2.字段
mysql数据库优化
1、索引优化
确保使用适当索引,使用explain查询
2、查询优化
避免select*,只选取需要的列
3、数据库结构优化
使用合适的数据类型
4、配置优化
5、硬件优化
6、定时优化
7、日志和监控
开启慢查询日志来查找需要优化的查询
SQL优化
1、避免使用select*
2、使用索引
3、选择合适的数据类型
5、批量查询
减少交互次数和服务器资源开销,提高整体效率。
MySQL索引
索引是帮助MySQL高效获取数据的数据结构。
索引的优缺点
优点:
提高数据的检索效率,降低数据库的I/O成本
通过索引对数据库进行排序,降低了数据的成本,降低了CPU的消耗
被索引的列会自动进行排序,包括单列排序和组合排序,只是组合索引的排序要复杂一些。
缺点:
索引会占据磁盘的空间
索引虽然会提高查询效率,但是会降低更新表的效率。比如每次对表进行增删该操作,MySQL不仅要保存数据,还有保存或者更新对应的索引文件。
索引的使用场景
需要创建索引
1、主键自动建立唯一索引
2、频繁作为查询条件的字段应该创建索引
不需要建立索引
1、表记录太少的
2、经常进行增删改的表
创建索引
单值索引
一个索引只包含单个列,一个表可以有多个单值索引。
1、建表时可随表一起建立单值索引。
2、单独创建和删除单值索引。
创建:alter table 表名 add index 索引名(字段)或create index 索引名 on 表名(字段)
删除:drop index 索引名 on 表名
复合索引
一个索引包含多个列
1、建表时可随表一起建立复合索引
2、单独创建和删除复合索引
创建:create index 索引名 on 表名 (字段1,字段2)或alter table 表名 add index 索引名 (字段1,字段2)
删除:drop index 索引名 on 表名
索引什么时候失效
1、列类型不匹配,如果查询中使用的列与索引列的类型不匹配,例如字符串类型上使用了数值比较,那么索引将无法正常工作。
2、函数操作
3、索引列值为空,如果查询条件中使用is null或is not null操作,而索引列上存在null,那么索引将无法正常工作。
4、类型转换,如果查询中使用了某种类型转换,例如在查询中将字符串转换为数字,那么索引将不再有效。
5、当使用OR语句时,索引可能会失效。
什么是索引回表,如何避免
回表的情况
当查询涉及的列不完全在索引中,或者查询请求的列没有在索引里时,数据库会首先通过索引定位到数据所在行,然后再去对应表中查找这些完整记录。
这种过程称为“回表”,因为它所需要从索引返回到原始的数据表中去获取数据。
回表可能会导致性能下降,因为它需要额外的IO操作,从索引到表的访问。
优化:为了避免回表,可以考虑创建覆盖索引,这样数据库可以直接从索引中返回结果,无需访问表。
B+树与B树的主要区别
1、所有键值存储在叶子节点:B+树的内部节点只存储键值用于导航,而不存储实际数据。所有实际数据存储在叶子节点中。
2、叶子节点之间有链表结构:B+树的叶子节点通过指针串联成一个双向链表,以方便范围查询和顺序遍历。
3、内节点不存储实际数据:内节点只用于引导查找路径,数据只保存在叶子节点。
B+树的优势
范围查找性能优越:由于B+树的叶子节点通过链表相连,范围查找操作非常高效。只需从起始节点找到目标范围的第一个叶子节点,然后通过链表依次遍历即可。
磁盘I/O效率高:B+树的内部节点只存储键值,用于导航查找路径,节省了内存空间,并且每次查询只需要访问叶子节点,减少了磁盘I/O操作。
支持顺序遍历:B+树的叶子节点有序排列并通过链表连接,可以高效地进行顺序遍历,特别适合范围查询和排序查询的场景。
什么是事务
事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有操作作为一个整体向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。
事务的操作
MySQL的事务操作主要有三种:
1、开启事务:Start Transaction或begin
2、提交事务:commit
成功结束,将所有的DML语句操作历史记录和底层硬盘数据来一次同步。
3、回滚事务:rollback
失败结束,将所有的DML语句操作历史记录全部清空。
设置MySQL的自动提交模式:
set autocommit=0 禁止自动提交
set autocommit=1 开启自动提交
事务的特性
原子性:事务是不可分割的最小操作单位,要么全部成功,要么全部失败。
一致性:事务完成时,必须所有的数据都保持一致性状态。
隔离性:数据库系统提供隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
持久性:事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。
事务出现的问题
脏读:当一个事务正在访问数据,并对数据进行修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据然后使用了这个数据。
不可重复读:值在一个事务内,多次读取同一数据。这个事务还没结束,另外一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的数据可能是不一样的。
幻读:在一个事务内多次查询某个符合条件的记录数量,如果前后两次查询到的记录数量不一样情况,意味着发生了幻读现象。
丢失更新:两个事务同时获取同一条记录,例如A先修改记录,B也修改记录(B不知道A修改过),B提交数据后B的修改结果覆盖了A的修改结果。
事务的隔离级别
1、读未提交(Read uncommitted)
一个事务可以读取另一个事务未提交的数据,最低级别,会造成脏读。
2、读已提交(Read committed)
一个事务要等另一个事务提交后才能读取数据,可避免脏读,会造成不可重复读。
3、可重复读(Repeatable read)
开始读取数据是,不在允许修改操作,可避免脏读,不可重复读发生,但会造成幻读。
4、串行化(Serializable)
MySQL默认隔离级别是Repeatable read
事务的传播机制
required:支持当前事务,如果没有事务,就新建一个事务。
supports:支持当前事务,如果没有事务,就以非事务的方式执行。
mandatory:支持当前事务,如果没有事务,就抛出异常。
requires_new:新建事务,如果当前存在事务,把当前事务挂起。
not_supported:以非事务方式执行,如果当前存在事务,就把当前事务挂起。
never:以非事务的方式执行,如果当前存在事务,则抛出异常。
nested:支持当前事务,如果当前事务存在,则嵌套事务,如果没有事务,就新建一个事务。
MVCC
多版本并发控制,在MySQL的InnoDB中处理并发时,不加锁和非阻塞并发读,提高读性能的一种机制。MVCC维持了数据的多个版本,让并发读写时没有冲突。
目的:就是多版本并发控制,在数据库中的实现,就是为了解决脏读和不可重复读等事务之间读写问题而诞生的,MVcc在某些场景中替代了相对的低效的锁(共享锁,排他锁),在保证了隔离性的基础上,提升了读取效率和并发性。
它的实现原理主要是依赖记录中的 3个隐式字段,undo log ,read view 来实现的。
后面三个隐含字段分别对应该行的隐含ID(DB_ROW_ID)、事务号(DB_TRX_ID,最新更新这条记录的事务ID)和回滚指针(DB_ROLL_PT,指向当前记录项的回滚的undo log记录 )。
MySQL的锁
全局锁
//使用全局锁
flush tables with read lock
执行后,整个数据库就处于只读状态,这时其它线程操作都会被阻塞。
//释放全局锁
unlock tables
会话断开,全局锁会被自动释放。
应用场景
全局锁主要应用于全库逻辑备份,这样在备份期间,不会因为数据或表结构的更新,而出现备份文件的数据与预期不一样。
缺点
加全局锁,业务只能读数据,而不能更新数据,这样会造成业务停滞。
解决
如果数据库的引擎支持的事务支持可重复读的隔离级别,那么在备份数据库之前开启事务,会先创建Read View,然后整个事务执行期间都在用这个Read View,而且由于MVCC的支持,备份期间业务依然可以对数据进行更新操作。
表锁
//表级别的共享锁,也就是读锁
lock tables table_name read;
//表级别的排它锁,也就是写锁
lock tables table_name write;//释放锁
unlock tables
1、意向锁,当执行插入、更新、删除操作,需要先对表加上意向独占锁,然后对记录加独占锁。
意向锁的目的是为了快速判断表里是否有记录被加锁。
2、自增锁,当事务插入数据到自增列时就会触发。当某个事务在往表中插入数据时,另外一个事务必须等待上个事务执行完毕,实现主键的连续自增。
行级锁
1、Record Lock,记录锁,也就是把一条记录锁上。
2、Gap Lock,间隙锁,锁定一个范围,但是不包含记录本身。只存在于可重复读隔离级别,目的是为了解决可重复读隔离级别下的幻读。
3、Next-Key Lock,记录锁和间隙锁组合,锁定一个范围,并且锁定记录本身。
4、插入意向锁,有insert操作在行插入之前设置的一种间隙锁,当多个事务插入记录到相同索引间隙时彼此并不需要互相等待,除非插入到相同的位置。
MySQL的主从复制
MySQL主从复制是一种用于实现数据库高可用和负载均衡的机制,它允许一个MySQL主服务器(主库)将数据同步到一个或多个从服务器(从库)。这个过程可以实时或近实时进行,主要用于提高系统的读取性能、故障转移和数据备份。
怎么保证主从库中数据的一致性
异步复制:虽然MySQL默认使用异步复制,在这种模式下,主库提交事务不会后不会等待从库确认,这可能导致数据不一致。
半同步复制:在这种模式下,主库提交事务后等待至少一个从库确认接收到并写入到中继日志中,才返回给客户端。这提高了数据的一致性,但可能会引入一定延迟。
全同步复制:要求所有的从库都接收到主库的数据并且执行完成其中事务后,主库才会返回客户端,虽然这种模式下数据强一致性得到保证,但性能损耗较大。
处理数据库百万条数据,按年月日分别查询排序
1、索引优化
创建日期索引,复合索引
2、查询优化
使用范围查询,排序,限制结果集
3、分区表
按日期分区
4、缓存和视图化