mysql有记录但是基于条件则无法查询_Mysql知识整理 - osc_r3mtqivi的个人空间 - OSCHINA - 中文开源技术交流社区...

一、乐观锁和悲观锁

1.悲观锁是指假设并发更新会发生冲突,不管冲突是否会发生,都会使用锁机制。

优点: 完全保证数据安全。

缺点:锁机制会有额外开销,并发度降低。 可能会产生死锁。

2. 乐观锁是指假设数据不会发生冲突,只在数据提交更新的时候,才会对数据是否冲突进行检测(通过版本号),如果发现冲突,则认为是过期数据。

优点: 没有锁机制的额外开销,并发高,不会出现死锁。

缺点:回滚重试性能孙损耗明显。

mysql底层update会自动施加写锁,不会在底层还支持并发更新,所以如果两个请求同时打进来要更新版本号,只有一个会成功,另一个则会由于等待写锁释放而失败,然后需要重新查询最新版本号去更新

二、Innodb的四种隔离级别,mysql的默认隔离级别是

首先要知道脏读、不可重复读、幻读的概念。

脏读:一个事务读取到另一个事务未提交的数据。

不可重复读:同一事务,多次读取同一数据,结果返回不同。也就是读取到了其他事务已提交的数据。 相反,可重复读也就是同一事物多次读取同一数据,结果返回都是一样的。

幻读:主要指的是,一个事务读取到了另一个事务新insert的数据。

四种隔离级别如下:

未提交读(Read uncommitted)   脏读、不可重复读、幻读。

已提交读(Read committed)  不可重复读、幻读。

可重复读(Repeatable read) 幻读。  --- mysql 默认的隔离级别。  但是mysql在此基础上,通过事务版本号的形式解决了可能会出现幻读的问题。mvcc 多版本并发控制

可串行化(SERIALIZABLE) 三种问题都不存在。

mvcc

2f27b516c965c19b068ce1fc7831aeac.png

三、事务的四种特性

事务是并发控制的基本单位,要么全执行,要么全不执行。

原子性、一致性、隔离性、持久性。

由undo log 实现原子性(回滚)

由redo log 实现一致性 (提交)

mysql更新的时候 会率先将更新前的内容和更新后的内容写到内存缓冲区中 (redo buffer 和 undo buffer)。 回滚和提交时候,由后台进程去异步读取buffer里的log。 但是如果遇到Mysql突然宕机,则需要使用更新之后生成的落到磁盘上的redo log 和 undo log进行数据持久化和一致性。

四、查找慢查询的sql方法以及优化方案

1. sql慢查询的查找方法:

a. 查看慢查询日志   这里有慢查询日志记录的开启方法  (I. set global slow_query_log=1; 只开启当前数据库的慢查询日志记录,重启Mysql失效。   II.set gloal long_query_time = 1 全局设置,但是对当前连接不生效。 如果需要对当前连接生效, 需要使用 set session_long_query_time = 1.0  III. 如果要永久生效,需要修改my.cnf配置 slow_query_log =1

slow_query_log_file=/var/lib/mysql/atguigu-slow.log  指定开启慢查询以及文件记录位置。)

b. set profiling = 1的情况下 使用show profile;   (只能对当前会话执行的sql进行分析)  再通过show profile + id的形式看每条慢的语句慢的原因。   新版本的mysql 用 performance schema

c. show status 可以看一些 操作记录的次数等 以及执行过的一些curd语句,可以理解为作为计数器。

d. show processlist  看Mysql连接线程的问题。

e. 单条sql的话,直接用explain 或者 desc + sql语句,看索引的使用情况,扫描行数等。

2.sql优化方案:

a.查询时,用对索引,减少大量无用的行数扫描。 以及所查即所需,尽量不要使用select * ,指定好使用的列,避免大量冗余数据扫描。以及大量重复查询,在应用层做一下缓存。

b.分解部分复杂的查询变成相关少量的多条, 可以提高缓存效率,单挑查询减少锁的竞争等。

