Mysql学习笔记

Mysql学习笔记

Linux安装Mysql

安装

安装方法搜索即可,不再赘述

验证安装是否成功

rpm -qa|grep -i mysql 查看是否安装过Mysql
ps -ef|grep mysql 查看mysql状态
cat /etc/passwd|grep mysql cat /etc/group|grep mysql 查看用户组
mysqladmin --version 查看mysql版本

启动/停止

service mysql start
service mysql stop

MYSQL用户管理

用户管理命令

create user aaa identified by ‘123456’; 创建名称为zhang3的用户,密码设为 123123;
select host,user,password,select_priv,insert_priv,drop_priv from mysql.user 查看用户和权限的相关信息
set password =password(‘123456’) 修改当前用户的密码
update mysql.user set password=password(‘123456’) where user=‘li4’; 修改其他用户的密码 ps:所有通过 user 表的修改必须用 flush privileges;命令才能生效
update mysql.user set user=‘li4’ where user=‘wang5’; 修改用户名 ps:所有通过 user 表的修改,必须用 flush privileges;命令才能生效
drop user li4 ps:不要通过 delete from user uwhere user=‘li4’ 进行删除,系统会有残留信息保留。

用户权限查看

select host,user,password,select_priv,insert_priv,drop_priv from mysql.user
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​在这里插入图片描述

  • host :表示连接类型
  • % 表示所有远程通过 TCP 方式的连接
  • IP 地址 如 (192.168.1.2,127.0.0.1) 通过制定 ip 地址进行的 TCP 方式的连接
  • 机器名 通过制定 i 网络中的机器名进行的 TCP 方式的连接
  • ::1 IPv6 的本地 ip 地址 等同于 IPv4 的 127.0.0.1
  • localhost 本地方式通过命令行方式的连接 ,比如 mysql -u xxx -p 123xxx 方式的连接。
  • user:表示用户名 同一用户通过不同方式链接的权限是不一样的
  • password:密码 所有密码串通过 password(明文字符串) 生成的密文字符串。加密算法为 MYSQLSHA1 ,不可逆 。mysql 5.7 的密码保存到 authentication_string 字段中不再使用 password 字段。
  • 权限查看 select_priv , insert_priv 等为该用户所拥有的权限。

Mysql权限管理

赋予权限

命令: grant 权限 1,权限 2,…权限 n on 数据库名称.表名称 to 用户名@用户地址 identified by‘连接口令’

ps: 该权限如果发现没有该用户,则会直接新建一个用户。

示例:grant select,insert,delete,drop on atguigudb.* to li4@localhost ;给 li4 用户用本地命令行方式下,授予 atguigudb 这个库下的所有表的插删改查的权限。

收回权限

命令: show grants 查看当前用户权限
命令: revoke [权限 1,权限 2,…权限 n] on 库名.表名 from 用户名@用户地址 ; 收回权限命令
命令: REVOKE ALL PRIVILEGES ON mysql.* FROM joe@localhost; 收回全库全表的所有权限
命令: REVOKE select,insert,update,delete ON mysql.* FROM joe@localhost; 收回 mysql 库下的所有表的插删改查权限
查看权限
命令:show grants; 查看当前用户权限
命令:select * from user ;

Mysql架构

整体架构

和其它数据库相比,MySQL 有点与众不同,它的架构可以在多种不同场景中应用并发挥良好作用。主要体现在
存储引擎的架构上,插件式的存储引擎架构将查询处理和其它的系统任务以及数据的存储提取相分离。这种架构可
以根据业务的需求和实际需要选择合适的存储引擎。

连接层

最上层是一些客户端和连接服务,包含本地 sock 通信和大多数基于客户端/服务端工具实现的类似于 tcp/ip 的
通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程池的概念,为通过认证
安全接入的客户端提供线程。同样在该层上可以实现基于 SSL 的安全链接。服务器也会为安全接入的每个客户端验
证它所具有的操作权限。

服务层

Management Serveices & Utilities 系统管理和控制工具
SQL Interface: SQL 接口。接受用户的 SQL 命令,并且返回用户需要查询的结果。比如 select from 就是调用 SQL Interface
Parser 解析器。 SQL 命令传递到解析器的时候会被解析器验证和解析
Optimizer 查询优化器。 SQL 语句在查询之前会使用查询优化器对查询进行优化,比如有where 条件时,优化器来决定先投影还是先过滤。
Cache 和 Buffer 查询缓存。如果查询缓存有命中的查询结果,查询语句就可以直接去查询缓存中取数据。这个缓存机制是由一系列小缓存组成的。比如表缓存,记录缓存,key 缓存,权限缓存等

引擎层

    存储引擎层,存储引擎真正的负责了 MySQL 中数据的存储和提取,服务器通过 API 与存储引擎进行通信。不同

的存储引擎具有的功能不同,这样我们可以根据自己的实际需要进行选取。

存储层

    数据存储层,主要是将数据存储在运行于裸设备的文件系统之上,并完成与存储引擎的交互。

show profile

    利用 show profile 可以查看 sql 的执行周期!

