ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

mysql基础操作理解(一)

2021-05-13 15:31:31  阅读:115  来源: 互联网

标签:事务 隔离 -- 索引 理解 mysql 操作 级别 READ


MySql基础

按照数据结构来组织、存储和管理数据的仓库;是一个长期存储在计算机内的、有组织的、可共享的、统一管理的大量数据的集合;

SQL

定义

结构化查询语言(Structured Query Language)简称SQL,是一种特殊目的的编程语言,是一种数据库查询和程序设计语言,用于存取数据以及查询、更新和管理关系数据库系统。SQL是关系数据库系统的标准语言。关系型数据库包括:MySQL, SQL Server, Oracle, Sybase, postgreSQL 以及 MS Access等;

SQL命令包括:DQL、DML、DDL、DCL以及TCL;
 

DQL

Data Query Language-数据查询语言;

select,从一个或多个表中检索特定的记录;

DML

Data Manipulate Language-数据库操作语言

insert:插入记录;

update:更新记录;

delete:删除记录;

DDL

Data Define Language-数据定义语言

create:创建一个表,表的视图,或者再数据库中的对象

alter:修改现有的数据库对象,修改表的熟悉和字段;

drop:删除表,数据库对象或者视图

DCL

Data Control Language-数据库控制语言

grant:授予权限

revoke:收回用户权限

TCL

Transaction Control Language-事务控制语言

commit:提交;

rollback:事务回滚;

Mysql体系结构

如下图

Mysql有以下组件       

连接池组件

管理缓冲用户连接,用户名,密码,权限校验,线程处理等需要缓存的需求;

网络处理流程:主线程接收链接或者接收链接交给线程池处理

主要处理方式:IO多路复用,select+阻塞的IO

管理服务和工具组件

系统管理和控制工具,例如备份恢复,Mysql复制,集群等;

SQL接口组件

将SQL语句解析生成对象;DML,DDL,存储过程,视图,触发器等;

查询分析器组件

将SQL对象交由解析器验证和解析,并生成语法树;

优化器组件

SQL语句执行前使用查询优化器进行优化

缓冲组件

是一块内存区域,用来弥补磁盘速度较慢对数据库性能的影响;在数据库进行读取页操作,首先将从磁盘读到的页存放在缓冲池中,下一次再读相同的页时,首先判断该页是否在缓冲池中,若在缓冲池命中,直接读取;否则读取磁盘中的页,说明该页被LRU淘汰了;缓冲池中LRU采用最近最少使用算法来进行管理;缓冲池缓存的数据类型有:索引页、数据页、以及与存储引擎缓存相关的数据(比如innodb引擎:undo页、插入缓冲、自适应hash索引、innodb相关锁信息、数据字典信息等);
 

插件式存储引擎

物理文件

索引

索引包括,主键索引,唯一索引,普通索引,组合索引,全文索引

主键索引

非空唯一索引,一个表只有一个主键索引;在innodb中,主键索引的B+树包含数据信息;

唯一索引

不可以出现相同的值,但可以出现NULL

普通索引

允许出现相同的索引内容

组合索引

对表中的多个列进行索引

全文索引
将存储在数据库当中的整本书和整篇文章中的任意内容信息查找出来的技术;关键词 FULLTEXT;
在短字符串中用 LIKE % ;在全文索引中用 match 和 against ;

主键选择
innodb 中表是索引组织表,每张表有且仅有一个主键;
1. 如果显示设置 PRIMARY KEY ,则该设置的key为该表的主键;
2. 如果没有显示设置,则从非空唯一索引中选择;
       1). 只有一个非空唯一索引,则选择该索引为主键;
       2). 有多个非空唯一索引,则选择声明的第一个为主键;
3. 没有非空唯一索引,则自动生成一个 6 字节的 _rowid 作为主键;

索引实现

索引存储

innodb由段、区、页组成;段分为数据段、索引段、回滚段等;区大小为 1 MB(一个区由64个连续页构成);页的默认值为16k;页为逻辑页,磁盘物理页大小一般为 4K 或者 8K;为了保证区中的页的连续,存储引擎一般一次从磁盘中申请 4~5 个区;


页是 innodb 磁盘管理的最小单位;默认16k,可通过 innodb_page_size 参数来修改;B+树的一个节点的大小就是该页的值;

B+树存储结构

聚集索引
按照主键构造的 B+ 树;叶子节点中存放数据页;数据也是索引的一部分;

下面演示select的执行过程

select * from user where id 1 >= 18 and id < 40;

如下图的执行过程

辅助索引
叶子节点不包含行记录的全部数据;辅助索引的叶子节点中,除了用来排序的 key 还 包含一个
bookmark ;该书签存储了聚集索引的 key;

