mysql面试题话术

1、解释一下单列索引和联合索引

单列索引是指在表的某一列上创建索引,联合索引是在多个列上联合创建索引。单列索引可以出现在where条件的任何位置,而联合索引需要按照一定的顺序来写。在多条件查询的时候,联合索引的效率更高,我们联合索引也最多创建两列。

我们创建索引的时候也得考虑到我们这张表的更新频率,如果表里索引比较多的话是比较影响更新速度的,因为创建索引的过程其实就是构建一个二叉树,而每次更新完数据都得重新计算二叉树,所以就影响更新速度。

索引并不是时时都会生效的,比如以下几种情况就能导致索引失效:

如果条件中有or,即使其中有条件带索引也不会使用,这也是为什么尽量少用or的原因,如果要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引
like查询是以%开头,会导致索引失效
如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则索引失效
如果mysql估计使用全表扫描要比使用索引快,则不使用索引
所以呢,我们创建索引的话,也不是随便创建的,我给您说下一些常用的创建索引的原则吧(接着背第四题)

2、使用索引查询的优缺点

使用索引优点第一:可以保证数据库表中每一行的数据的唯一性,第二:可以大大加快数据的索引速度,在使用分组和排序语句

进行数据检索时,同样可以显著减少查询中分组和排序的时间;

缺点:创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加

3、mysql存储引擎都有哪些,有什么区别

我了解到的数据库搜索引擎有MyISAM、InnoDB、BDB、MEMORY等,对于 MySQL 5.5 及更高版本,默认的存储引擎是 InnoDB。在 5.5 版本之前,MySQL 的默认存储引擎是 MyISAM,我主要给您介绍下这两个的区别吧

InnoDB 存储引擎:

支持自增长列(auto_increment),自增长列的值不能为空,如果在使用的时候为空的话就会从现有的最大值自动+1,如果有但是比现在的还大,则就保存这个值。

支持外键(foreign key),外键所在的表称为子表而所依赖的表称为父表。

支持事务,回滚以及系统崩溃的修复能力,并且支持多版本并发控制的事务安全。

支持mvcc(多版本并发控制)的行级锁,就是通过多版本控制来实现的乐观锁

索引使用的是B+Tree

优缺点:InnoDB的优势在于提供了良好的事务处理、崩溃修复能力和并发控制。缺点是读写效率较差,占用的数据空间相对较大。

MyISAM 存储引擎

不支持事务、支持表级锁

支持全文搜索

缓冲池只缓存索引文件,

不缓存数据文件 MyISAM 存储引擎表由 数据文件(MYD)和索引文件( MYI)组成

我们项目中常用到的是innoDB,InnoDB存储引擎提供了具有提交、回滚和崩溃恢复能力的事务安全,但是对比Myisam的存储引擎InnoDB写的处理效率差一些并且会占用更多的磁盘空间以保留数据和索引。

4、创建索引的原则

经常需要搜索的列上建立索引,可以加快搜索的速度。

在作为主键的列上创建索引,强制该列的唯一性,并组织表中数据的排列结构。

在经常使用表连接的列上创建索引,这些列主要是一些外键,可以加快表连接的速 度。

在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,所以其指定的 范围是连续的。

在经常需要排序的列上创建索引,因为索引已经排序,所以查询时可以利用索引的 排序,加快排序查询。

在经常使用 WHERE 语句的列上创建索引,加快条件的判断速度。

5、如何查看查询语句索引是否生效

使用 explain 执行计划查看 在sql前面加入关键字explain 查询出的结果查看type类型检查是否有执行索引

举例:EXPLAIN select * from table where id=2;我们一般优化sql语句的话,type级别都要至少达到ref级别,就是每次查询必须要使用索引

在这里插入图片描述
在这里插入图片描述

6、有没有做过数据库建模,自己是设计表和模块

一个有三年工作经验的人,一定要说设计过,(实际工作经验的程序员:在系统设计、需求文档,数据建模都应该有所涉及)