c.特定类型相关优化,尽量不用子查询,用关联或者拆分代替,count(*),加*号会不扫描列,只扫描行。

ps: count(1) 和 count(*) 和 count(name) 的区别

count(1) 和 count(*) 无任何区别,因为()里的不是字段名 也非null。 如果count(null)  则直接等于0 不扫表了。

count(name) name是字段名,这样的话如果name字段为null的就不会计算在总数中。

五、sql具体索引相关优化

1.insert多次插入的时候选择批量插入。

(合并后日志量(MySQL的binlog和innodb的事务日志)减少了,降低日志刷盘的数据量和频率,从而提高效率。通过合并SQL语句,同时也能减少SQL语句解析的次数,减少网络传输的IO。)

2.%开头的Like无法使用索引。

3.数据类型隐式转换无法使用索引。int 转 string 这种

4.如果mysql使用索引时比全表扫描慢则不使用索引,扫描行数超过30%一般就会不用索引了。(也是避免了频繁的普通索引和聚集索引的切换)

5.大的文本或超长字段不要建索引。

6.垂直分表,水平分表相关,这时候一般可以考虑人为生成主键id,单要维持顺序。

7.避免null字段 原因如下:

(1)所有使用NULL值的情况,都可以通过一个有意义的值的表示,这样有利于代码的可读性和可维护性,并能从约束上增强业务数据的规范性。

(2)NULL值到非NULL的更新无法做到原地更新,更容易发生索引分裂,从而影响性能。(null -> not null性能提升很小,除非确定它带来了问题,否则不要当成优先的优化措施)

(3)NULL值在timestamp类型下容易出问题,特别是没有启用参数explicit_defaults_for_timestamp

(4)NOT IN、!= 等负向条件查询在有 NULL 值的情况下返回永远为空结果,查询容易出错

六、常用的索引类型

主键索引、唯一索引、普通索引、联合索引。

主键索引属于聚簇索引(也叫聚集索引),其他索引属于非聚簇索引。

聚簇索引在存储结构中存储了索引的id以及行记录(使用的是b+树的叶子节点。) 而其他索引存的是索引内容以及主键聚集索引的值,查的时候通过索引再结合主键索引指向的位置获取数据。

为什么主键一般自增,因为自增的话就不用去改变节点的结构,只需要在最后追加就行,不然就要不断调整数据的物理地址分页等,加大io损耗。

联合索引有个最左前缀原则 key idx_a_b_c(a,b,c);

查询 (abc) (ab) (a) (ac)都会直接用到索引时,explain出来的type为ref。 但是需要注意的是,查询ac的时候 Extra还会出现 using Where。 说明不仅使用了索引,还使用了where进行过滤。这个时候如果type为all之类的,则会有优化空间。   ref代表mysql会根据特定的算法快速查找到某个符合条件的索引。

查询 (b) (c) 时, explain 出来的type 为 index。 这种类型表示mysql也用到了索引。但是效率不高,是从第一个索引一直查找到最后一个索引,直到找到符合判断条件的索引才用。

七、分库分表分区

千万行级别的表才要拆。一般行数量级在500W以下是mysql性能最优的时候。

分库:主从复制,负载均衡。降低单数据库压力。

分表:垂直分表 水平分表

垂直分表:

将一个表结构的字段拆成多张表, 容易变更的一些字段(热数据)存在一张表,主更新,并且采用redis等加以缓存配置。不容易变更的一些字段(冷数据)存在另一张表,主查询,可以多配置一些从库。

水平分表:

表的字段结构不变,按id或者日期等属性,将一张表的数据拆分成多张表。

分库分表会带来的系统问题:

数据迁移,分页排序,表关联查询(设计之初最好就避免,通过提高冗余度降低查询复杂度),分布式事务一致性,分布式全局唯一Id (预生成id , uuid ,使用系统时间, snowflake算法等)