开启 profile

show variables like ‘%profiling%’;
在这里插入图片描述
如果没有开启,可以执行 set profiling=1 开启
在这里插入图片描述

使用 profile

执行 show prifiles 命令,可以查看最近的几次查询。
在这里插入图片描述
根据 Query_ID,可以进一步执行 show profile cpu,block io for query Query_id 来查看 sql 的具体执行步骤。
在这里插入图片描述

查询流程

mysql 的查询流程大致是:
mysql 客户端通过协议与 mysql 服务器建连接,发送查询语句,先检查查询缓存,如果命中,直接返回结果,
否则进行语句解析,也就是说,在解析查询之前,服务器会先访问查询缓存(query cache)——它存储 SELECT 语句以及
相应的查询结果集。如果某个查询结果已经位于缓存中,服务器就不会再对查询进行解析、优化、以及执行。它仅
仅将缓存中的结果返回给用户即可,这将大大提高系统的性能。
语法解析器和预处理:首先 mysql 通过关键字将 SQL 语句进行解析,并生成一颗对应的“解析树”。mysql 解析
器将使用 mysql 语法规则验证和解析查询;预处理器则根据一些 mysql 规则进一步检查解析数是否合法。
查询优化器当解析树被认为是合法的了,并且由优化器将其转化成执行计划。一条查询可以有很多种执行方式,
最后都返回相同的结果。优化器的作用就是找到这其中最好的执行计划。
然后,mysql 默认使用的 BTREE 索引,并且一个大致方向是:无论怎么折腾 sql,至少在目前来说,mysql 最多只
用到表中的一个索引。

MyISAM 和 和 InnoDB

在这里插入图片描述
InnoDB:支持事务处理,支持外键,支持崩溃修复能力和并发控制。如果需要对事务的完整性要求比较高(比如银行),要求实现并发控制(比如售票),那选择InnoDB有很大的优势。如果需要频繁的更新、删除操作的数据库,也可以选择InnoDB,因为支持事务的提交(commit)和回滚(rollback)。

MyISAM:插入数据快,空间和内存使用比较低。如果表主要是用于插入新记录和读出记录,那么选择MyISAM能实现处理高效率。如果应用的完整性、并发性要求比较低,也可以使用。

注意,同一个数据库也可以使用多种存储引擎的表。如果一个表要求比较高的事务处理,可以选择InnoDB。这个数据库中可以将查询要求比较高的表选择MyISAM存储。如果该数据库需要一个用于查询的临时表,可以选择MEMORY存储引擎。

索引

概念

索引(Index)是帮助 MySQL 高效获取数据的数据结构。可以得到索引的本质: 索引是数据结构。可以简单理解为排好序的快速查找数据结构
在这里插入图片描述
左边是数据表,一共有两列七条记录,最左边的是数据记录的物理地址。为了加快 Col2 的查找,可以维护一个 右边所示的二叉查找树,每个节点分别包含索引键值和一个指向对应数据记录物理地址的指 针,这样就可以运用 二叉查找在一定的复杂度内获取到相应数据,从而快速的检索出符合条件的记录。

特点

优点

  • 提高数据检索的效率,降低数据库的IO成本
  • 通过索引列对数据进行排序,降低数据排序的成本,降低了CPU的消耗。

缺点

  • 虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为 更新表时,MySQL不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为 更新所带来的键值变化后的索引信息
  • 实际上索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录,所以索引列也是要占用空间的

Mysql索引

B-树(B树)

B树属于多叉树又名平衡多路查找树

规则

(1)排序方式:所有节点关键字是按递增次序排列,并遵循左小右大原则;

(2)子节点数:非叶节点的子节点数>1,且<=M ,且M>=2,空树除外(注:M阶代表一个树节点最多有多少个查找路径,M=M路,当M=2则是2叉树,M=3则是3叉);

(3)关键字数:枝节点的关键字数量大于等于ceil(m/2)-1个且小于等于M-1个(注:ceil()是个朝正无穷方向取整的函数 如ceil(1.1)结果为2);

(4)所有叶子节点均在同一层、叶子节点除了包含了关键字和关键字记录的指针外也有指向其子节点的指针只不过其指针地址都为null对应下图最后一层节点的空格子;
在这里插入图片描述
3 层的 b+树可以表示上百万的数据,如果上百万的数据查找只需要三次 IO,性能提高将是巨大的, 如果没有索引,每个数据项都要发生一次 IO,那么总共需要百万次的 IO,显然成本非常非常高

B+树(B+tree)

相对于B树来说B+树更充分的利用了节点的空间,让查询速度更加稳定,其速度完全接近于二分法查找

规则

(1)B+跟B树不同B+树的非叶子节点不保存关键字记录的指针,只进行数据索引,这样使得B+树每个非叶子节点所能保存的关键字大大增加;

(2)B+树叶子节点保存了父节点的所有关键字记录的指针,所有数据地址必须要到叶子节点才能获取到。所以每次数据查询的次数都一样;