数据库建模就是使用PowerDesigner工具,先分析项目需求,前端先出相应的原型,根据原型,我开始做相应的表,设计初期的时候表会有些小浮动修改等,再根据需求设计详细字段。如果后期客户需求改变时,表结构后期跟着调整,就是这样使用工具不断完善过程就是建模,不过一些小的项目的话,简单的通过Navicat里的模型工具就可以实现了
mysql高性能优化的注意点:
https://javaguide.cn/database/mysql/mysql-high-performance-optimization-specification-recommendations.html#%E7%A6%81%E6%AD%A2%E5%9C%A8%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%AD%E5%AD%98%E5%82%A8%E6%96%87%E4%BB%B6-%E6%AF%94%E5%A6%82%E5%9B%BE%E7%89%87-%E8%BF%99%E7%B1%BB%E5%A4%A7%E7%9A%84%E4%BA%8C%E8%BF%9B%E5%88%B6%E6%95%B0%E6%8D%AE

7、左连接、右连接、内连接的区别

内连接的话,就是两表关联的数据才能查出来,关联不到的就查询不到。左连接就是以左表为主,左表数据全查,右表数据没有就显示null,右连接相反

我给您举个例子吧,比如员工和部门表,如果要查询出每个员工的信息以及他的部门信息,那么这个时候用内连接最合适。如果要查询出每个部门下对应的员工信息,那么就需要以部门表为左表,进行左连接查询。这样的话,没有员工的部门也可以被查询出来。

8、 count(1)和count(*) 有什么区别

从执行结果来看count()和count(1)没有区别,因为他们都不过滤空值
从执行效率来看MySQL会对count(
)做优化
(1)如果列为主键,count(列名)效率优于count(1)

(2)如果列不为主键,count(1)效率优于count(列名)

(3)如果表中存在主键,count(主键列名)效率最优

(4)如果表中只有一列,则count(*)效率最优
COUNT(column_name):用于统计特定列中非 NULL 值的行数,适用于需要排除 NULL 值的场景。

9、mysql查询语句的优化?

对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及 的列上建立索引。

应尽量避免在 where 子句中使用!=或<>操作符,否则引擎将放弃使用索引而进行 全表扫描。

应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用 索引而进行全表扫描,如: select id from t where num is null 可以在 num 上设置默认值 0,确保表中 num 列没有 null 值,然后这样查询:select id from t where num=0

应尽量避免在 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

以%开头的模糊查询也会导致全表扫描: select id from t where name like ‘%abc%’ ,如果要提高效率的话,可以考虑全文检索来解决。

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

应尽量避免在 where 子句中对字段进行表达式操作,这将导致放弃使用索引 而进行全表扫描。如:select id from t where num/2=100 应改为: select id from t where num=100*2

应尽量避免在 where 子句中对字段进行函数操作,这将导致引擎放弃使用索引而 进行全表扫描。

比如说查询name以abc开头的数据: select id from t where substring(name,1,3)=‘abc’ ,可以改为select id from t where name like ‘abc%’

不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系 统将可能无法正确使用索引。

在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中 的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可 能的让字段顺序与索引顺序相一致。

很多时候用 exists 代替 in 是一个好的选择: select num from a where num in(select num from b) 用下面的语句替换: select num from a where exists(select 1 from b where num=a.num)

并不是所有索引对查询都有效,SQL 是根据表中数据来进行查询优化的,当索引 列有大量数据重复时,SQL 查询可能不会去利用索引,如一表中有字段 sex,男、女的值 几乎各一半,那么即使在 sex 上建了索引也对查询效率起不了作用。

索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低 了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索 引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过 6 个

10、mysql批量插入5000条数据如何优化?

第一种方法:
合并sql插入语句,合并后日志量减少,降低日志刷盘的数据量和频率,从而提高效率,通过合并SQL语句,

同时也能减少SQL语句解析的次数,减少网络传输的IO

比如:INSERT INTO table(uid,content, type) VALUES (‘userid_0’, ‘content_0’, 0);

改为:

INSERT INTO table (uid,content, type) VALUES (‘userid_0’, ‘content_0’, 0), (‘userid_1’,‘content_1’, 1);
第二种方法:
在同一个事务中进行插入处理

这是因为进行一个INSERT操作时,MySQL内部会建立一个事务,在事务内才进行真正插入处理操作。通过使用同一个事务可以减少创建事务所消耗的时间,所有插入都在执行后才统一进行提交操作。

11、mysql查询重复数据?

比如A表有字段id,pid,sname,

查询重复数据:select * from A

where pid in (select pid from A group by pid having count(pid) > 1);

12、了解过MySQL存储过程和视图吗,介绍一下