分区: 将sql的数据散落在不同的物理文件,可以按照HASH分区(分区键必须是int或者可以通过函数转换为int类型的字段,散落数据很平均)、RANGE分区(比较常用,大多按日期等节点金子那个分区, 默认less than 原则,每个分区不包括指定的那个原则,多个分区的范围要连续,不可重叠)、LIST分区(采用values in 每行数据必须找到自己的分区,否则插入报错)。

ps : mysql的分区受mysql版本限制,用之前需要先用show plugins; 查看partition属性是否启用。

八、char和varchar  Int和tinyint

char 定长  最大长度255  空符从右边填充空格  检索时删除尾部空格  |  varchar 变长 最大长度65535 不填充空格  检索时不删除空格

int  和 tinyint 存储的数据大小有区别 , tinyint  0 - 255  |  int 0 - 2^32   int(m) tinyint(m)  括号里的m指的是显示的数字的长度,不足长度的会以0填充。

九、SQL的约束类型

NOT NULL | UNIQUE | PRIMARY KEY | FOREIGN KEY |  CHECK

十、主从复制

Mysql主从复制基于binlog,主服务器使用binlog记录数据变更情况,从服务器通过读取和选择性执行该日志文件来保持和主服务器的数据一致。

主库会生成一个 log dump 线程,给从库传binlog。

从库会生成两个线程, 一个是I/O线程,用来获取主库生成的binlog文件,并写入relay log (中继日志)文件中。  一个是SQL线程,读取并解析relay log文件成具体的操作,用来保证和主库一致。

ps: 有一点呢需要注意的是,主库上的sql操作在并发的场景下,都是并行的,但是从库从relayl log里解析出来后,会串行执行。再加上从库本身还要去获取主库的binlog,时间上在一定是存在主从复制延迟的。

解决方案:

1.主库的binlog没有及时同步给从库:

采用半同步复制(semi-sync):指的就是主库写入 binlog 日志之后,就会将强制此时立即将数据同步到从库,从库将日志写入自己本地的 relay log 之后,接着会返回一个 ack 给主库,主库接收到至少一个从库的 ack 之后才会认为写操作完成了。

2.主从同步延时:

采用并行复制:指的是从库开启多个线程,并行读取relay log中不同库的日志,然后并行重放不同库的日志。属于库级别的并行。

最好还是避免写后立即查询的场景,如果实在避免不了,可以采用1.分主库,降低qps压力。2.并行复制。 3:查询时直连主库。

十一、 auto increment 自增,表中记录达到最大值,会怎样

插入报错。

十二、一条select语句的执行过程

引用大佬的图

d3d3f8ed094deceb93b80dff7bb8a19f.png

ps:  1.分析器和优化器之间其实还应该有一层预处理器。主要用来校验列名是否在表中存在,以及该sql是否有权限操作表。

2.缓存层可以理解为hash表,key为查询sql、数据库、客户端协议版本等生成的,value为结果。  如果select中指定了SQL_NO_CACHE 则直接越过缓存层。 mysql8.0已经取消了缓存层。

十三、索引覆盖与回表

背景:

1. 需要了解索引的定义, 索引是帮助mysql高效获取数据并且排好序的数据结构。

2.Innodb 本身数据就已经聚集在主键索引这个大b+树上了。

3.其他辅助索引叶子节点存的是索引内容以及主键的值。

这时候再来介绍回表:

mysql获取数据的时候,单独从一颗索引树上获取不到全部列的值,需要通过获取叶子节点的主键id再去聚集索引的树上获取列值 就可称为回表。

这时候再说下索引覆盖:

mysql获取数据的时候,从一颗索引树上直接获取了全部列值数据,效率很快,无需回表。  Extra出来的属性为using index。

从回表->索引覆盖的常用做法就是单字段索引->联合索引。 将所查的列字段值作为索引内容存储。

十四、B+树小tips

f7e12052019d143a0462cadf8edbf6fd.png

如图所示,不同页之间维护着双向链表,然后一个叶子节点之间其实可以存储多个数据,叶子节点之间的数据是单向的,通过这种“外双内单”的形式,支持mysql快速进行范围查找。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值