(3)B+树叶子节点的关键字从小到大有序排列,左边结尾数据都会保存右边节点开始数据的指针。

(4)非叶子节点的子节点数=关键字数(来源百度百科)(根据各种资料 这里有两种算法的实现方式,另一种为非叶节点的关键字数=子节点数-1(来源维基百科),虽然他们数据排列结构不一样,但其原理还是一样的Mysql 的B+树是用第一种方式实现);
在这里插入图片描述

B树与B+树区别

  1. B-树的关键字和记录是放在一起的,叶子节点可以看作外部节点,不包含任何信息;B+树的非叶子节点中只 有关键字和指向下一个节点的索引,记录只放在叶子节点中
  2. 在 B-树中,越靠近根节点的记录查找时间越快,只要找到关键字即可确定记录的存在;而 B+树中每个记录 的查找时间基本是一样的,都需要从根节点走到叶子节点,而且在叶子节点中还要再比较关键字。从这个角度看 B- 树的性能好像要比 B+树好,而在实际应用中却是 B+树的性能要好些。因为 B+树的非叶子节点不存放实际的数据, 这样每个节点可容纳的元素个数比 B-树多,树高比 B-树小,这样带来的好处是减少磁盘访问次数。尽管 B+树找到 一个记录所需的比较次数要比 B-树多,但是一次磁盘访问的时间相当于成百上千次内存比较的时间,因此实际中 B+树的性能可能还会好些,而且 B+树的叶子节点使用指针连接在一起,方便顺序遍历(例如查看一个目录下的所有 文件,一个表中的所有记录等),这也是很多数据库和文件系统使用 B+树的缘故。

为什么说 B+树比 B-树更适合实际应用中操作系统的文件索引和数据库索引?

  1. B+树的磁盘读写代价更低 B+树的内部结点并没有指向关键字具体信息的指针。因此其内部结点相对 B 树更小。如果把所有同一内部结点 的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就 越多。相对来说 IO 读写次数也就降低了。
  2. B+树的查询效率更加稳定 由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须 走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。

聚簇索引和非聚簇索引

在这里插入图片描述
聚簇索引优点
按照聚簇索引排列顺序,查询显示一定范围数据的时候,由于数据都是紧密相连,数据库不不用从多 个数据块中提取数据,所以节省了大量的 io 操作
聚簇索引的限制
对于 mysql 数据库目前只有 innodb 数据引擎支持聚簇索引,而 Myisam 并不支持聚簇索引。 由于数据物理存储排序方式只能有一种,所以每个 Mysql 的表只能有一个聚簇索引。一般情况下就是 该表的主键。 为了充分利用聚簇索引的聚簇的特性,所以 innodb 表的主键列尽量选用有序的顺序 id,而不建议用 无序的 id,比如 uuid 这种

索引分类

单值索引

一个索引只包含单个列,一个表可以有多个单列索引

//随表创建
CREATE TABLE customer (
	id INT(10) UNSIGNED AUTO_INCREMENT ,
	customer_no VARCHAR(200),
	customer_name VARCHAR(200), 
	PRIMARY KEY(id), KEY (customer_name) 
);
//单独创建
CREATE INDEX idx_customer_name ON customer(customer_name);

唯一索引

索引列的值必须唯一,但允许有空值

//随表创建
CREATE TABLE customer (
	id INT(10) UNSIGNED AUTO_INCREMENT ,
	customer_no VARCHAR(200),
	customer_name VARCHAR(200), 
	PRIMARY KEY(id), KEY (customer_name), UNIQUE (customer_no) 
);
//单独建立
CREATE UNIQUE INDEX idx_customer_no ON customer(customer_no);

主键索引

设定为主键后数据库会自动建立索引,innodb为聚簇索引

//随表创建
CREATE TABLE customer (
	id INT(10) UNSIGNED AUTO_INCREMENT ,
	customer_no VARCHAR(200),
	customer_name VARCHAR(200), 
	PRIMARY KEY(id) 
);
//单独创建
ALTER TABLE customer add PRIMARY KEY customer(customer_no);
//删除索引
ALTER TABLE customer drop PRIMARY KEY ;

复合索引

一个索引包含多个列

//随表创建
CREATE TABLE customer (
	id INT(10) UNSIGNED AUTO_INCREMENT ,
	customer_no VARCHAR(200),
	customer_name VARCHAR(200), 
	PRIMARY KEY(id), 
	KEY (customer_name), 
	UNIQUE (customer_name), 
	KEY (customer_no,customer_name) 
);
//单独创建
CREATE INDEX idx_no_name ON customer(customer_no,customer_name);

索引应用场景

适合创建场景

  1. 主键自动建立唯一索引;
  2. 频繁作为查询条件的字段应该创建索引
  3. 查询中与其它表关联的字段,外键关系建立索引
  4. 单键/组合索引的选择问题, 组合索引性价比更高
  5. 查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度
  6. 查询中统计或者分组字段

不适合创建的场景

  1. 表记录太少
  2. 经常增删改的表或者字段
  3. Where 条件里用不到的字段不创建索引
  4. 过滤性不好的不适合建索引

