目录
什么情况不可以执行insert、update和delete操作?
Innodb:
mysql默认存储引擎,支持事务,支持行级锁、支持外键、不支持全文索引。
聚集索引,所有数据都保存在一个表里面。支持在线热备份
获取总数据量需要扫描全表。
Myisam:
不支持事务、不支持行级锁,只能对整张表加锁。
支持压缩表和空间数据索引。
保存了数据的总行数
innodb |
Myisam |
支持事务、行锁,表锁,页面锁 |
不支持事务、只支持表锁 |
所有数据都保存在一个表中,没有保存表数据的行数 |
数据分三个文件保存在磁盘上、保存了整个表的行数 |
聚集索引、有自己的缓存,支持在线热备份 |
非聚集索引、不支持在线热备份 |
聚簇索引:数据和索引在一起存储的索引方式叫做聚簇索引,一张表只能有一个聚簇索引。
热备份:不需要关闭mysql服务,备份的同时,不影响业务。
冷备份:需要关mysql服务,读写请求均不允许的状态下进行。
作用:加快数据库数据的检索速度
优势:
劣势:
索引会占据磁盘空间
(降低更新速率)索引虽然会提高查询效率,但是会降低更新表的效率。比如每次对表进行增删改操作,MySQL不仅要保存数据,还有保存或者更新对应的索引文件。
(1)磁盘 IO 次数
最大化的减少数据库的磁盘IO次数。
索引使用B+树结构。
B+树分为叶子节点和非叶子节点。非叶子节点不存储数据,只存储主键和指针,数据都存在叶子节点。
并且非叶子节点中的 key 都按照从小到大的顺序排列(左小右大)。叶子节点也是按照从小
到大排列的,每个叶子节点都存有相邻叶子节点的指针。(支持范围查找)
相对于B树来说,B+树因为没有存储全量数据,所以一页能存储的数据量就更多,同样多
的数据,树高可能更低,磁盘IO次数也就更少。
(2)磁盘预读特性
innodb最小储存单元是页(一个磁盘块),磁盘往往不是严格按需读取,而是每次都会预读。
预读过程中,磁盘进行顺序读取,顺序读取不需要进行磁盘寻道。每次会读取页的整数倍。
联合索引,最左优先,以最左边的为起点任何连续的索引都能匹配上。
最左匹配原则是针对联合索引来说的,假设建了一个索引 index(A,B,C),
查询条件使用
A = 1 ,C=1 ,B=1 或
A = 1 ,B=1,C=1 或
A = 1 ,B=1 或
A = 1,C=1 又或者
A = 1, index(A,B,C)都会生效
但如果是使用 B=1,C=1 或 B=1 或C=1 索引都不会起作用
可以建表玩一下:
- CREATE TABLE staffs(
- id INT PRIMARY KEY AUTO_INCREMENT,
- `name` VARCHAR(24) NOT NULL DEFAULT'' COMMENT'姓名',
- `age` INT NOT NULL DEFAULT 0 COMMENT'年龄',
- `pos` VARCHAR(20) NOT NULL DEFAULT'' COMMENT'职位',
- `add_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT'入职时间'
- )CHARSET utf8 COMMENT'员工记录表';
-
- INSERT INTO staffs(`name`,`age`,`pos`,`add_time`) VALUES('z3',22,'manager',NOW());
- INSERT INTO staffs(`name`,`age`,`pos`,`add_time`) VALUES('July',23,'dev',NOW());
- INSERT INTO staffs(`name`,`age`,`pos`,`add_time`) VALUES('2000',23,'dev',NOW());
- #联合索引
- ALTER TABLE staffs ADD INDEX index_staffs_nameAgePos(name,age,pos);
-
- explain select * from staffs where name='z3'
- explain select * from staffs where name='z3'and age=22 and pos='manager';
- explain select * from staffs where name='z3' and pos='manager' and age=22;
- explain select * from staffs where pos='manager' and age=22;
走了两遍索引----举例:有一个主键索引,一个普通索引,当在普通索引字段上使用select*。先根据普通索引找到主键id,再根据主键id去主键索引中找到对应行的全量数据。普通索引,没有全量数据。
避免回表:使用覆盖索引
不使用Select* 使用Select ID ,然后ID对应的是索引字段。覆盖索引可以减少树的搜索次数,提升性能。
MVCC 是多版本并发控制,在很多情况下避免加锁,⼤都实现了⾮阻塞的读操作,写操作也只锁定必要 的⾏。
通过在每⾏记录后⾯保存两个隐藏的列来实现。创建时间版本号,过期(删除)时间版本号,每开始一个新的事务,版本号都会自动递增。
MVCC 只能在已提交读 和 可重复读 两个隔离级别下⼯作,因为 未提交读总是读取最新的数据⾏,⽽不是符合当前事务版本的数据⾏。⽽ SERIALIZABLE 则会对所有读取的⾏都加锁
MVCC的原理是查找创建版本小于或等于当前事务版本,删除版本为空或大于当前事务版本
假设表里面两条数据如下:
id |
name |
创建版本号 |
删除版本号 |
1 |
一一 |
1 |
|
2 |
二二 |
2 |
|
三个事务:
A:查询id小于3的数据,创建版本号3,删除版本号空
B:修改id为1的数据name--->王八,创建版本号4,删除版本号空
C:删除id为2的数据,删除版本号5。
A查询到的数据还是上表中的数据。
id |
name |
创建版本号 |
删除版本号 |
1 |
一一 |
1 |
|
2 |
二二 |
2 |
|
1 |
王八 |
4 |
|
2 |
二二 |
2 |
5 |
(1)原子性:(undo log)
事务被视为不可分割的最小单元,事务的所有操作要么全部成功,要么全部失败回滚。
实现原理:利用innodb的undo log,undo log 记录的反向sql逻辑。
(2)一致性:
数据库在事务执行前后都保持一致性状态,在一致性状态下,所有事务对一个数据的读取结果都是相同的
实现原理:
数据库层面:通过原子性、隔离性、持久性来保证一致性。一致性是目的,其他是手段。
应用层面:通过代码判断数据库数据是否有效,然后决定回滚还是提交。
(3)隔离性:(锁和MVCC机制)
事务之间互不影响,事务所做的修改在提交前,对其他事务是不可见的。
实现原理:利用的是锁和MVCC机制
(4)持久性:(redo log)
事务一旦提交,其所做的修改就是永久有效,即使是数据库宕机,事务执行的结果也不能丢。
实现原理:
利用innodb的redo log 日志文件,这文件记录了数据库表结构和表数据的物理变化。
数据进行修改时,不仅会在内存进行修改,还会在redo log 中记录这次操作。redo log ,也会
刷到磁盘上,但是是顺序IO速度快,且体积小。当数据库宕机时,会将redo log中的内容恢复到数
据库中,再根据undo log和binlog内容决定回滚数据还是提交数据。
undo log、 binlog、 redo log
(1)binlog
binlog记录了数据库表数据和表结构的变更的日志文件。
存储着每条变更的SQL语句等。用来复制和恢复数据。
(2)redo log
redo log 也是记录了数据库表数据和表结构的变更的日志文件。
不过记录的是物理变化,文件小,恢复速度快。
redo log 要写磁盘,但是redo log是顺序IO(比随机IO快很多)写入速度快。
(3)binlog与redo log 的区别
(4)undo log
主要有两个作用:回滚和多版本控制(MVCC)
主要存储的也是逻辑日志,反向逻辑。
|
bin log |
redo log |
undo log |
存储内容 |
存sql逻辑 |
物理变化 |
反向sql |
作用 |
复制+恢复(原子性) |
持久化(持久性) |
回滚+多版本控制(原子性) |
隔离级别 |
脏读 |
不可重复读 |
幻影读 |
未提交读 |
√ |
√ |
√ |
提交读 |
× |
√ |
√ |
可重复读 |
× |
× |
√ |
可串行化 |
× |
× |
× |
(1)未提交读
事务中的修改,即使没有提交,对其他事务也是可见的。
会存在脏读,不可重复度,幻读问题。
(2)已提交读
事务只能读取已经提交的事务所做的修改。也就是未提交前,事务做的修改对其他事务不可见。
会存在不可重复度,幻读问题。
(3)可重复读
保证在同一个事务中多次读取同样数据的结果是一样的。
会存在幻读问题。
(4)串行化读
强制事务串行执行。需要加锁实现。
实际运用中,按业务场景需求来,隔离级别越低,事务并发性能越高。mysql默认可重复读。
(1)脏读:(读取到的数据与数据库数据值不一致)事务A读取了事务B未提交的修改数据,事务B随时可能回滚。
(2)不可重复读取:同一个事务,多次读取同一个数据,值都不同。
事务A 读取数据值为2,此时事务B修改数据值为5并提交,事务A再一次读取数据,值为5。事务A前后两次读取的值并不相同。
(3)幻读:事务A获取全表数据为10条,此时事务B新增/删除一条数据,事务A再一次获取全表数据为11/9条,就好像出现幻觉一样。
不可重复读重点在于其他事务修改数据并提交了:值不同
幻读的重点在于其他事务新增或者删除数据并提交了:数据量不同了
多个事务同时更新同一个数据,后更新的事务把前面事务更新的结果覆盖了,导致丢失更新。
现在数据库当一个事务更新一条记录时,就会加排他锁,另外一个的更新就会阻塞住。所以数据库本身并没有丢失更新的问题。通常都是由于程序产生的。可以通过乐观锁的方式来解决这个问题。
对于开发者,优化在于【开发规范】【数据库索引】【慢查询(慢sql)处理】。
从查询来说:
--走索引,理论上来说,数据达到一定数据量,就应该建索引。
能否使用覆盖索引,减少回表。
是否建立联合索引,区分度高的放在左边,并考虑最左匹配原则
尽量避免索引失效的操作,比如使用函数操作或者表达式计算
通过explain命令查看,sql是否走索引,走什么索引。
走了索引仍然查询缓慢:
1、考虑删除旧数据,能删数据的业务很少很少,所以一般都不是删除数据。
2、加缓存,能接受非真正实时数据,查询条件简单,如果查询条件相对复杂且多变不建议使用
3、如果有字符串检索的场景导致查询低效,考虑将数据导入es类搜索引擎
Mysql-->es需要对应的同步程序(监听binlog,解析binlog导入es)
参考博客https://blog.csdn.net/ByteDanceTech/article/details/125795764?spm=1000.2115.3001.5927
数据在缓存还是磁盘,是否通过全局索引快速寻址
排序、子查询、聚合、关联等,一般要先把数据取到临时表中,再对数据进行加工。
对于数据量比较多的计算,会消耗大量计算节点的 CPU 资源,让数据加工变得更加缓慢。
是否选择了合适的 join 方式
减少数据量扫描。尽量在查询中加入一些可以提前过滤数据的条件。
减少交互次数(减少网络传输):将数据存放在更快的地方(redis,es等)
减少服务器 CPU 开销(减少 CPU 及内存开销)
避免大事务操作
增加资源
只含数值信息的字段,尽量不设置为字符串。引擎在处理查询和连接时逐个比较字符串中的每个字符,数字型只需比对一次。
vachar是可变长度的,char是固定大小的。
提高 GROUP BY 语句的效率, 将不需要的记录在 GROUP BY 之前过滤掉
(原sql)select class , avg(age) from student group by class having job = 'class';
(优化)select class , avg(age) from student where job = 'class' group by class;
查看查询语句的执行计划,是查询性能优化的重要工具
详情见下面文章
数据库--explain的使用_上房揭瓦ing的博客-CSDN博客
现象:接口响应时间超长,耗时几十秒才返回错误提示,后台日志中出现Lock wait.....
原因:锁等待超过了innodb_lock_wait_timeout(默认是50s)设置的时间,所以报错
场景:
(1)同一个事务内先后对同一数据进行插入和更新。
(2)多台服务器操作同一数据库
(3)短时间内出现高并发现象,spring事务造成数据库死锁,后续操作超时抛出异常
(4)两个事务同时更新、删除,事务等待另一个事务释放锁。
排查:
- # 查看当前被锁的表
- show OPEN TABLES where In_use > 0;
- #查看数据库当前进程,看有无正在执行的慢SQL记录线程。
- show processlist;
- #查看当前运行的事务
- SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
- #或
- select trx_state,trx_started,trx_mysql_thread_id,trx_query
- from information_schema.innodb_trx;
-
- #查询全局的自动提交是否开启:1表示开启
- show global variables like 'autocommit';
- select @@autocommit;
- #查询当前会话等待事务锁超时时间:
- SHOW VARIABLES LIKE 'innodb_lock_wait_timeout';
- #修改当前会话等待事务锁超时时间:
- SET innodb_lock_wait_timeout=10000;
解决
(1)治标
改大锁定等待时间,找到事务对应的线程kill掉
(2)治本
找到锁表的事务,分析锁表原因,进行优化
来源百度的一个提问下的答案
存储过程就是一组预先编译好的sql语句集
优点:
提高重用性,减少冗余;
减少了sql的编译次数,减少了与服务器连接交互的次数;
生产环境下,可通过直接修改存储过程的方式修改业务逻辑或bug,而不用重启服务器。
执行速度快,存储过程经过编译之后会比单独一条一条编译执行要快很多。
缺点:
过程化编程,复杂业务处理的维护成本高。
调试不便。
因为不同数据库语法不一致,不同数据库之间可移植性差。
- create procedure 存储过程名(in/out/inout参数列表)
- begin
- //....存储过程体
- end;
(1)空参数列表的存储过程
- #空参数列表的存储过程
- DELIMITER $$
- CREATE PROCEDURE allEmpList()
- BEGIN
- SELECT * from emp;
- END $$
- #调用
- call allEmpList()
(2)带 in的存储过程
- #示例
- DELIMITER $$
- CREATE PROCEDURE getEmpByEmpName (IN empName VARCHAR(255))
- BEGIN
- SELECT * FROM emp t LEFT JOIN dept t2 ON t.dept_id = t2.dept_id WHEREt.emp_name = empName ;
- END$$
-
- #调用
- call getEmpByEmpName('张三'
(3)带out的存储过程
- DELIMITER $$
- CREATE PROCEDURE getEmpNameByEmpId (
- IN empId INT,
- OUT empName VARCHAR (255)
- )
- BEGIN
- SELECT t.emp_name INTO empName FROM emp t WHERE t.emp_id = empId ;
- END$$
-
- #使用
- call getEmpNameByEmpId(1,@empName);
- select @empName as empName;
(4)带INOUT的存储过程
- DELIMITER $$
- CREATE PROCEDURE customSum (INOUT a INT, INOUT b INT)
- BEGIN
- SET a = a * 12 ;
- SET b = b * 12 ;
- END$$
-
- #使用
- set @a = 10;
- set @b = 11;
- call customSum(@a,@b);
- select @a,@b;
视图是虚拟表,不存储数据,存储的是sq
查询简单化,提高复杂SQL语句的复用性和表操作的安全性
重用SQL语句
简化复杂的SQL操作
使用表的组成部分而不是整个表
为了保护数据
创建:create view视图名 as select语句;
删除:drop view视图名;
修改:replace view 视图名 as select语句;
使用:select * from 视图名 [where 条件];
多表连接,包含distinct、聚合函数,group by、order by、union、union all、包含子查询等。
(1)存储过程是程序化的sql可以实现一般sql不能实现的功能。
如:先检索一个表得到一些数据,经过一定的编辑后更新到另外一个表中、这就可以用不带参数的存储过程实现。
(2)视图是虚拟表,不存储数据,存储的是sql,检索他的时候,实际上是执行定义它的sql语句。
触发器是用来响应激活或者触发数据库行为事件的存储程序。通常,触发器用来作为数据库操作语言的响应而被调用,触发器可以被用来作为数据校验和自动反向格式化。
1、数字函数:
ABS(x):绝对值
AVG(expression):平均值
MAX(expression):最大值
MIN(最小值)
2、字符串:
CONCAT(s1,s2…sn):合并成一个字符串
SUBSTR()字符串截取
REVERSE()颠倒顺序
3、日期函数:
DATE():提取日期值
DAY(d):提取日期部分
4、高级点的函数
IF(expr,v1,v2)如果表达式 expr 成立,返回结果 v1;否则,返回结果 v2
left(V1, V2):取字符串V1 前V2个字符
内连接:(交集)
inner join
外连接:(差集)
(1)左外连接 left join
(2)右外连接 right join
(3)全外连接 full join
交叉连接(并集)
union (去重)和 union all
常用代理方式来实现读写分离
主:写操作+实时性要求比较高的读操作
从:处理读操作。
缓解了锁的争用,增加冗余,提高可用性
主库提交事务时,把数据变更作为事件记录在binlog日志中
主库推送binlog到中继日志,从库根据中继日志进行数据变更
(主从架构和分库分表待补充)
使用的是xmin思维导图工具
网盘取思维导图文件
链接:https://pan.baidu.com/s/1jp6BKRML0oUGw4q-cbCODA
提取码:1234
链接:https://pan.baidu.com/s/1a1iGyqNieqk70xK8hmb0mw
提取码:1234