-- 某个表 包含 id name lockyNum; id是主键,lockyNum存储辅助索引;
select * from user where lockyNum = 33;

最左匹配原则
对于组合索引,从左到右依次匹配,遇到 > < between like 就停止匹配;
-- 某个表 包含 id name lockyNum; id是主键,lockyNum存储辅助索引;
select * from user where lockyNum = 33;
1
2
覆盖索引
从辅助索引中就能找到数据,而不需通过聚集索引查找;利用辅助索引树高度一般低于聚集索引
树;较少磁盘io;
索引失效

select ... where A and B 若 A 和 B 中有一个不包含索引,则索引失效;
索引字段参与运算,则索引失效;例如: from_unixtime(idx) = '2021-04-30';
索引字段发生隐式转换,则索引失效;例如: '1' 隐式转换为 1 ;
LIKE 模糊查询,通配符 % 开头,则索引失效;例如: select * from user where name like '%ark';
在索引字段上使用 NOT <> != 索引失效;如果判断 id <> 0 则修改为idx > 0 or idx < 0 ;
组合索引中,没使用第一列索引,索引失效;

索引原则

1.查询频次较⾼且数据量⼤的表建⽴索引;索引选择使⽤频次较⾼,过滤效果好的列或者组合;
2.使⽤短索引;节点包含的信息多,较少磁盘io操作;
3.对于很长的动态字符串,考虑使用前缀索引;
         有时候需要索引很长的字符串,这会让索引变的大且慢,通常情况下可以使用某个列开始的部分字符串,这样大大的节约索引空间,从而提高索引效率,但这会降低索引的选择性,索引的选择性是指不重复的索引值和数据表记录总数的比值。索引的选择性越高则查询效率越高,因为选择性更高的索引可以让mysql在查找的时候过滤掉更多的行。对于BLOB,TEXT,VARCHAR类型的列,必须要使用前缀索引,因为mysql不允许索引这些列的完整长度,使用该方法的诀窍在于要选择足够长的前缀以保证较高的选择性,通过又不能太长。

select count(distinct left(name,3))/count(*) as sel3,
count(distinct left(name,4))/count(*) as sel4,
count(distinct left(name,5))/count(*) as sel5,
count(distinct left(name,6))/count(*) as sel6,
from user;
alter table user add key(name(4));
-- 注意:前缀索引不能做 order by 和 group by

4.对于组合索引,考虑最左侧匹配原则和覆盖索引;
5.尽量选择区分度⾼的列作为索引;该列的值相同的越少越好

6.尽量扩展索引,在现有索引的基础上,添加复合索引;
7.不要 select * ; 尽量只列出需要的列字段;
8.索引列,列尽量设置为非空;

SQL优化

type
type 显示访问类型;采用怎么样的方式来访问数据;效率从好到坏依次为:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery >
index_subquery > range > index > ALL
ALL : 全表扫描;如果数据量大则需要进行优化;
index :全索引扫描这个比 ALL 的效率要好,主要有两种情况,一种是当前的查询时覆盖索引,
即我们需要的数据在索引中就可以索取,或者是使用了索引进行排序,这样就避免数据的重排序;
range :表示利用索引查询的时候限制了范围,在指定范围内进行查询,这样避免了 index 的全
索引扫描,适用的操作符: = , <> , > , >= , < , <= , IS NULL , BETWEEN , LIKE , or IN()
index_subquery :利用索引来关联子查询,不再扫描全表;
unique_subquery :该连接类型类似与 index_subquery ,使用的是唯一索引;
index_merge :在查询过程中需要多个索引组合使用;
ref_or_null :对于某个字段即需要关联条件,也需要 null 值的情况下,查询优化器会选择这
种访问方式;
ref :使用了非唯一性索引进行数据的查找;
eq_ref :使用唯一性索引进行数据查找;
const :这个表至多有一个匹配行;
system :表只有一行记录(等于系统表),这是 const 类型的特例;

 

possible_keys
查询涉及到字段的索引,则这些索引都会列举出来,但是不一定采纳;
key
实际使用的索引,如果为 NULL ,则没有使用索引
key_len
表示索引中使用的字节数;查询中使用的索引长度;在不损失精度的情况下长度越短越好。
ref
显示索引的哪一列被使用了,如果可能的话,是一个常数;
rows
大致估算出找出所需记录需要读取的行数,反映了sql找了多少条数据,该值越小越好。
extra
额外信息;
using filesort :使用了文件排序;
using temporary :建立临时表来保存中间结果,查询完成之后把临时表删除;
using index :采用覆盖索引,直接从索引中读取数据,而不用访问数据表。如果同时出现using
where 表名索引被用来执行索引键值的查找,如果没有,表面索引被用来读取数据,而不是真的
查找;
using where :使用where进行条件过滤;
using join buffer :使用连接缓存;
impossible where : where 语句的结果总是 false ;