Explain性能分析

概念

使用 EXPLAIN 关键字可以模拟优化器执行 SQL 查询语句,从而知道 MySQL 是如何处理你的 SQL 语句的。分 析你的查询语句或是表结构的性能瓶颈。
在这里插入图片描述

id

表示查询中执行 select 子句或操作表的顺序

id 相同

执行顺序由上至下在这里插入图片描述

id 不同

如果是子查询,id 的序号会递增,id 值越大优先级越高,越先被执行在这里插入图片描述

有相同也有不同

id 如果相同,可以认为是一组,从上往下顺序执行;在所有组中,id 值越大,优先级越高,越先执行衍生 = DERIVED在这里插入图片描述

id 号每个号码,表示一趟独立的查询。一个 sql 的查询趟数越少越好

select_type

select_type 代表查询的类型,主要是用于区别普通查询、联合查询、子查询等的复杂查询

select_type 属性含义
SIMPLE简单的 select 查询,查询中不包含子查询或者 UNION
PRIMARY查询中若包含任何复杂的子部分,最外层查询则被标记为 Primary
DERIVED在 FROM 列表中包含的子查询被标记为 DERIVED(衍生) MySQL 会递归执行这些子查询, 把结果放在临时表里
SUBQUERY在SELECT或WHERE列表中包含了子查询
DEPEDENT SUBQUERY在SELECT或WHERE列表中包含了子查询,子查询基于外层
UNCACHEABLE SUBQUERY无法使用缓存的子查询
UNION若第二个SELECT出现在UNION之后,则被标记为UNION; 若UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED
UNION RESULT从UNION表获取结果的SELECT

SIMPLE

SIMPLE 代表单表查询
在这里插入图片描述

PRIMARY

查询中若包含任何复杂的子部分,最外层查询则被标记为 Primary
在这里插入图片描述

DERIVED

在 FROM 列表中包含的子查询被标记为 DERIVED(衍生),MySQL 会递归执行这些子查询, 把结果放在临时表里

SUBQUERY

在 SELECT 或 WHERE 列表中包含了子查询在这里插入图片描述

DEPENDENT SUBQUERY

在 SELECT 或 WHERE 列表中包含了子查询,子查询基于外层,都是 where 后面的条件,subquery 是单个值,dependent subquery 是一组值
在这里插入图片描述

UNCACHEABLE SUBQUREY

当使用了@@来引用系统变量的时候,不会使用缓存
在这里插入图片描述

UNION

若第二个 SELECT 出现在 UNION 之后,则被标记为 UNION;若 UNION 包含在 FROM 子句的子查询中,外层 SELECT 将被标记为:DERIVED
在这里插入图片描述

UNION RESULT

从 UNION 表获取结果的 SELECT

table

这个数据是基于哪张表的

type

type 是查询的访问类型。是较为重要的一个指标,结果值从最好到最坏依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
一般来说,得保证查询至少达到 range 级别,最好能达到 ref

system

表只有一行记录(等于系统表),这是 const 类型的特列,平时不会出现,这个也可以忽略不计

const

表示通过索引一次就找到了,const 用于比较 primary key 或者 unique 索引。因为只匹配一行数据,所以很快 如将主键置于 where 列表中,MySQL 就能将该查询转换为一个常量

eq_ref

唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描
在这里插入图片描述

ref

非唯一性索引扫描,返回匹配某个单独值的所有行.本质上也是一种索引访问,它返回所有匹配某个单独值的行, 然而,它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体
没用索引前:
在这里插入图片描述
建立索引后:
在这里插入图片描述

range

只检索给定范围的行,使用一个索引来选择行。key 列显示使用了哪个索引一般就是在你的 where 语句中出现 了 between、<、>、in 等的查询这种范围扫描索引扫描比全表扫描要好,因为它只需要开始于索引的某一点,而 结束语另一点,不用扫描全部索引
在这里插入图片描述
在这里插入图片描述

index

出现index是sql使用了索引但是没用通过索引进行过滤,一般是使用了覆盖索引或者是利用索引进行了排序分组
在这里插入图片描述

all

Full Table Scan,将遍历全表以找到匹配的行
在这里插入图片描述

index_merge

在查询过程中需要多个索引组合使用,通常出现在有 or 的关键字的 sql 中
在这里插入图片描述

ref_or_null

对于某个字段既需要关联条件,也需要 null 值得情况下。查询优化器会选择用 ref_or_null 连接查询
在这里插入图片描述

index_subquery

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

unique_subquery

该联接类型类似于 index_subquery。 子查询中的唯一索引
在这里插入图片描述
备注:一般来说,得保证查询至少达到range级别,最好能达到ref

possible_keys

显示可能应用在这张表中的索引,一个或多个。查询涉及到的字段上若存在索引,则该索引将被列出,但不一 定被查询实际使用

key