存储过程
存储程序是被存储在服务器中的组合SQL语句,经过创建编译并保存在数据库中,用户可通过存储过程的名字调用执行。存储过程核心思想就是数据库SQL语言层面的封装与复用。使用存储过程可以较少应对系统的业务复杂性,但是会增加数据库服务器系统的负荷,所以在使用的时候需要综合业务考虑。

对应存储过程的名字使用call调用 ,把对应的参数传递进去,输出参数使用@声明

基本语法,了解熟悉一下

– 创建存储过程

DROP PROCEDURE IF EXISTS p01_discount; //如果存在先删掉再创建

CREATE PROCEDURE p01_discount(IN consume NUMERIC(5,2),OUT payfee NUMERIC(5,2)) //声明存储过程,in输入参数 out输出参数

BEGIN

​ --判断收费方式

​ IF(consume>100.00AND consume<=300.00) THEN

​ SET payfee=consume*0.8;

​ ELSEIF(consume>300.00) THEN

​ SET payfee=consume*0.6;

​ ELSE

​ SET payfee = consume;

​ END IF;

​ SELECT payfee AS result;

END ;

– 调用存储过程

CALL p01_discount(100.0,@discount);
视图
视图本身是一张虚拟表,不存放任何数据。在使用SQL语句访问视图的时候,获取的数据是MySQL从其它表中生成的,视图和表在同一个命名空间(因为表和视图共享数据库中相同的名称空间,因此,数据库不能包含具有相同名称的表和视图)。视图查询数据相对安全,视图可以隐藏一些数据和结构,只让用户看见权限内的数据,使复杂的查询易于理解和使用。

原来我们公司做过一个项目的时候,用的是5张表的联查,然后用sql语句来写的话,比较慢,比较麻烦,然后我们把这5张表的联查创建了一个视图,然后就直接查找的是视图,查询速度快,这个视图就是只能做查询,而不能做增删改操作

基本语法,了解熟悉一下

– 创建视图

CREATE OR REPLACE VIEW user_order_view AS

SELECT

​ t1.id,t1.user_name,t2.order_no,t2.good_id,

​ t2.good_name,t2.num,t2.total_price

FROM v01_user t1

LEFT JOIN v02_order t2 ON t2.user_id =t1.id;

– 视图调用

SELECT * FROM user_order_view WHERE user_name=‘Cicada’;

13、where和having的区别

这两个都是添加查询条件用的。where的话就是拼接普通字段的查询条件,having后边跟上聚合之后数据的查询条件。

比如计算平均薪资在10k以上的部门信息,这会儿的话就要用select xx from table group by deptId having avg(salary)>10000

常用的聚合函数有:count、sum、avg、min、max

14、数据库三范式介绍一下

第一范式,原子性,列或者字段不能再分

第二范式的话要满足第一范式,并且不可以把多种数据保存在同一张表中,即一张表只能保存一类数据,否则可能导致插入数据异常。

第三范式,直接性,不存在传递依赖,他要在满足第二范式的条件上,在每一列都和主键直接相关,而不能间接相关。

15、select语句的执行顺序

  1. FROM 子句:首先确定数据源(表或视图),包括表连接(JOIN)操作。如果有多个表进行连接,MySQL 会确定连接的顺序。

    FROM table1
    LEFT JOIN table2 ON table1.id = table2.id
    
  2. WHERE 子句:对数据源中的数据进行过滤,排除不满足条件的行。

    WHERE table1.status = 'active'
    
  3. GROUP BY 子句:将数据分组,为每个分组计算聚合函数。分组操作通常是在过滤之后进行的。

    GROUP BY table1.category
    
  4. HAVING 子句:对分组后的数据进行过滤,排除不满足条件的分组。HAVING 子句通常用于对聚合结果进行过滤。

    HAVING COUNT(table1.id) > 1
    
  5. SELECT 子句:选择所需的列,包括计算表达式和聚合函数。这一步生成最终的结果集。

    SELECT table1.category, COUNT(table1.id) AS total
    
  6. DISTINCT 子句:去除结果集中的重复行。DISTINCT 子句应用于 SELECT 子句的结果。

    SELECT DISTINCT table1.category
    
  7. ORDER BY 子句:对结果集进行排序。排序可以基于一列或多列,按照升序(ASC)或降序(DESC)排序。

    ORDER BY total DESC
    
  8. LIMIT 子句:限制返回的行数。这是执行计划的最后一步,应用于已经排序的结果集。

    LIMIT 10
    