优化器选择过程
优化器根据解析树可能会生成多个执行计划,然后选择最优的的执行计划;

SHOW VARIABLES LIKE 'optimizer_trace';
-- 启用优化器的追踪
SET optimizer_trace='enabled=on';
-- 执行一条查询语句
SELECT * FROM information_schema.optimizer_trace;
-- 用完关闭
SET optimizer_trace="enabled=off";
SHOW VARIABLES LIKE 'optimizer_trace';

事务
目的
事务将数据库从一种一致性状态转换为另一种一致性状态;
组成
事务可由一条非常简单的SQL语句组成,也可以由一组复杂的SQL语句组成;
特征
在数据库提交事务时,可以确保要么所有修改都已经保存,要么所有修改都不保存;
事务是访问并更新数据库各种数据项的一个程序执行单元。
在 MySQL innodb 下,每一条语句都是事务;可以通过 set autocommit = 0; 设置当前会话手动提交;

事务控制语句

-- 显示开启事务
START TRANSACTION | BEGIN
-- 提交事务,并使得已对数据库做的所有修改持久化
COMMIT
-- 回滚事务,结束用户的事务,并撤销正在进行的所有未提交的修改
ROLLBACK
-- 创建一个保存点,一个事务可以有多个保存点
SAVEPOINT identifier
-- 删除一个保存点
RELEASE SAVEPOINT identifier
-- 事务回滚到保存点
ROLLBACK TO [SAVEPOINT] identifier

ACID特性
原子性(A)
        事务操作要么都做(提交),要么都不做(回滚);事务是访问并更新数据库各种数据项的一个程序执行单元,是不可分割的工作单位;通过undolog来实现回滚操作。undolog记录的是事务每步具体操作,当回滚时,回放事务具体操作的逆运算;
隔离性(I)
       事务的隔离性要求每个读写事务的对象对其他事务的操作对象能相互分离,也就是事务提交前对其他事务都不可见;通过 MVCC 和 锁来实现;MVCC 时多版本并发控制,主要解决一致性非锁定读,通过记录和获取行版本,而不是使用锁来限制读操作,从而实现高效并发读性能。锁用来处理并发 DML 操作;数据库中提供粒度锁的策略,针对表(聚集索引B+树)、页(聚集索引B+树叶子节点)、行(叶子节点当中某一段记录行)三种粒度加锁;
持久性(D)
       事务提交后,事务DML操作将会持久化(写入redolog磁盘文件 哪一个页 页偏移值 具体数据);即使发生宕机等故障,数据库也能将数据恢复。redolog记录的是物理日志;
一致性(C)
      一致性指事务将数据库从一种一致性状态转变为下一种一致性的状态,在事务执行前后,数据库完整性约束没有被破坏。例如:一个表的姓名是唯一键,如果一个事务对姓名进行修改,但是在事务提交或事务回滚后,表中的姓名变得不唯一了,这样就破坏了一致性;一致性由原子性、隔离性以及持久性共同来维护的

脏读

事务(A)可以读到另外一个事务(B)中未提交的数据;也就是事务A读到脏数据;在读写分离的
场景下,可以将slave节点设置为 READ UNCOMMITTED;此时脏读不影响,在slave上查询并不
需要特别精准的返回值。

不可重复读
事务(A) 可以读到另外一个事务(B)中提交的数据;通常发生在一个事务中两次读到的数据是不
一样的情况;不可重复读在隔离级别 READ COMMITTED 存在。一般而言,不可重复读的问题是
可以接受的,因为读到已经提交的数据,一般不会带来很大的问题,所以很多厂商(如Oracle、
SQL Server)默认隔离级别就是READ COMMITTED;

幻读
事务中一次读操作不能支撑接下来的业务逻辑;通常发生在一个事务中一次读判断接下来写操作失败的情况;例如:以name为唯一键的表,一个事务中查询 select * from t where name ='mark'; 不存在,接下来 insert into t(name) values ('mark'); 出现错误,此时另外一个事务也执行了insert 操作;幻读在隔离级别 REPEATABLE READ 及以下存在;但是可以在REPEATABLE READ 级别下通过读加锁(使用next-key locking)解决;

解决办法

mysql隔离级别