表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。 key_len 字段能够帮你检查是否充分的 利用上了索引。ken_len 越长,说明索引使用的越充分
在这里插入图片描述
在这里插入图片描述
如何计算: ①先看索引上字段的类型+长度比如 int=4 ; varchar(20) =20 ; char(20) =20 ②如果是 varchar 或者 char 这种字符串字段,视字符集要乘不同的值,比如 utf-8 要乘 3,GBK 要乘 2, ③varchar 这种动态字符串要加 2 个字节 ④允许为空的字段要加 1 个字节 第一组:key_len=age 的字节长度+name 的字节长度=4+1 + ( 20*3+2)=5+62=67 第二组:key_len=age 的字节长度=4+1=5

ref

显示索引的哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值
在这里插入图片描述

rows

rows 列显示 MySQL 认为它执行查询时必须检查的行数。越少越好!
在这里插入图片描述

Extra

其他的额外重要的信息

Using filesort

说明 mysql 会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。MySQL 中无法利用索引 完成的排序操作称为“文件排序”。 出现 filesort 的情况
在这里插入图片描述
优化后,不再出现 filesort 的情况:
在这里插入图片描述
查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度

Using temporary

使了用临时表保存中间结果,MySQL 在对查询结果排序时使用临时表。常见于排序 order by 和分组查询 group by
优化前:
在这里插入图片描述
优化后:
在这里插入图片描述

Using index

Using index 代表表示相应的 select 操作中使用了覆盖索引(Covering Index),避免访问了表的数据行,效率不错! 如果同时出现 using where,表明索引被用来执行索引键值的查找;如果没有同时出现 using where,表明索引只是 用来读取数据而非利用索引执行查找。 利用索引进行了排序或分组

Using where

表明使用了 where 过滤

Using join buffer

在这里插入图片描述
使用了连接缓存

impossible where

where 子句的值总是 false,不能用来获取任何元组
在这里插入图片描述

select tables optimized away

在没有 GROUPBY 子句的情况下,基于索引优化 MIN/MAX 操作或者对于 MyISAM 存储引擎优化 COUNT(*)操 作,不必等到执行阶段再进行计算,查询执行计划生成的阶段即完成优化
在 innodb 中:在这里插入图片描述
在 Myisam 中:
在这里插入图片描述

批量脚本

插入数据

随机产生字符串

DELIMITER $$ 
CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255) 
BEGIN 
DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ'; 
DECLARE return_str VARCHAR(255) DEFAULT ''; 
DECLARE i INT DEFAULT 0; 
WHILE i < n 
DO 
	SET return_str =CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1)); 				
	SET i = i + 1; 
END WHILE; 
RETURN return_str; END $$

随机产生编号

#用于随机产生多少到多少的编号 
DELIMITER $$ 
CREATE FUNCTION rand_num (from_num INT ,to_num INT) 
RETURNS INT(11) 
BEGIN 
DECLARE i INT DEFAULT 0; 
SET i = FLOOR(from_num +RAND()*(to_num -from_num+1)) ; 
RETURN i; 
END$$

创建存储过程

创建往 emp 表中插入数据的存储过程

DELIMITER $$ 
CREATE PROCEDURE insert_emp( START INT , max_num INT ) 
BEGIN 
DECLARE i INT DEFAULT 0; 
#set autocommit =0 把 autocommit 设置成 0 SET autocommit = 0; 
REPEAT SET i = i + 1;
INSERT INTO emp (empno, NAME ,age ,deptid ) VALUES ((START+i) ,rand_string(6) , rand_num(30,50),rand_num(1,10000)); 
UNTIL i = max_num 
END REPEAT; 
COMMIT; 
END$$ 
#删除 
# DELIMITER ; 
# drop PROCEDURE insert_emp;

调用存储过程

添加数据

#执行存储过程,往 dept 表添加 1 万条数据 DELIMITER ; 
CALL insert_dept(10000);

批量删除某个表上的所有索引

删除索引的存储过程

DELIMITER $$ 
CREATE PROCEDURE `proc_drop_index`(dbname VARCHAR(200),tablename VARCHAR(200)) 
BEGIN
DECLARE done INT DEFAULT 0; 
DECLARE ct INT DEFAULT 0; 
DECLARE _index VARCHAR(200) DEFAULT ''; 
DECLARE _cur CURSOR FOR SELECT index_name FROM information_schema.STATISTICS WHERE table_schema=dbname AND table_name=tablename AND seq_in_index=1 AND index_name <>'PRIMARY' ; 
DECLARE CONTINUE HANDLER FOR NOT FOUND set done=2 ; 
OPEN _cur; 
FETCH _cur INTO _index; 
WHILE _index<>'' 
DO SET @str = CONCAT("drop index ",_index," on ",tablename ); PREPARE sql_str FROM @str ; 
EXECUTE sql_str; 
DEALLOCATE PREPARE sql_str; 
SET _index=''; 
FETCH _cur INTO _index; 
END WHILE; CLOSE _cur; 
END$$

执行存储过程

调用:

CALL proc_drop_index("dbname","tablename");

单表使用索引常见的索引失效

全值匹配

有以下 SQL 语句

EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptid=4 
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptid=4 AND emp.name = 'abcd'