综合示例

SELECT DISTINCT table1.category, COUNT(table1.id) AS total
FROM table1
LEFT JOIN table2 ON table1.id = table2.id
WHERE table1.status = 'active'
GROUP BY table1.category
HAVING COUNT(table1.id) > 1
ORDER BY total DESC
LIMIT 10;

执行顺序总结

  1. FROM:确定数据源及连接。
  2. WHERE:过滤数据源中的行。
  3. GROUP BY:分组数据。
  4. HAVING:过滤分组后的数据。
  5. SELECT:选择所需的列和计算表达式。
  6. DISTINCT:去重。
  7. ORDER BY:排序结果。
  8. LIMIT:限制返回的行数。

16、mysql分库分表介绍下

分库分表的话,是解决MySQL数据量多了之后,单表单库存储量多了之后查询效率低下等问题的,主要分为两种方式,一个是水平拆分,另一个是垂直拆分

垂直拆分的话就是单个表中比如30个字段,拆分为两个表,一个表20个字段,一个表10个字段这样,或者按照其他方式拆分成3个表,这样的拆分原则呢就是将大字段或者不经常修改的或者经常查询的字段拆分出来,作为单独的表存储,然后跟主表一对一的关系存储,这样的话水平扩展了表,并且对功能也做了分离,高并发场景下,垂直拆分一定程度的提升IO性能,不过依然存在单表数据量过大的问题

水平拆分的话就是按照数据量来拆分,比如我们的表里,每个表最多存储200W条数据,然后每个表命名方式为user_0001、user_0002的方式,在查询的时候,用逻辑代码来控制数据查询。这样的话不存在单表单库数据量过大、高并发的性能瓶颈,提升系统稳定性和负载能力。不过水平拆分会导致跨分片的事务一致性难以保证,跨库的join关联查询性能较差,要根据具体的业务来判断具体适用那种分表方式

我们都是结合读写分离和mysql集群做的,读写分离以及集群的话,读写分离话保证了数据的安全性,集群的话其实就相当于水平拆分。这个我们项目中使用MyCat来做的,在mycat里配置好主库和从库,做增删改的时候是对主库进行操作,查询的时候是对从库进行操作,其实mysql本身从5.6以后的版本就带主从复制的功能了,他们是利用mysql里的log文件进行的数据同步

17、各种索引

创建索引:

  1. 使用 CREATE INDEX 语句创建索引
    普通索引用于加速查询,不强制唯一性约束。
CREATE INDEX index_name ON table_name(column_name);

示例:

CREATE INDEX idx_last_name ON employees(last_name);

唯一索引确保索引列的值是唯一的,不允许重复值。

CREATE UNIQUE INDEX index_name ON table_name(column_name);

复合索引在多个列上创建索引,可以加速涉及多个列的查询。

CREATE INDEX index_name ON table_name(column1, column2);

示例:

CREATE INDEX idx_last_first_name ON employees(last_name, first_name);
``
2. 在创建表时创建索引
#### 创建普通索引
```sql
CREATE TABLE employees (
    emp_id INT PRIMARY KEY,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    email VARCHAR(100),
    INDEX idx_last_name (last_name)
);

创建唯一索引

CREATE TABLE employees (
    emp_id INT PRIMARY KEY,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    email VARCHAR(100),
    UNIQUE INDEX idx_email (email)
);

创建复合索引

CREATE TABLE employees (
    emp_id INT PRIMARY KEY,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    email VARCHAR(100),
    INDEX idx_last_first_name (last_name, first_name)
);
  1. 通过 ALTER TABLE 添加索引
    添加普通索引
ALTER TABLE table_name ADD INDEX index_name (column_name);

添加唯一索引

ALTER TABLE table_name ADD UNIQUE INDEX index_name (column_name);

添加复合索引

ALTER TABLE table_name ADD INDEX index_name (column1, column2);
  1. 创建全文索引

全文索引用于全文检索,可以在 CHAR, VARCHAR, TEXT 类型的列上创建。

在创建表时创建全文索引

CREATE TABLE articles (
    id INT PRIMARY KEY,
    title VARCHAR(255),
    body TEXT,
    FULLTEXT (title, body)
);

使用 ALTER TABLE 添加全文索引

ALTER TABLE articles ADD FULLTEXT (title, body);

聚簇索引:在InnoDB里,索引B+Tree的叶子结点存储了整行数据的是主键索引,也被称之为聚簇索引,即将数据存储和索引放到了一块,找到了索引也就找到了数据。
非聚簇索引:索引B+tree的叶子结点存储了主键的值是非主键索引,就是非聚簇索引,二级索引。
区别:
非聚簇索引页字结点不存储表中的数据,而是存储该列对应的主键(行号);
非聚簇索引想要查找数据还需要根据主键再去聚簇索引中进行查找(回表)。第一次索引一般是顺序IO,回表的操作属于随机IO。需要回表的次数越多,随机IO次数越多,我们就越倾向于使用全表扫描;
通常情况下,聚簇索引查询只会查一次,而非聚簇索引需要回表查询多次,当然,如果覆盖索引(如果一个索引包含所有需要查询的字段的值,即需要查询的字段正好是索引的字段,那么直接根据该索引,就可以查到数据了,就无须回表查询)的话,查询一次即可;
注意:Myisam无论主键索引还是二级索引,都是非聚簇索引,而INNODB的主键索引是聚簇索引,二级索引是非聚簇索引,我们自己建的索引基本都是非聚簇索引。
联合索引:多个字段创建索引,就是联合索引,也叫 组合索引或复合索引。最左前缀匹配原则指的是,在使⽤联合索引时,MySQL 会根据联合索引中的字段顺序,从左到右依次到查询条件中去匹配,如果查询条件中存在与联合索引中最左侧字段相匹配的字段,则就会使⽤该字段过滤⼀批数据,直⾄联合索引中全部
字段匹配完成,或者在执⾏过程中遇到范围查询,如 > 、 < 、 between 和 以%开头的like查询 等条件,才会停⽌匹配。
前缀索引索引字段非常长,既占内存空间,也不利于维护,索所以我们就想,如果只把很长字段的前面的公共部分作为一个索引,就会产生超级加倍的效果,但是,我们需要注意,order by不支持前缀索引
索引下推是 MySQL 5.6 引入的一项优化技术,用于提高使用二级索引进行查询的效率。通过将部分 WHERE 条件下推到存储引擎层进行过滤,可以减少从存储引擎返回的数据量,从而提高查询性能。
索引下推的工作原理:在没有索引下推的情况下,当使用二级索引查询时,MySQL 会读取索引中的记录,然后回表(访问数据行)进行进一步的过滤。这意味着即使索引已经过滤掉了一部分数据,MySQL 还是会访问所有符合索引条件的数据行来进行后续的过滤。
启用索引下推后,MySQL 会将部分 WHERE 条件下推到存储引擎层,这样存储引擎在扫描索引时就可以直接过滤掉不满足条件的记录,减少回表的次数,从而提高查询效率。
假设有一个表 employees,结构如下:

CREATE TABLE employees (
    emp_id INT PRIMARY KEY,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    email VARCHAR(100),
    department_id INT,
    salary DECIMAL(10, 2),
    INDEX idx_last_name_salary (last_name, salary)
);

有这样一个查询:

SELECT * FROM employees WHERE last_name LIKE 'Smith%' AND salary > 50000;

在没有索引下推的情况下,查询执行流程如下:

  1. MySQL 读取索引 idx_last_name_salarylast_name LIKE 'Smith%' 的所有记录。
  2. 对于每一条符合条件的索引记录,回表读取数据行。
  3. 在存储引擎层之外进行 salary > 50000 的过滤。
    在启用了索引下推的情况下,查询执行流程如下:
  4. MySQL 读取索引 idx_last_name_salarylast_name LIKE 'Smith%' 的所有记录。
  5. 在存储引擎层过滤掉 salary <= 50000 的记录。
  6. 对于符合条件的记录进行回表操作。
    这样可以显著减少回表操作的次数,从而提高查询性能。
    启用索引下推:MySQL 默认启用索引下推。可以通过以下方式验证是否启用了索引下推:
EXPLAIN SELECT * FROM employees WHERE last_name LIKE 'Smith%' AND salary > 50000;

EXPLAIN 输出中,如果 Extra 列包含 “Using index condition”,则表示索引下推已启用。

假设你有一个数据集和上述表结构,可以通过以下方式验证索引下推:

-- 创建示例表
CREATE TABLE employees (
    emp_id INT PRIMARY KEY,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    email VARCHAR(100),
    department_id INT,
    salary DECIMAL(10, 2),
    INDEX idx_last_name_salary (last_name, salary)
);

-- 插入示例数据
INSERT INTO employees (emp_id, first_name, last_name, email, department_id, salary) VALUES
(1, 'John', 'Smith', 'john.smith@example.com', 1, 60000),
(2, 'Jane', 'Doe', 'jane.doe@example.com', 2, 40000),
(3, 'Jim', 'Beam', 'jim.beam@example.com', 1, 55000),
(4, 'Jack', 'Daniels', 'jack.daniels@example.com', 3, 70000),
(5, 'Joe', 'Smith', 'joe.smith@example.com', 1, 50000);

-- 执行查询并查看执行计划
EXPLAIN SELECT * FROM employees WHERE last_name LIKE 'Smith%' AND salary > 50000;

EXPLAIN 结果中,你应该能看到 “Using index condition”。

18、mysql中char和varchar的区别

char是一个定长字段,假如申请了char(10)的空间,那么无论实际存储多少内容,该字段都占用10字符,而varchar是变长的,也就是说申请的只是最大长度,占用的空间为实际字符长度+1,最后一个字符存储使用了多长时间,在检索效率上来讲,char>varchar,因此在使用中,如果确定某个字段的值的长度,使用char,否则应该尽量使用varchar,例如存储用户MD5加密后的密码,则应该使用char。

19、mysql执行查询过程

1、客户端通过TCP连接发送连接请求到mysql连接器,连接器会对该请求进行权限验证以及连接资源分配
2、查缓存。当判断缓存是否命中时,mysql不会进行解析查询语句,而是直接使用sql语句和客户端发送过来的其他原始信息。所以,任何字符上的不同,例如空格、注解等都会导致缓存的不命中。
3、语法分析,sql语法是否写错了,如何把语句给到预处理器,检查数据表和数据列是否存在,解析别名看是否存在歧义。
4、优化。是否使用索引,生成执行计划。
5、交给执行器,将数据保存到结果集中,同时会逐步将数据缓存到查询缓存中,最终将结果集返回给客户端。
更新语句执行会复杂一些。需要检查表是否有排它锁,写binlog,刷盘,是否执行commit。

20、事务

要么全部执⾏成功,要么全部不执⾏。

1.ACID

  1. 原⼦性( Atomicity ) : 事务是最⼩的执⾏单位,不允许分割。事务的原⼦性确保动作要么全部完成,要么完全不起作⽤;
  2. ⼀致性( Consistency ): 执⾏事务前后,数据保持⼀致,例如转账业务中,⽆论事务是否成功,转账者和收款⼈的总额应该是不变的;
  3. 隔离性( Isolation ): 并发访问数据库时,⼀个⽤户的事务不被其他事务所⼲扰,各并发事务之间数据库是独⽴的;
  4. 持久性( Durabilily ): ⼀个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发⽣故障也不应该对其有任何影响。
    只有保证了事务的持久性、原⼦性、隔离性之后,⼀致性才能得到保障。也就是说 A、I、D 是⼿段,C是⽬的。

2.事务带来的问题

1.脏读(Dirty read): 当⼀个事务正在访问数据并且对数据进⾏了修改,⽽这种修改还没有提交到数据库中,这时另外⼀个事务也访问了这个数据,然后使⽤了这个数据。
2.不可重复读(Unrepeatable read): 指在⼀个事务内多次读同⼀数据。在这个事务还没有结束时,另⼀个事务也访问该数据,发⽣了在⼀个事务内两次读到的数据是不⼀样的情况
3.幻读(Phantom read): 在⼀个事务内多次读取的数量不⼀致,在于记录新增⽐如多次执⾏同⼀条查询语句(DQL)时,发现查到的记录增加了
不可重复读侧重于修改,幻读侧重于新增或删除(多了或少量行),脏读是一个事务回滚影响另外一个事务。

3.事务的隔离级别

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

4.Mysql中的锁

MySQL InnoDB ⽀持三种⾏锁定⽅式:
记录锁(Record Lock) :也被称为记录锁,属于单个⾏记录上的锁。
间隙锁(Gap Lock) :锁定⼀个范围,不包括记录本身。
临键锁(Next-key Lock) :RecordLock+Gap Lock,锁定⼀个范围,包含记录本身。
记录锁只能锁住已经存在的记录,为了避免插⼊新记录,需要依赖间隙锁。
InnoDB 的默认隔离级别 RR(可重读)是可以解决幻读问题发⽣的,主要有下⾯两种情况:
快照读(⼀致性⾮锁定读) :由 MVCC 机制来保证不出现幻读。
当前读 (⼀致性锁定读): 使⽤ Next-Key Lock 进⾏加锁来保证不出现幻读。
MVCC就是多版本并发控制,实现了【读-写冲突不加锁】,【⾮阻塞并发读】
MVCC只针对读已提交和可重复读,如果是读未提交,每次都是当前读
共享锁(S 锁) :⼜称读锁,事务在读取记录的时候获取共享锁,允许多个事务同时获取
(锁兼容)。
排他锁(X 锁) :⼜称写锁/独占锁,事务在修改记录的时候获取排他锁,不允许多个事务同时获取。如果⼀个记录已经被加了排他锁,那其他事务不能再对这条事务加任何类型的锁
(锁不兼容)。

5、事务的实现原理

事务是基于重做日志文件(redo log)和回滚日志(undo log)实现的。每提交一个事务必须先将该事务的所有日志写入到重做日志文件进行持久化,数据库就可以通过重做日志来保证事务的原子性和持久性。每当有修改事务时,还会产生undo log,如果需要回滚,则根据undo log的反向语句进行逻辑操作,比如insert一条记录就delete一条记录。undo log主要实现数据的一致性。
undo log指事务开始之前,在操作任何数据之前,首先将需操作的数据备份到一个地方。
redo log指事务中操作的任何数据,将最新的数据备份到一个地方。
binlog
在这里插入图片描述

6、MVCC

通过保存数据在某个时间点的快照来实现的。根据事务开始的时间不同,每个事务对同一张表,同一时刻看到的数据可能是不一样的。
实现的原理:
InnoDB每一行数据都有一个隐藏的回滚指针,用于指向该行修改前的最后一个历史版本,这个历史版本存放在undolog中。如果要执行更新操作,会将原纪录放入undo log中,并通过隐藏的回滚指针指向undo log中的原纪录。其他事务此时需要查询时,就是查询undo log中这行数据的最后一个历史版本。最大的好处是读不加锁,读写不冲突,极大增加了mysql的并发性。通过mvcc,保证了事务ACID中的隔离性。

21、分库分表

1,水平分库,将一个库的数据拆分到多个库中,解决海量数据存储和高并发的问题
2,水平分表,将一个表的数据拆分到多个表中(可以在同一个库内)。解决单表存储和性能的问题
3,垂直分库,根据业务进行拆分,高并发下提高磁盘IO和网络连接数
4,垂直分表,以字段为依据,根据字段属性将不同字段拆分到不同表中。冷热数据分离,多表互不影响
分库之后的问题:
分布式事务一致性问题
跨节点关联查询
跨节点分页、排序函数
主键避重

22、UUID和自增ID哪个做主键好?

UUID

一个128位长的唯一标识符,通常以字符串形式表示。它可以使用不同的算法生成,比如基于时间戳的UUID和随机数生成的UUDID等;他的优点是:全局唯一:使用不同的算法生成,几乎可以保证在全球范围内唯一,避免了多台机器之间主键冲突的问题。
不可预测性:随机生成的 UUID 很难被猜测出来,对于需要保密性的应用场景较为适用。
。分布式:由于可以在不同的机器上生成 UUID,因此可以用于分布式系统中。
UUID当做主键ID的话的缺点同样也有,如:
存储空间比较大:UUID 通常以字符串形式存储,占用的存储空间比较大.不适合范围查询:因为不是自增的,所以在做范围查询的时候是不支持的。(后插入的UUID在排序时可能比前面的要小,在做范围查询的时候可能会出现数据重复或者漏数据的情况)
不方便展示:主键ID有的时候会需要在系统间、或者前台页面展示,如果是UUID的话,就因为比较长、并且没有任何业务含义,所以不方便展示。
查询效率低:。
在UUID列上创建索引,因为他很长,所以索引的大小会变得非常大。大的索引(会占用更多的磁盘空间,导致缓存命中率下降,进而增加了磁盘I/0的需求。此外,大的索引还会导致查询时的内存开销增加。
当使用UUID进行排序时,新的UUID值通常会插入到叶子节点的中间位置。这可能导致B+树的分裂和平衡操作频繁进行,从而增加了写入的开销。每次分裂或平衡都涉及到数据的重新排序和移动,这会影响查询的性能。

自增ID

在 MySQL 中,可以通过设置 AUTO_INCREMENT 属性实现ID的自增长,通常可以用来作为主键ID。
使用自增ID做主键的好处是:
存储空间:ID是数字,所以占用的位数要比UUID小多了,所以在存储空间上也节省很多。
查询效率:ID 是递增的,因此在使用 B+Tree 索引时,查询效率较高、。
方便展示:因为ID比较短,方便展示。
分页方便:因为ID是连续自增的,所以在分页的时候,可以通过ID解决深度分页的问题。
但是,使用自增主键做主键ID也存在一定的问题
分库分表:当我们做分库分表的时候,就没办法依赖一张表的自增主键来做主键ID了,这样就会发生重复导致冲突的问题
可预测:因为ID是顺序自增的,所以是可以预测的,这就给系统带来了一定的安全。
风险。
可能用尽:自增id的话可能是int、bigint等,但是他们都是有范围的,有可能会用。
自增 ID 适用场景:
• 单一数据库的中小型应用。
• 不需要频繁进行数据迁移和合并的系统。
• 对安全性和数据泄漏不敏感的应用。
UUID 适用场景:
• 分布式系统和微服务架构。
• 需要高安全性和避免数据泄漏的应用。
• 需要频繁进行数据迁移和合并的系统。

23、mysql和oracle的区别

1、本质的区别
Oracle数据库是一个=对象关系数据库管理系统(ORDBMS)。它通常被称为Oracle RDBMS或简称为Oracle,是一个收费的数据库。

MySQL是一个开源的关系数据库管理系统(RDBMS)。它是世界上使用最多的RDBMS,作为服务器运行,提供对多个数据库的多用户访问。它是一个开源、免费的数据库。

2、Oracle数据库产品是闭源同时也是收费的,MySQL是开源的项目(免费);

3、Oracle是大型数据库,Mysql是中小型数据库;

4、Oracle可以设置用户权限、访问权限、读写权限等,MySQL没有;

5、Oracle有表空间的概念,MySQL没有;

6、Oracle默认不自动提交,需要用户手动提交。Mysql默认是自动提交。

7、Oracle逻辑备份时不锁定数据,且备份的数据是一致的。Mysql逻辑备份时要锁定数据,才能保证备份的数据是一致的,影响业务正常使用。

8、Oracle有各种成熟的性能诊断调优工具,能实现很多自动分析、诊断功能。比如awr、addm、sqltrace、tkproof等;Mysql的诊断调优方法较少,主要有慢查询日志。

9、Oracle容量无限,根据配置决定;而MySQL使用MyISAM存储引擎,最大表尺寸为65536TB。 MySQL数据库的最大有效表尺寸通常是由操作系统对文件大小的限制决定的,而不是由MySQL内部限制决定。

10、Oracle在Linux下的性能,在少量数据时速度低于MySQL,在千万级时速度快于MySQL。

11、Oracle全面,完整,稳定,但一般数据量大,对硬件要求较高 ;而MySQL使用CPU和内存极少,性能很高,但扩展性较差。

12、MySQL处理翻页的SQL语句比较简单,用LIMIT 开始位置, 记录个数。Oracle处理翻页的SQL语句就比较繁琐了。每个结果集只有一个ROWNUM字段标明它的位置, 并且只能用ROWNUM80。

13、MySQL日期字段分DATE和TIME两种,Oracle日期字段只有DATE,包含年月日时分秒信息,用当前数据库的系统时间为SYSDATE, 精确到秒。

14、SQL语句的区别:

mysql可以没有from,oracle必须有,可以写成from dual;

mysql使用concat()函数连接字符串,oracle不仅有concat()函数,还可以使用||;

mysql没有全外连接,使用集合连接代替,oracle有全外连接,而且左右外连接有自己的语法:(+);

mysql分页使用limit,oracle分页得借助rownum关键字;

mysql自动增长auto_increment,oracle使用序列代替;

mysql直接书写循环判断语句,oracle得借助PLSQL语句;

mysql判断使用elseif,oracle使用elsif;

mysql可以直接增删改,oracle需要commit;

group by,在下oracle下用group by的话,group by后面的字段必须在select后面出现,不然会报错的,而mysql却不会;

24、sql优化

在这里插入图片描述
SQL优化参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值