隔离级别
ISO和ANIS SQL标准制定了四种事务隔离级别的标准,各数据库厂商在正确性和性能之间做了妥协,并没有严格遵循这些标准;MySQL innodb默认支持的隔离级别是 REPEATABLE READ;
1.READ UNCOMMITTED
读未提交;该级别下读不加锁,写加排他锁,写锁在事务提交或回滚后释放锁;
2.READ COMMITTED
读已提交;从该级别后支持 MVCC (多版本并发控制),也就是提供一致性非锁定读;此时读取操作
读取历史快照数据;该隔离级别下读取历史版本的最新数据,所以读取的是已提交的数据;
3.REPEATABLE READ
可重复读;该级别下也支持 MVCC,此时读取操作读取事务开始时的版本数据;
4.SERIALIZABLE
可串行化;该级别下给读加了共享锁;所以事务都是串行化的执行;此时隔离级别最严苛;

命令

-- 设置隔离级别
SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 或者采用下面的方式设置隔离级别
SET @@tx_isolation = 'REPEATABLE READ';
SET @@global.tx_isolation = 'REPEATABLE READ';
-- 查看全局隔离级别
SELECT @@global.tx_isolation;
-- 查看当前会话隔离级别
SELECT @@session.tx_isolation;
SELECT @@tx_isolation;
-- 手动给读加 S 锁
SELECT ... LOCK IN SHARE MODE;
-- 手动给读加 X 锁
SELECT ... FOR UPDATE;
-- 查看当前锁信息
SELECT * FROM information_schema.innodb_locks;

隔离级别的实现


锁机制用于管理对共享资源的并发访问;用来实现事务的隔离级别 ;
锁类型
共享锁和排他锁都是行级锁;MySQL当中事务采用的是粒度锁;针对表(B+树)、页(B+树叶子节点)、行(B+树叶子节点当中某一段记录行)三种粒度加锁;
意向共享锁和意向排他锁都是表级别的锁;

共享锁(S)
事务读操作加的锁;对某一行加锁;
在 SERIALIZABLE 隔离级别下,默认帮读操作加共享锁;
在 REPEATABLE READ 隔离级别下,需手动加共享锁,可解决幻读问题;
在 READ COMMITTED 隔离级别下,没必要加共享锁,采用的是 MVCC;
在 READ UNCOMMITTED 隔离级别下,既没有加锁也没有使用 MVCC;
排他锁(X)
事务删除或更新加的锁;对某一行加锁;
在4种隔离级别下,都添加了排他锁,事务提交或事务回滚后释放

锁算法
Record Lock
记录锁,单个行记录上的锁;
Gap Lock
间隙锁,锁定一个范围,但不包含记录本身;全开区间;REPEATABLE READ级别及以上支持间隙锁;
如果 REPEATABLE READ 修改 innodb_locks_unsafe_for_binlog = 0 ,那么隔离级别相当于退化为 READ COMMITTED;

-- 查看是否支持间隙锁,默认支持,也就是 innodb_locks_unsafe_for_binlog = 0;
SELECT @@innodb_locks_unsafe_for_binlog;

Next-Key Lock
记录锁+间隙锁,锁定一个范围,并且锁住记录本身;左开右闭区间;
Insert Intention Lock
插入意向锁,insert操作的时候产生;在多事务同时写入不同数据至同一索引间隙的时候,并不需要等待其他事务完成,不会发生锁等待。假设有一个记录索引包含键值4和7,两个不同的事务分别插入5和6,每个事务都会产生一个加在4-7之间的插入意向锁,获取在插入行上的排它锁,但是不会被互相锁住,因为数据行并不冲突。

AUTO-INC Lock
自增锁,是一种特殊的表级锁,发生在 AUTO_INCREMENT 约束下的插入操作;采用的一种特殊的表锁机制;完成对自增长值插入的SQL语句后立即释放;在大数据量的插入会影响插入性能,因为另一个事务中的插入会被阻塞;从MySQL 5.1.22开始提供一种轻量级互斥量的自增长实现机制,该机制提高了自增长值插入的性能;

锁的对象
行级锁是针对表的索引加锁;索引包括聚集索引和辅助索引;
表级锁是针对页或表进行加锁;
考虑 InnoDB 在 read committed 和 repeatable read 级别下锁的情况;

MVCC
多版本并发控制;用来实现一致性的非锁定读;非锁定读是指不需要等待访问的行上X锁的释放;
在 read committed 和 repeatable read下,innodb使用MVCC;然后对于快照数据的定义不同;
在 read committed 隔离级别下,对于快照数据总是读取被锁定行的最新一份快照数据;而在repeatable read 隔离级别下,对于快照数据总是读取事务开始时的行数据版本;
思考:为什么读取快照数据不需要上锁?
因为没有事务需要对历史的数据进行修改操作;

 

 

 

 

 

 

标签:事务,隔离,--,索引,理解,mysql,操作,级别,READ
来源: https://blog.csdn.net/lyt_dawang/article/details/116722172

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有