建立索引

CREATE INDEX idx_age_deptid_name ON emp(age,deptid,NAME);

在这里插入图片描述
查询的字段按照顺序在索引中都可以匹配到
在这里插入图片描述
SQL 中查询字段的顺序,跟使用索引中字段的顺序,没有关系。优化器会在不影响 SQL 执行结果的前提下,自动地优化

最左前置法则

在这里插入图片描述
查询字段与索引字段顺序的不同会导致索引无法充分使用,甚至索引失效
原因:使用复合索引,需要遵循最佳左前缀法则,即如果索引了多列,要遵守最左前缀法则。指的是查询从索引的最左前列开始并且不跳过索引中的列。
结论:过滤条件要使用索引必须按照索引建立时的顺序,依次满足,一旦跳过某个字段,索引后面的字段都无法被使用

不要在索引列上做任何计算

不在索引列上做任何操作(计算、函数、(自动 or 手动)类型转换),会导致索引失效而转向全表扫描

索引列不能有范围查询

在这里插入图片描述
建议:将可能做范围查询的字段的索引顺序放在最后

尽量使用覆盖索引

在这里插入图片描述

使用不等于(!= 或者<>)的时候

mysql 在使用不等于(!= 或者<>)时,有时会无法使用索引会导致全表扫描
在这里插入图片描述

字段的 is not null 和 is null

在这里插入图片描述
当字段允许为 Null 的条件下:
在这里插入图片描述
is not null 用不到索引,is null 可以用到索引

like 的前后模糊匹配

在这里插入图片描述
只有后缀查询可以使用索引

减少使用or

在这里插入图片描述
使用 union all 或者 union 来替代:
在这里插入图片描述

关联查询优化

left join

EXPLAIN SELECT * FROM class LEFT JOIN book ON class.card = book.card;

查询
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
①在优化关联查询时,只有在被驱动表上建立索引才有效!
②left join 时,左侧的为驱动表,右侧为被驱动表

inner join

④inner join 时,mysql 会自己帮你把小结果集的表选为驱动表。 ⑤straight_join: 效果和 inner join 一样,但是会强制将左侧作为驱动表

四个关联查询案例分析

在这里插入图片描述
在这里插入图片描述
上述两个案例,第一个查询效率较高,且有优化的余地。第二个案例中,子查询作为被驱动表,由于子查询是虚表, 无法建立索引,因此不能优化
结论:子查询尽量不要放在被驱动表,有可能使用不到索引; left join时,尽量让实体表作为被驱动表。

子查询优化

取所有不为掌门人的员工,按年龄分组

select 
	age as '年龄', count(*) as '人数' 
from t_emp 
where id not in (select ceo from t_dept where ceo is not null) group by age;

在这里插入图片描述
如何优化?
①解决 dept 表的全表扫描,建立 ceo 字段的索引:
在这里插入图片描述
此时,再次查询:
在这里插入图片描述
②进一步优化,替换 not in。 上述 SQL 可以替换为:

select 
	age as '年龄',count(*) as '人数' 
from emp e 
left join dept d on e.id=d.ceo 
where d.id is null 
group by age;

在这里插入图片描述
结论: 在范围判断时,尽量不要使用 not in 和 not exists,使用 left join on xxx is null 代替

排序分组优化

索引的字段必须由where或limit处理

where 条件和 on 的判断这些过滤条件,作为优先优化的部门,是要被先考虑的!其次,如果有分组和排序,那么 也要考虑 grouo by 和 order by
在这里插入图片描述
在这里插入图片描述
using filesort 说明进行了手工排序!原因在于没有 where 作为过滤条件
在这里插入图片描述
结论: 无过滤,不索引。where,limt 都相当于一种过滤条件,所以才能使用上索引

顺序错,必排序

①explain select * from emp where age=45 order by deptid,name;
在这里插入图片描述
②explain select * from emp where age=45 order by deptid,empno;
在这里插入图片描述
empno 字段并没有建立索引,因此也无法用到索引,此字段需要排序
③explain select * from emp where age=45 order by name,deptid;
在这里插入图片描述
where 两侧列的顺序可以变换,效果相同,但是 order by 列的顺序不能随便变换!
④explain select * from emp where deptid=45 order by age;
在这里插入图片描述
deptid 作为过滤条件的字段,无法使用索引,因此排序没法用上索引

方向反,必排序

①explain select * from emp where age=45 order by deptid desc, name desc ;
在这里插入图片描述
如果可以用上索引的字段都使用正序或者逆序,实际上是没有任何影响的,无非将结果集调换顺序。
②explain select * from emp where age=45 order by deptid asc, name desc ;
在这里插入图片描述
如果排序的字段,顺序有差异,就需要将差异的部分,进行一次倒置顺序,因此还是需要手动排序的

索引选择

①首先,清除 emp 上面的所有索引,只保留主键索引!

drop index idx_age_deptid_name on emp; 

②查询:年龄为 30 岁的,且员工编号小于 101000 的用户,按用户名称排序

explain 
SELECT 
	SQL_NO_CACHE * 
FROM emp 
WHERE age =30 AND empno <101000 ORDER BY NAME ;

③全表扫描肯定是不被允许的,因此我们要考虑优化。
思路:首先需要让 where 的过滤条件,用上索引; 查询中,age.empno 是查询的过滤条件,而 name 则是排序的字段,因此我们来创建一个此三个字段的复合索引:

create index idx_age_empno_name on emp(age,empno,name);

在这里插入图片描述
再次查询,发现 using filesort 依然存在。
原因: empno 是范围查询,因此导致了索引失效,所以 name 字段无法使用索引排序。 所以,三个字段的符合索引,没有意义,因为 empno 和 name 字段只能选择其一
④解决: 鱼与熊掌不可兼得,因此,要么选择 empno,要么选择 name drop index idx_age_empno_name on emp; create index idx_age_name on emp(age,name); create index idx_age_empno on emp(age,empno);
两个索引同时存在,mysql 会选择哪个?
在这里插入图片描述
explain SELECT SQL_NO_CACHE * FROM emp use index(idx_age_name) WHERE age =30 AND empno <101000 ORDER BY NAME ;
在这里插入图片描述
原因:所有的排序都是在条件过滤之后才执行的,所以如果条件过滤了大部分数据的话,几百几千条数据进行排序 其实并不是很消耗性能,即使索引优化了排序但实际提升性能很有限。 相对的 empno<101000 这个条件如果没 有用到索引的话,要对几万条的数据进行扫描,这是非常消耗性能的,使用 empno 字段的范围查询,过滤性更好 (empno 从 100000 开始)! 结论: 当范围条件和 group by 或者 order by 的字段出现二选一时 ,优先观察条件字段的过滤数量,如果过滤的 数据足够多,而需要排序的数据并不多时,优先把索引放在范围字段上。反之,亦然。

using filesort

mysql排序算法

  1. 双路排序
    MySQL 4.1 之前是使用双路排序,字面意思就是两次扫描磁盘,最终得到数据,读取行指针和 orderby 列,对他 们进行排序,然后扫描已经排序好的列表,按照列表中的值重新从列表中读取对应的数据输出。 从磁盘取排序字段,在 buffer 进行排序,再从磁盘取其他字段。 简单来说,取一批数据,要对磁盘进行了两次扫描,众所周知,I\O 是很耗时的,所以在 mysql4.1 之后,出现了第二种改进的算法,就是单路排序。
  2. 单路排序
    从磁盘读取查询需要的所有列,按照 order by 列在 buffer 对它们进行排序,然后扫描排序后的列表进行输出, 它的效率更快一些,避免了第二次读取数据。并且把随机 IO 变成了顺序 IO,但是它会使用更多的空间, 因为它把每一行都保存在内存中了
  3. 单路排序的问题
    由于单路是后出的,总体而言好过双路。但是存在以下问题: 在 sort_buffer 中,方法 B 比方法 A 要多占用很多空间,因为方法 B 是把所有字段都取出, 所以有可能取出的数 据的总大小超出了 sort_buffer 的容量,导致每次只能取 sort_buffer 容量大小的数据,进行排序(创建 tmp 文件,多 路合并),排完再取取 sort_buffer 容量大小,再排……从而多次 I/O。

如何优化

增大 sort_butter_size 参数的设置
不管用哪种算法,提高这个参数都会提高效率,当然,要根据系统的能力去提高,因为这个参数是针对每个进程的 1M-8M 之间调整。
增大 max_length_for_sort_data 参数的设置
mysql 使用单路排序的前提是排序的字段大小要小于 max_length_for_sort_data。 提高这个参数,会增加用改进算法的概率。但是如果设的太高,数据总容量超出 sort_buffer_size 的概率就增大, 明显症状是高的磁盘 I/O 活动和低的处理器使用率。(1024-8192 之间调整)。
减少 select 后面的查询的字段
当 Query 的字段大小总和小于 max_length_for_sort_data 而且排序字段不是 TEXT|BLOB 类型时,会用改进后的 算法——单路排序, 否则用老算法——多路排序。 两种算法的数据都有可能超出 sort_buffer 的容量,超出之后,会创建 tmp 文件进行合并排序,导致多次 I/O, 但是用单路排序算法的风险会更大一些,所以要提高 sort_buffer_size。

截取查询分析

慢日志查询

介绍

(1)MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阀值的语句,具 体指运行时间超过long_query_time值的SQL,则会被记录到慢查询日志中。
(2)具体指运行时间超过long_query_time值的SQL,则会被记录到慢查询日志中。long_query_time的默认值为 10,意思是运行10秒以上的语句。 (3)由他来查看哪些SQL超出了我们的最大忍耐时间值,比如一条sql执行超过5秒钟,我们就算慢SQL,希望能 收集超过5秒的sql,结合之前explain进行全面分析。

怎么用

默认情况下,MySQL 数据库没有开启慢查询日志,需要我们手动来设置这个参数。
如果不是调优需要的话,一般不建议启动该参数,因为开启慢查询日志会或多或少带来一定的性能影响。 慢查询日志支持将日志记录写入文件
(1) 开启设置

SQL 语句描述备注
SHOW VARIABLES LIKE ‘%slow_query_log%’;查看慢查询日志是否开启默认情况下 slow_query_log 的值为 OFF, 表示慢查询日志是禁用的
set global slow_query_log=1;开启慢查询日志
SHOW VARIABLES LIKE ‘long_query_time%’;查看慢查询设定阈值单位秒
set long_query_time=1设定慢查询阈值单位秒

(2) 如永久生效需要修改配置文件 my.cnf 中[mysqld]下配置

[mysqld] slow_query_log=1 
slow_query_log_file=/var/lib/mysql/atguigu-slow.log 
long_query_time=3 log_output=FILE

(3) 运行查询时间长的 sql,打开慢查询日志查看

日志分析工具mysqldumpslow

得到返回记录集最多的 10SQL 
mysqldumpslow -s r -t 10 /var/lib/mysql/atguigu-slow.log 
得到访问次数最多的 10SQL 
mysqldumpslow -s c -t 10 /var/lib/mysql/atguigu-slow.log 
得到按照时间排序的前 10 条里面含有左连接的查询语句 
mysqldumpslow -s t -t 10 -g "left join" /var/lib/mysql/atguigu-slow.log 
另外建议在使用这些命令时结合 | 和 more 使用 ,否则有可能出现爆屏情况 
mysqldumpslow -s r -t 10 /var/lib/mysql/atguigu-slow.log | more

SHOW PROCESSLIST

介绍

查询 mysql 进程列表,可以杀掉故障进程

怎么用

在这里插入图片描述

工具和技巧拾遗

介绍

将一段查询 sql 封装为一个虚拟的表。 这个虚拟表只保存了 sql 逻辑,不会保存任何查询结果。

作用

(1)封装复杂 sql 语句,提高复用性
(2)逻辑放在数据库上面,更新不需要发布程序,面对频繁的需求变更更灵活

主从复制

基本原理

(1)slave 会从 master 读取 binlog 来进行数据同步
(2)三步骤+原理图
在这里插入图片描述
MySQL 复制过程分成三步:
(1)master 将改变记录到二进制日志(binary log)。这些记录过程叫做二进制日志事件,binary log events;
(2)slave 将 master 的 binary log events 拷贝到它的中继日志(relay log)
(3)slave 重做中继日志中的事件,将改变应用到自己的数据库中。 MySQL 复制是异步的且串行化的

基本原则

(1)每个 slave 只有一个 master
(2)每个 slave 只能有一个唯一的服务器 ID
(3)每个 master 可以有多个 salve

最大问题

因为发生多次 IO,存在延时问题

一主一从常见配置

(1) mysql 版本一致且后台以服务运行
(2) 主从都配置在[mysqld]结点下,都是小写 主机修改 my.ini 配置文件
在这里插入图片描述

#主服务器唯一 ID 
server-id=1 
#启用二进制日志
log-bin=自己本地的路径/data/mysqlbin 
log-bin=D:/devSoft/MySQLServer5.5/data/mysqlbin 
#设置不要复制的数据库 
binlog-ignore-db=mysql 
#设置需要复制的数据库 
binlog-do-db=需要复制的主数据库名字 
#设置 logbin 格式 
binlog_format=STATEMENT(默认)

mysql 主从复制起始时,从机不继承主机数据
(3) logbin 格式 binlog_format=STATEMENT(默认) binlog_format=ROW binlog_format=MIXED
(4) 从机配置文件修改 my.cnf 的[mysqld]栏位下

#从机服务 id 
server-id = 2 
#注意 my.cnf 中有 
server-id = 1 
#设置中继日志 
relay-log=mysql-relay

(5) 因修改过配置文件,请主机+从机都重启后台 mysql 服务
(6) 主机从机都关闭防火墙、安全工具(腾讯管家等)
(7) 在 Windows 主机上建立帐户并授权 slave

#创建用户,并授权 
GRANT REPLICATION SLAVE ON *.* TO '备份账号'@'从机器数据库 IP' IDENTIFIED BY '123456';

在这里插入图片描述
(8) 查询 master 的状态,并记录下 File 和 Position 的值

#查询 master 的状态 
show master status;

在这里插入图片描述
执行完此步骤后不要再操作主服务器 MYSQL,防止主服务器状态值变化 (9) 在 Linux 从机上配置需要复制的主机

#查询 master 的状态 
CHANGE MASTER TO MASTER_HOST='主机 IP',
MASTER_USER='创建用户名',
MASTER_PASSWORD='创建的密码', 
MASTER_LOG_FILE='File 名字',
MASTER_LOG_POS=Position 数字;

在这里插入图片描述
(10) 启动从服务器复制功能

start slave; 
show slave status\G;

在这里插入图片描述
下面两个参数都是 Yes,则说明主从配置成功!
(11) 主机新建库、新建表、insert 记录,从机复制
(12) 如何停止从服务复制功能 stop slave;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值