Mysql高级

Mysql调优解决思路
1、收到爆炸,整顿SQL
2、开启慢查询日志,抓取执行慢的SQL
3、Explain开始分析(应该会找到问题所在)
4、Show profile(比explain更加细粒度,基本95%的问题就解决了)
5、配合DBA开始各种参数调优

mysql的架构介绍
(1)Mysql简介
1、概述
MySQL是一个关系型数据库管理系统,有瑞典MySQLAB公司开发,目前属于Oracle公司
MySQL是一种关联数据库管理系统,将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性

MySQL是开源的,所以你不需要支付额外的费用
MySQL支持大型的数据库,可以处理拥有上千万条记录的大型数据库
Mysql可以允许于多个系统上,并且支持多种语言,这些编程语言包括C、C++、python、java、perl、php、eiffel、ruby和tcl等
Mysql对PHP有很好的支持,PHP是目前最流行的web开发语言
Mysql支持大型数据库。支持5000万条记录的数据残酷,32位系统表文件最大可支持4GB,64位系统支持最大的表文件为8TB
Mysql是可以定制的,采用了GPL协议,你可以修改源码来开发自己的mysql系统
2、高级mySQL(完整的mysql优化需要很深的功底,大公司甚至有专门的DBA写上述)
①Mysql内核
②Sql优化工程师
③Mysql服务器的优化
④各种参数常量设定
⑤查询语句优化
⑥主从复制
⑦软硬件升级
⑧容灾备份
⑨Sql编程
(2)mysqlLinux版的安装
Mysql5.5版本
1、下载地址:
http://dev.mysql.com/downloads/mysql
2、检查当前系统是否安装过mysql
rpm -qu|grep -i mysql
3、安装mysql服务端(注意提示)
rpm -ivh mysql-server-5.5.48-1.linux2.6.i386.rpm
直接修改密码:/usr/bin/mysqladmin -u root password root
4、安装mysql客户端
rpm -ivh mysql-client-5.5.48-1.linux2.6.i386.rpm
5、看mysql是否安装
cat /etc/passwd|grep mysql查看用户信息
cat /etc/group|grep mysql查看组
或者mysqladmin -version
6、查看mysql是否启动
ps -ef|grep mysql
7、查看mysql安装时创建的mysql用户和mysql组
8、Mysql服务的启+停
启动:Service mysql start
停止:service mysql stop

Mysql启动后,开始连接
首次连接成功 输入mysql -uroot -p root
注意这里,因为mysql没有密码,所以这里我们没有输入密码就直接连上了
按照安装server中的提示修改登录密码
9、自启动mysql服务
设置开机自启动:Chkconfig mysql on
Ntsysv
10、mysql的安装位置
在linux下查看安装目录 ps -ef|grep mysql
mysql数据库的数据库的存放位置/var/lib/mysql
路径 解释 备注
/var/lib/mysql/ Mysql数据库文件的存放路径 /var/lib/mysql/atguigu.cloud.pid
/usr/share/mysql 配置文件目录 Mysql.server命令及配置文件
/usr/bin 相关命令目录 Mysqladmin mysqldump命令
/etc/init.d/mysql 启停相关脚本
11、修改配置文件位置
Mysql5.5版本:cp /usr/share/mysql/my-huge.cnf /etc/my.cnf
Mysql5.6版本:cp /usr/share/mysql/my-default.cnf /etc/my.cnf
之后重新启动mysql:service mysql stop/start
12、修改字符集和数据存储路径
Vim /etc/my.cnf
[client]下添加一行
default-character-set=utf8
[mysqld]初添加三行
character_set_server=utf8
character_set_client=utf8
collation-server=utf8_general_ci
[mysql]下添加一行
default-character-set=utf8
重启mysql,重新创建数据库,建表,插入数据
(3)Mysql配置文件
主要配置文件
1、二进制日志log-bin
主从复制,配置在mysql的目录下面
2、错误日志log-error
默认是关闭的,记录严重的警告和错误信息,每次启动和关闭的详细信息等
配置在mysql/data下面
3、查询日志log
默认是关闭的,记录查询的sql语句,如果开启会减低mysql的整体性能,因为记录日志也是需要消耗系统资源
4、数据文件
1)两系统
Windows:D:\bigdataENV\MySql\mysql5.5\data目录下可以挑选很多数据库
Linux:查看当前系统中的全部库后再进去
默认路径是.var/lib/mysql
2)Frm文件
存放表结构
3)Myd文件
存放表数据
4)Myi文件
查找表的索引
5、如何配置
Windows my.ini文件
Linux /etc/my.cnf文件
(4)Mysql逻辑架构介绍
1、总体概览
和其他数据库相比,mysql有点与众不同,他的架构可以在多种不容场景中应用并发挥良好作用,主要提箱在存储引擎的架构上,插件式的存储引擎架构将查询和其他的系统任务以及数据的存储提取相分离,这种架构可以根据业务的需求和实际需要选择合适的存储引擎

1、连接层
最上层是溢写客户端和连接服务,包含本地sock通信和大多数基于客户端/服务端工具实现的类似于tcp/ip的通信,主要完成一些类似于连接处理,授权认证、及相关的安全方案,在该层上引入了线程池的概念,为通过认证安全接入的客户端提供的线程,同样在该层上可以基于SSL的安全链接,服务器䧥为安全接入地方每个客户端验证他所具有的的操作权限
2、服务层
第二层架构主要完成大多数的核心服务功能,入SQL接口,并完成缓存的查询,SQL的分析和优化及部分内置函数的执行,所有跨存储引擎的功能在这一层实现,入过程、函数等,在非常呢个,服务器会解析查询并创建相应的内部解析树,并对其完成相应的优化如确定查询表的顺序,是否利用索引等,最后生成相应的执行操作,如果是select语句,服务器还会有查询内部的缓存,如果缓存空间足够大,这样会解决大量读操作的环境中能够很好的提升系统的性能
3、引擎层
存储引擎层,存储引擎真正的负责了mysql中数据的存储和提取,服务器通过API与存储引擎进行通信,不容的存储引擎具有的功能不同,这样我们可以根据自己的实际需要进行选取,后米昂介绍MyISAMy和InnoDB
4、存储层
数据存储层,主要是将数据存储在运行在裸设备的温江系统之上,并完成与存储引擎的交互

2、查询说明
(5)Mysql的存储引擎
1、查看命令(如何用命令查看)
#查看你的mysql现在提供了什么存储引擎
Mysql>show engines;
#查看你的mysql当前使用的什么存储引擎
Mysql>show variables like ‘%storage_engine%’
2、MyISAM和InnoDB
对比项 MyISAM InnoDB
主外键 不支持 支持
事务 不支持 支持
行表锁 表锁,及时操作一条记录也会锁住整张表,不适合高并发 行锁,操作时只锁某一行,不对其他行有影响,适合高并发
缓存 只缓存索引,不缓存数据 不仅缓存索引还要缓存真是数据,对内存要求较高,而且内存大小对性能有决定性的影响
表空间 小 大
关注点 性能 事务
默认安装 Y Y

3、阿里巴巴和淘宝用那个
产品 价格 目标 主要功能 是否可投入生产?
Percona Server 免费 提供XtraDB粗糙农户引擎的包装器和其他分析工具 XtraDB 是
MariaDB 免费 扩展MySQL以包含XtraDB和其他性能改造 XtraDB 是
Drizzle 免费 提供比MySQL更强大的可扩展性和性能改进 高可用性 是

Percona为MySQL数据库服务器记性了改进,在功能和性能上交MySQL有这很显著的提升,该版本提升了负载情况下的InnoDB的性能,为DBA提供一些非常有用的性能诊断工具;另外有更多的参数和命令来控制服务器行为

该公司新建了一款存储引擎脚xtradb完全可以替代innodb,并且在性能个并发上做的更好

阿里巴巴大部分mysql数据库其实使用的percona的原型加以修改
AliSql+AliRedis
2、索引优化分析
(1)性能下降SQL慢(执行时间长、等待时间长)
1、查询语句写的烂
2、索引失效
单值 复合
3、关联查询太多join(设计缺陷或不得已的需求)
4、服务器调优即各个参数设置(缓冲、线程等)
(2)常见通用的join查询
1、SQL执行顺序
手写
Select destinct

From

Join on
Where

Group by

Having

Order by

Limit
机读
From
On
join
Where
Group by
Having
Select
Distinct
Order by
Limit
总结

2、Join图(7种join)

(3)索引简介
1、索引是什么?
1)Mysql官方对索引的定义为:索引(index)是帮助mysql高效的获取数据的数据结构
可以得到数据的本质:索引就是数据结构

索引的目的在于调高查询效率,可以类比字典
如果要查“mysql”这个单词,我们肯定需要定位到m字母,然后从上往下找到字母,在找到剩下的sql
如果没有索引,那么你可能需要a—z,如果我想找到java开头的单词呢?或者oracle开头的单词呢?
是不是觉得如果没有这个事情根本无法完成
2)你可以简单的理解为“排好序的快速查找数据结构”
1、详解
在数据之外,数据库系统还卫华这满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级是查找算法,这种数据结构,就是索引,下图就是一种可能的索引方式示例

左表是数据表,以供有两列七条记录,最左边的是数据记录的物理地址

为了加快col2的查找,可以维护一个右边所示的二叉查找树,每个节点分别包含索引键值和一个纸箱对应数据记录物理地址的指针,这样就可以运用二叉查找在一定的复杂度内回去到相应数据,从而快读的检索出符合条件的记录
2、结论
数据本身之外,数据库还维护着一个满足特定查找算法的数据结构,这些数据结构以某种方式纸箱数据,这样就可以在这些数据结构的基础上实现高级查找算法,这种数据结构就是索引
3)一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往以文件形式存储在磁盘上
4)我们平常所说的索引,如果没有特别指明,都是指B树(多路搜索树,并不一定是二叉的)结构组织的索引,其中聚焦索引,次要索引,覆盖索引,复合索引,前缀索引,唯一索引默认都是使用B+树索引,统称索引,当然,除了B树这种类型的索引之外,还有哈希(hash)索引
2、优势
类似大学图书馆简述目录索引,提高数据检索的效率,降低数据库的IO成本
通过索引列岁数据排序,降低数据排序的成本,降低了CPU的消耗
3、劣势
实际上索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录,所以索引列也是要占用空间的
虽然索引大大提高了查询速度,同时却会降低更新表的速度,入对表进行insert、update和delete
因为更新表时,mysql不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息
索引只是提高效率的一个因素,如果你的mysql有大数据量的表,就需要花时间研究建立最优秀的索引,或优化查询
4、Mysql索引分类
单值索引:
即一个索引只包含单个列,一个表可以有多个单例索引(最多不要超过5个)
唯一索引:
索引列的值必须唯一,但允许有空值
复合索引:
即一个索引包含了多个列
基本语法:
#创建(两种方式):
create [unique] index indexName on mytable(columnname(length));
Alter mytable add [unique] index [indexName] on (columnname(length))
#删除:drop index [indexName] on mytable
#查看:show index from tableName;
#使用alter命令:
#有四种方式来添加数据表的索引:
Alter table tbl_name add primary key(column_list):该语句添加一个主键,这意味着索引值必须是唯一的,且不能为null
Alter table tbl_name add unique index_name (column_list);这条语句创建爱你索引的值必粗是唯一的(除了null外,null、可能会出现多次)
Alter table tbl_name add index index_name (column_list);添加普通索引,索引值可以出现多次(复合)
Altertable tbl_name add fulltext index_name (column_list);该语句指定了索引为fulltext,用于全文索引

5、Mysql索引结构
BTree索引
检索原理:

【初始化介绍】
一个B+树,浅蓝色的块我们称之为一个磁盘块,可以看到每个磁盘块包含几个数据项(深蓝色所示)和指针(黄色所示)
入磁盘块1包含数据项17和35,包含指针P1、P2、P3。
P1表示小玉17的磁盘块,P2表示在17和35之间的磁盘块,P3表示大于36的磁盘块
真实数据存在于叶子节点,即3、5、9、10、13、15、28、29、36、60、75、79、90、99
非叶子节点只不存储真实数据,只存储指引搜索方向的数据项,如17、35并不真实存在于数据表中

【查找过程】
如果要查找数据项29,那么首先会把磁盘块1有磁盘加载到内存,此事发生一次IO流,在内存中用二分法查找确定29在17和35之间,锁定磁盘块1的P2指针,内存时间因为分长短(相比磁盘的IO)可以忽略不计,通过磁盘块1的P2指针对磁盘地址把磁盘块3由磁盘加载到内存,发生第二次IO,29在26和30之间,锁定3的P2指针,通过指针加载磁盘块8到内存,发生地单词IO,同时内存中共做二分查找找到29,结束查询,总计三次IO
真实情况是,3层的B+树可以表示上百万的数据,如果上百万的数据查找只需要三次IO,性能提高讲师巨大的,如果没有索引,每个数据项都要发生一个IO,那么总共需要百万次的IO,显然成本非常非常高

Hash索引
full-text索引
R-Tree索引
6、那些情况需要创建索引
1、主键自动建立唯一索引
2、频繁作为查询条件的字段应该创建索引
3、查询中与其他字段关联的字段,外键关系建立索引
4、频繁更新的字段不适合创建索引
5、因为每次更新不单单是更新了记录还会更新索引
6、Where条件里用不到的字段不创建索引
7、单键/组合索引的选择问题,who?(在并发下倾向创建组合索引)
8、查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度
9、查询中统计或者分组字段
7、那些情况不需要创建索引
1、表记录太少

2、经常增删改的表
Why?
提高了查询速度,同时却会降低更新表的速度,如对表进行insert、update和delete
因为更新表时,mysql不仅要保存数据,还要保存一下索引文件
3、数据重复且分布平均的字段,因此应该只为最经常查询和最经常排序的数据列建立索引
Tips:如果某个数据列包含许多重复的内容,为他建立索引就没有太大是的实际效果
Eg:加入一个表有10万行记录,有一个字段A只有T和F两种值,且每个值的分布概率大约为50%,那么对这种表A字段建索引一般不会提高数据库的查询速度
索引的选择是指索引类中不同值的数目与表中记录数的比,如果一个表中有2000条记录,表索引列有1980个不同的值,那么这个索引的选择性就是1980/2000=0.99,一个索引的选择性月接近于1,这个索引的效率就越高
(4)性能分析
1、Mysql query optimizer
1、Mysql中有专门负责优化select语句的优化器模块,主要功能:通过计算分析系统中收集到的彤彤一级信息,为客户端请求的query提供他认为最优的执行计划(他认为最优的数据检索方式,但不见得是DBA认为是最优的,这部分最耗费时间)
2、当客户端向mysql请求一条query,命令解析器模块完成请求分类,区别是select并转发给mysql query optimizer时,mysql query optimizer首先会对整条query进行优化,处理掉一些常量表达式的预算,直接换算成常量值,并对query中的查询条件进行简化和转换,如去掉溢写无用或显而易见的条件,结构调整等,然后分析query中的hint信息(如果有,)看显示hinit信息是否可以完全确定该query的执行计划,如果没有hint或者hint信息还不足以完全确定执行计划,则会读取锁设计对象的统计信息,根据query进行写相应的计算分析,然后在得出最后的执行计划
2、Mysql常见瓶颈
1、CPU:CPU在饱和的时候一般发生在数据装入内存或从磁盘上读取数据的时候
2、IO:磁盘IO瓶颈发生在装入数据远大于内存容量的时候
3、服务器硬件的性能瓶颈:top、free、iostat和vmstat来查看系统的性能状态
3、Explain
1、是什么(查看执行计划)
使用explain关键字可以模拟优化器执行sql查询语句,从而知道mysql是如何处理你的SQL语句的,分析你的查询语句或是表结构的性能瓶颈
官网介绍
http://dev.mysql.com/doc/refman/5.5/en/explain-output.html
2、能干嘛?
(1)表的读取顺序
(2)数据读取操作的操作类型
(3)哪些索引可以使用
(4)哪些索引被实际使用
(5)表之间的引用
(6)每张表有多少行被优化器查询
3、怎么玩?
1)Explain+SQL语句
2)执行计划包含的信息(多了一个表头信息)

4、各个字段解释
1、Id:
(1)select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序
(2)三种情况:
1)Id相同(执行顺序由上至下):

2)Id不同(如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行)

如果是子查询,id的序号会递增,id值越大优先级越高,月先被执行
3)Id既相同又不同(同时存在)

Id如果相同,可以认为是一组,从上往下顺序执行
在所有组中,id值越大,优先级越高,越先执行
衍生 = DERIVED
2、select_type
1、常用的有6个
±-------±-----------------------------+
| id |select_type +
±-------±---------------------------+
| 1 | simple |
| 2 | primary |
| 3 | subquery |
| 4 | derived |
| 5 | union |
| 6 | union result |
±-------±---------------------------+
2、查询的类型,只要是用于区别普通查询、联合查询、子查询等的复杂查询
Simple:简单的select查询,查询中不包含子查询或者union
Primary:查询中包含任何复杂的字部分,最外层查询则被标记为Primary
subquery:在select或where列表中包含了子查询
Derived:在from列表中包含的子查询被标记为derived(衍生)
Mysql会递归执行这些子查询,把结果放在临时表里
Union:若第二个select出现在union之后,则被标记为union
入union包含在from子句的子查询中,外层select将被标记为:derived
Union result:从union表获取结果的select
3、table
显示这一行的数据时关于那张表的
4、type

1、访问类型排列
Type显示的是访问类型,是较为重要的一个指标,结果值从最好到最坏依次是
System>const>eq_ref>ref>fulltext>ref_or_null>index_merge>unique_subquery>index_sybquery>range>index>all

System>const>eq_ref>ref>ragne>index>all
一般来说,得保证查询知道达到range级别,最好能达到ref
2、显示查询使用了几种类型,
从最好到最差依次是:system>const>eq_ref>ref>rabge>index>All
依次解释:
System:表只有一行记录(等于系统表),这是const类型的特例,平时不会出现,这个也 可以忽略不计(单表单行)
Const:表示通过索引一次就找到了,const用于比较primary key或者unique索引,因为只匹配一行数据,所以很快
如将主键至于where列表中,mysql就能将该查询转换为一个常量(写死常量)

eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配,常见于主键或唯一索引扫描(如同公司CEO,只有一个)

Ref:非唯一性索引行索引扫描,返回匹配某个单独值的所有行
本质上也是一种索引访问,他返回所有匹配某个单独值的行,然而,他可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体(如同研发部的程序员)

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

Index:full index scan,index与all区别为index类型只遍历索引数,这通常比all块,因为 索引文件通常比数据文件小,(也就是说虽然all和index都是读取全表,但index是 从索引中读取的,而all是从硬盘中读取的)

All:full table scan,将遍历全表以找到匹配的行

备注:一般来说,得保证查询至少达到range级别,最好能达到ref
5、possible_keys
显示可能应用在这张表中的索引,一个或多个
查询涉及到的字段存在索引,则该索引将被列出,但不一定被查询实际使用
6、key
实际使用的索引,如果为null,则没有使用索引
查询中若使用了索引,则该索引仅出现在key列表中

7、key_len
表示索引中使用的字节数,可通过该列计算查询着使用的索引的长度,在不损失精性的情况下,长度越短越好
key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的

8、ref
显示索引的那一列被使用了,如果可能的话,是一个常数,那些列或常量被用于查找索引列上的值

由key_len可知t1表的idx_col1_col2被充分使用,col1匹配t2表的col1,col2匹配了一个常量,即‘ac’
查询中与其他表关联的字段,外键关系建立索引
9、rows:
根据表统计信息及索引选用情况,大致估算出找到记录所需要读取的行数(每张表有多少行被优化,用的越少越好)

10、extra:
包含不适合在其他列中显示但十分重要的额外信息
1、using filesort(九死一生)
说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取
mysql中无法利用索引完成的排序操作成为“文件排序”

2、using temporary(必死无疑)
使用了临时表来保存中间结果,mysql在查询结果排序是使用临时表,常见于排序order by和分查询group by

3、using index(最好的)
表示相应的select操作中使用了覆盖索引(Covering index),避免访问了表的数据行,效率不错
如果同时出现using where,表明索引被用来执行索引键值的查找
如果没有同时出现using where,表明索引用来读取数据而非执行查找动作
覆盖索引(covering index)
覆盖索引(covering index),一说为索引覆盖
理解一:就是select的数据列只用从索引中就能够取得,不必读取数据行,mysql可以利用索引返回select列表中的字段,而不必根据索引再次读取数据文件,换句话说查询列要被所建的索引覆盖
理解二:索引就是高效的找到行的一个方法,但是一般数据库也能使用索引找到一个列的数据,因此他不比读取整个行,毕竟索引叶子节点存储了他们索引的数据,当能通过读取索引就可以得到想要的数据,那就不需要读取行了,一个索引包含了(或覆盖了)满足查询结果的数据就叫做覆盖索引

Tips:如果使用覆盖索引,一定要注意select列表中只取出需要的列,不可select*
因为如果将所有字段一起做索引会导致索引文件过大,查询性能下降

4、using where
表明使用了where过滤
5、using join buffer
使用了连接缓存
6、impossible where
Where子句的值总是false,不能用来获取任何元组

7、select table optimized away
在没有groupby子句的情况下,基于索引优化min/max操作或者对于myidam存储引擎优化count(*)操作,不必等到执行阶段在进行计算,查询执行计划生成的阶段即完成优化
8、distinc
优化distinct操作,在找到第一匹配的原则后即停止找同样值的动作

5、热身case

(5)索引优化
1、单表
1)建表SQL

Select * from article;
2)案例

2、两表
1)建表SQL

2)案例

3、三表
1)建表SQL

2)案例

结论优化总结:1、尽可能减少join语句中的nestedLoop的循环总次数,“永远用小的结果集驱动大的结果集”
2、优先优化nestedloop的内层循环
3、保证join语句中被驱动表上的join条件字段已经被索引
4、当无法保证被驱动表的join条件字段被索引且内存资源充足的前提下,不要太吝啬joinBuffer的设置
4、索引失效(应该避免)
1)建表SQL

2)案例(索引失效)
1、全职匹配我最爱
2、最佳左前缀法则:如果索引了多列,要遵守最左前缀法则,指的是查询从索引的最前列开始并且不跳过索引中的列

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

Select * from staffs where name = “July”;
Select * from staffs where left(name,4) = “July”;会全表扫描,索引列会失效
4、存储引擎不能使用索引中范围条件右边的列

5、尽量使用覆盖索引(只访问索引的查询(索隐列和查询列一致)),减少select*

6、Mysql在使用不等于(!=或者<、>)的时候无法使用索引会导致全表扫描

7、Is null,is not null也无法使用索引

8、Like以通配符开头(‘%abc…’)mysql索引失效会变成全表扫描的操作

问题:解决like%字符串%索引不被使用的方法???
建表SQL
DROP TABLE IF EXISTS tbl_user;

CREATE TABLE tbl_user (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(20) NOT NULL,
age int(11) DEFAULT NULL,
email varchar(20) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

insert into tbl_user(id,name,age,email) values (2,‘1aa1’,21,‘[email protected]’),(3,‘2aa2’,21,‘[email protected]’),(4,‘3aa3’,21,‘[email protected]’),(5,‘4aa4’,21,‘[email protected]’);
Before index
EXPLAIN SELECT NAME,age FROM tbl_user WHERE NAME LIKE ‘%aa%’;
EXPLAIN SELECT NAME,age FROM tbl_user WHERE NAME LIKE ‘%aa’;
EXPLAIN SELECT NAME,age FROM tbl_user WHERE NAME LIKE ‘aa%’;

EXPLAIN SELECT id FROM tbl_user WHERE NAME LIKE ‘%aa%’;
EXPLAIN SELECT id,NAME,age FROM tbl_user WHERE NAME LIKE ‘%aa%’;
EXPLAIN SELECT NAME,age FROM tbl_user WHERE NAME LIKE ‘%aa%’;

EXPLAIN SELECT * FROM tbl_user WHERE NAME LIKE ‘%aa%’;
EXPLAIN SELECT id,NAME,age,email FROM tbl_user WHERE NAME LIKE ‘%aa%’;

Create index
CREATE INDEX idx_user_name_age ON tbl_user(NAME,age);

Create index idx_user_name_age on tbl_user(name,age)
9、字符串不加单引号索引失效

10、少用or,用它来连接是会索引失效

11、小总结

索引失效口诀
1、带头大哥不能死
2、中间兄弟不能断,永远要符合最佳左前缀原则
3、索引列上无计算,否则会显式隐式的进行类型转换
4、like%加右边
5、范围之后全失效
6、字符串里有引号

面试题讲解
题目SQL
#建表SQL
DROP TABLE IF EXISTS test03;

CREATE TABLE test03 (
id INT(10) NOT NULL AUTO_INCREMENT,
c1 CHAR(10) DEFAULT NULL,
c2 CHAR(10) DEFAULT NULL,
c3 CHAR(10) DEFAULT NULL,
c4 CHAR(10) DEFAULT NULL,
c5 CHAR(10) DEFAULT NULL,
PRIMARY KEY (id),
KEY idx_test_c1234 (c1,c2,c3,c4)
) ENGINE=INNODB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

#添加语句
INSERT INTO test03(c1,c2,c3,c4,c5)VALUES (‘a1’,‘a2’,‘a3’,‘a4’,‘a5’);
INSERT INTO test03(c1,c2,c3,c4,c5)VALUES (‘b1’,‘b2’,‘b3’,‘b4’,‘b5’);
INSERT INTO test03(c1,c2,c3,c4,c5)VALUES (‘c1’,‘c2’,‘c3’,‘c4’,‘c5’);
INSERT INTO test03(c1,c2,c3,c4,c5)VALUES (‘d1’,‘d2’,‘d3’,‘d4’,‘d5’);
INSERT INTO test03(c1,c2,c3,c4,c5)VALUES (‘e1’,‘e2’,‘e3’,‘e4’,‘e5’);

SELECT * FROM test03;

#建立索引
CREATE INDEX idx_test_c1234 ON test03(c1,c2,c3,c4);

#查看索引
SHOW INDEX FROM test03;

#问题,我们创建了符合索引,根据索引情况idx_test03_c1234根据以下SQL分析下索引使用情况
EXPLAIN SELECT * FROM test03 WHERE c1 = ‘a1’;
EXPLAIN SELECT * FROM test03 WHERE c1 = ‘a1’ AND c2 = ‘a2’;
EXPLAIN SELECT * FROM test03 WHERE c1 = ‘a1’ AND c2 = ‘a2’ AND c3 = ‘a3’;
EXPLAIN SELECT * FROM test03 WHERE c1 = ‘a1’ AND c2 = ‘a2’ AND c3 = ‘a3’ AND c4 = ‘a4’;

EXPLAIN SELECT * FROM test03 WHERE c1 = ‘a1’ AND c2 = ‘a2’ AND c3 = ‘a3’ AND c4 = ‘a4’;
2)
EXPLAIN SELECT * FROM test03 WHERE c1 = ‘a1’ AND c2 = ‘a2’ AND c4 = ‘a4’ AND c3 = ‘a3’;
3)
EXPLAIN SELECT * FROM test03 WHERE c1 = ‘a1’ AND c2 = ‘a2’ AND c3 > ‘a3’ AND c4 = ‘a4’;
4)
EXPLAIN SELECT * FROM test03 WHERE c1 = ‘a1’ AND c2 = ‘a2’ AND c4 > ‘a4’ AND c3 = ‘a3’;
5)
EXPLAIN SELECT * FROM test03 WHERE c1 = ‘a1’ AND c2 = ‘a2’ AND c4 > ‘a4’ ORDER BY c3;
c3的作用用作于排序而不是查找
6)
EXPLAIN SELECT * FROM test03 WHERE c1 = ‘a1’ AND c2 = ‘a2’ ORDER BY c3;
7)
EXPLAIN SELECT * FROM test03 WHERE c1 = ‘a1’ AND c2 = ‘a2’ ORDER BY c4;
会产生内部排序filesort
8)
8.1)
EXPLAIN SELECT * FROM test03 WHERE c1 = ‘a1’ AND c5 = ‘a5’ ORDER BY c2,c3;
只用到了c1一个字段,c2和c3用于排序,没有filesort
8.2)
EXPLAIN SELECT * FROM test03 WHERE c1 = ‘a1’ AND c5 = ‘a5’ ORDER BY c3,c2;
会出现filesort,因为我们的索引是1234,他没有按照顺序来,2,3颠倒了
9)
EXPLAIN SELECT * FROM test03 WHERE c1 = ‘a1’ AND c2 = ‘a2’ ORDER BY c2,c3;
10)
EXPLAIN SELECT * FROM test03 WHERE c1 = ‘a1’ AND c2 = ‘a2’ AND c5 = ‘a5’ ORDER BY c2,c3;
用c1,c2两个字段,但是c2,c3用于排序,无filesort
11)
EXPLAIN SELECT * FROM test03 WHERE c1 = ‘a1’ AND c2 = ‘a2’ AND c5 = ‘a5’ ORDER BY c3,c2;
没有出现filesort,因为c2是一个常量,与8.2对比
12)
EXPLAIN SELECT * FROM test03 WHERE c1 = ‘a1’ AND c4 = ‘a4’ GROUP BY c2,c3;
13)
EXPLAIN SELECT * FROM test03 WHERE c1 = ‘a1’ AND c4 = ‘a4’ GROUP BY c3,c2;

定值、范围还是排序,一般order by是给个范围
Group by基本上都需要进行排序,会有临时表产生
一般性建议
1、对于单键索引,尽量选择针对当前query过滤性更好的索引
2、在选择组合索引的时候,当前query中过滤性最好的字段在索引字段顺序中,位置越靠前越好
3、在选择组合索引的时候,尽量选择可以能够包含当前query中的where子句中更多字段的索引
4、尽可能通过分析统计信息和调整query的写法来达到选择合适索引的目的
3、查询截取分析
(1)查询优化
永远小表驱动大表,类似嵌套循环nested loop

Exists:
Select * from table where exists(subquery);
该语法可以理解为:将主查询的数据,放到子查询中做条件验证,根据验证结果(true或false)来决定主查询的数据结果是否得以保留
提示:
1、exists(subquery)只返回true或者false,因此子查询中的select*也可以是select1或者select’X’,官方说法是实际执行是会忽略select清单,因此没有区别
2、Exists子查询的实际执行过长可能经过了优化而不是我们理解上的逐条对比,如果担忧效率问题,课进行实际检验以确定是否有效率问题
3、Exists子查询往往也可以用条件表达式、其他子查询或者join来替代,何种最优需要具体问题具体分析
Order by关键字优化
1、order by子句,尽量使用index方式排序,避免使用filesort方式排序
1、建表SQL
#建表SQL
DROP TABLE IF EXISTS tblA;

CREATE TABLE tblA (
#id int PRIMARY KEY NOT NULL AUTO_INCREMENT,
age INT ,
birth TIMESTAMP NOT NULL
) ENGINE=INNODB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

#添加语句
INSERT INTO tblA(age,birth)VALUES (22,NOW());
INSERT INTO tblA(age,birth)VALUES (23,NOW());
INSERT INTO tblA(age,birth)VALUES (24,NOW());

#建立索引
CREATE INDEX idx_A_ageBirth ON tblA(age,birth)
#查看索引
SHOW INDEX FROM tblA

SELECT * FROM tblA;

#查看慢查询日志是否开启
SHOW VARIABLES LIKE ‘%slow_query_log%’;

#开启慢查询日志(临时开启)
SET GLOBAL slow_query_log = 1;

#永久开启,修改my.cnf文件,[mysqld]下增加或修改参数,之后重启
slow_query_log = 1
slow_query_log_file=D:\bigdataENV\MySql\mysql5.5\DATA\DESKTOP-975BPHT-slow.log

#查询默认时长
SHOW VARIABLES LIKE ‘%long_query_time%’;

#修改阈值时间
SET GLOBAL long_query_time = 3;

#查看修改时长
SHOW GLOBAL VARIABLES LIKE ‘%long_query_time%’;

#记录慢SQL并后续分析,
SELECT SLEEP(3)

#查询当前系统中有多少条慢查询记录
SHOW GLOBAL STATUS LIKE ‘%slow_queries%’;

#工作常用参考
mysqldumpslow -s r -t 10 D:\bigdataENV\MySql\mysql5.5\DATA\DESKTOP-975BPHT-slow.log;

#建立索引
CREATE INDEX idx_test_c1234 ON test03(c1,c2,c3,c4);

#问题,我们创建了符合索引,根据索引情况idx_test03_c1234根据以下SQL分析下索引使用情况
EXPLAIN SELECT * FROM tblA WHERE age > 20 ORDER BY age;
EXPLAIN SELECT * FROM tblA WHERE age > 20 ORDER BY age,birth;
EXPLAIN SELECT * FROM tblA WHERE age > 20 ORDER BY birth;
EXPLAIN SELECT * FROM tblA WHERE age > 20 ORDER BY birth,age;

2、Case
1、
2、
3、Mysql支持二种方式的排序,filesort和index,index效率高
他指mysql扫描索引本身完成排序,filesort方式效率较低

4、Order by满足两种情况,会只用index方式排序
(1)Order by语句使用索引最左前列
(2)使用where子句与order by子句条件列组合满足索引最左前列
2、尽可能在索引列上完成排序操作,遵照索引建的最佳左前缀
3、如果不在索引列上,filesort有两种算法:mysql就要启动双路排序和单路排序
1、双路排序
(1)Mysql4.1之前是使用双路排序,字面意思就是两次扫描磁盘,最终得到数据,读取行指针和orderby列,对他们排序,然后扫描已经排序好的列表,按照列表中的值重新从列表中的值重新从列表中读取对应的数据输出
(2)从磁盘取排序字段,在buffer进行排序,再从磁盘取其他字段
2、取一批数据,要对磁盘进行了两次扫描,众所周知,I/O是很耗时的,所以在mysql4.1之后,出现了第二种改进的算法,就是单路算法
3、单路排序
从磁盘读取查询需要的所有列,按照order by列在buffer对他们进行排序,然后扫描排序后的列表进行输出,他的效率更快一些,避免了第二次读取数据,并且把随机IO变成了顺序IO,但是他会使用更多的空间,因为他把每一行都保存在内存中共了
4、结论及申出的问题
(1)由于单路是后出的,总体而言好过双路
(2)但是单路有问题
①在sort_buffer中,方法B比方法A要多占用很多空间,因为方法B是吧所有字段都取出,所以有可能取出的数据的总大小超出了sort_buffer的容量,导致每次只能取sort_buffer容量大小的数据,进行排序(创建tmp文件,多路合并),排完在取sort_buffer容量大小,在排···从而多次I/O
②本来想省一次I/O操作,反而导致了大量的I/O操作,反而得不偿失
4、优化策略
1、增大sort_buffer_size参数的设置
2、增大max_length_for_sort_data参数的 设置
3、Why(提高order by的速度)
1、order by时select * 是一个大忌,只query需要的字段,这点非常重要,在这里的影响的是:
(1)当query的字段大小总和小于max_length_for_sort_data而且排序字段不是TEXT|BLOB类型时,会用改进后的算法——单路算法排序,否则用老算法——多路排序
(2)两种算法的数据都有可能超出sort_buffer的容量,超出之后,会创建tmp文件进行合并排序,导致多次I/O,但是用单路排序算法的风险会更大一些,所以要提高sort_buffer_size
2、尝试提高sort_buffer_size
不管用那种算法,提高这个参数都会提高效率,当然,要根据系统的能力去提高,因为这个参数是针对每个进程的
3、尝试提高max_length_for_sort_data
提高这个参数,会增减用改进算法的概率,但是如果设的太高,数据总统量超出sort_buffer_size的概率就会增大,明显症状是高的磁盘I/O活动和低的处理器使用率
5、小总结

Group by关键字优化
1、group by实质上是先排序后进行分组,遵照索引键的最佳左前缀
2、当无法使用索引列,增大max_length_for_sort_data参数的设置+增大sort_buffer_size参数的设置
3、Where高于having,能写where限定的条件就不要去having限定了
(2)慢查询日志
1、是什么
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进行全面分析
2、怎么玩
1、说明
默认情况下,mysql数据库没有开慢查询日志,需要我们手动来设置这个参数
当然,如果不是调优需要的话,一般不建议启动该参数,因为开启慢查询日志会或多或少带一定的想能影响,慢查询日志支持将日志记录写入文件
2、查看是否开启及如何开启
默认:show variables like ‘%slow_query_log%’;
默认情况下slow_query_log值为OFF,表示慢查询日志是禁用的
可以通过设置slow_query_log的值来开启
show variables like ‘%slow_query_log%’;

开启:set global slow_query_log = 1
使用set global slow_query_log = 1 开启了慢查询日志,只对当前数据库生效;
如果mysql重启后则会失效

如果要永久生效,就必须修改配置文件my.cnf(其他系统变量也是如此)
修改my.cnf文件,[mysqld]下增加或修改参数
Slow_query_log和slow_query_log_file后,然后重启mysql服务器,也即将如下两行配置进my.cnd文件
slow_query_log = 1
slow_query_log_file=D:\bigdataENV\MySql\mysql5.5\data\DESKTOP-975BPHT-slow.log
关于慢查询的参数slow_query_log_file,他指定慢查询日志文件的存刚路径,系统默认会给一个缺省的文件host_name_slow.log(如果没有指定参数slow_query_log_file的话)
3、那么开启了慢查询日志后,什么样的SQL才会记录到慢查询日志里面呢
这个是由参数long_query_time控制,默认情况下long_query_time的值为10秒
命令:show variables like ‘%long_query_time%’;

4、Case
1、查看当期那多少秒算慢:show variables like ‘%long_query_time%’;
2、是指慢的阈值时间:set global long_query_time = 3;
使用命令:set global long_query_time = 3;
修改为阈值到3秒钟就是慢sql

3、为什么设置后看不出时间
1、需要重新连接或新开一个会话才能看到修改值
show variables like ‘long_query_time’;
2、或者show global variables like ‘long_query_time’;
4、记录慢SQL并后续分析
select sleep(4);

5、查询当前系统中有多少条慢查询记录
show global status like ‘&&slow_queries’;

5、配置版
【mysqld】下配置
slow_query_log = 1;
slow_query_log_file = D:\bigdataENV\MySql\mysql5.5\data\DESKTOP-975BPHT-slow.log;
long_query_time = 3;
long_output = file;

3、日志分析工具(mysqldumpslow)
在生产环境中,如果要手工分析日志,查找、分析SQL,显然是个体力活,mysql提供了日志分析工具:MySQLdumpslow
1、查看mysqldumpslow的帮助信息

s:是表示按照何种方式排序;
c:访问次数
l:锁定时间
r:返回记录
t:查询时间
al:平均锁定时间
ar:平均返回记录数
at:平均查询时间
t:即为返回其那面多少条的数据
g:后边搭配一个正则匹配模式,大小写不敏感的
2、工作常用参考
得到返回记录集最多的10个SQL
mysqldumpslow -s r -t 10 D:\bigdataENV\MySql\mysql5.5\data\DESKTOP-975BPHT-slow.log;

得到访问次数最多的10个SQL
mysqldumpslow -s c -t 10 D:\bigdataENV\MySql\mysql5.5\data\DESKTOP-975BPHT-slow.log;

得到按照时间排序的前10条里面含有做链接的查询语句
mysqldumpslow -s r -t 10 -g “left join” D:\bigdataENV\MySql\mysql5.5\data\DESKTOP-975BPHT-slow.log;

另外建议在使用这些命令时结合|和more使用,否则有可能出现爆屏情况
mysqldumpslow -s r -t 10 D:\bigdataENV\MySql\mysql5.5\data\DESKTOP-975BPHT-slow.log | more;

(3)批量数据脚本
往表里插入1000W数据
1、建表
#新建库
CREATE DATABASE bigData;
USE bigData;

#建表dept
CREATE TABLE dept(
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,
dname VARCHAR(20) NOT NULL DEFAULT “”,
loc VARCHAR(13)NOT NULL DEFAULT""
)ENGINE = INNODB DEFAULT CHARSET = GBK;

#建表emp
CREATE TABLE emp(
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
empno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,/编号/
ename VARCHAR(20) NOT NULL DEFAULT “”,/名字/
job VARCHAR(9)NOT NULL DEFAULT"",/工作/
mgr MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,/上级编号/
hiredata DATE NOT NULL ,/入职时间/
sal DECIMAL(7,2) NOT NULL,/薪水/
comm DECIMAL(7,2) NOT NULL,/红利/
deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0/部门编号/
)ENGINE = INNODB DEFAULT CHARSET = GBK;

2、设置参数log_bin_trust_function_creators
创建函数,加入报错:this function has none of DETERMINISTIC…
#由于开启过慢查询日志,因为我们开启了bin-log我们必须为我们的function指定一个参数
临时方法:mysql重启,就会失效
SHOW VARIABLES LIKE “log_bin_trust_function_creators”;
set global log_bin_trust_function_creators = 1;
永久方法:
Windows下my.ini[mysqld]加上log_bin_turst_function_creators= 1
Linux下:/etc/my.cnf[mysqld]加上log_bin_trust_function_creators= 1
3、创建函数,保证每条数据都不同
①随机产生字符串
DELIMITER C R E A T E F U N C T I O N r a n d s t r i n g ( n , I N T ) R E T U R N S V A R C H A R ( 255 ) B E G I N D E C L A R E c h a r s s t r V A R C H A R ( 100 ) D E F A U L T ′ a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z ′ ; D E C L A R E r e t u r n s t r V A R C H A R ( 255 ) D E F A U L T ′ ′ ; D E C L A R E i I N T D E F A U L T 0 ; W H I L E i < n D O S E T r e t u r n s t r = C O N C A T ( r e t u r n s t r , S U B S T R I N G ( c h a r s s t r , F L O O R ( 1 + R A N D ( ) ∗ 52 ) , 1 ) ) ; S E T i = i + 1 ; E N D W H I L E ; R E T U R N r e t u r n s t r ; E N D CREATE FUNCTION rand_string(n,INT) RETURNS VARCHAR(255) BEGIN DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; 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 CREATEFUNCTIONrandstring(n,INT)RETURNSVARCHAR(255)BEGINDECLAREcharsstrVARCHAR(100)DEFAULTabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;DECLAREreturnstrVARCHAR(255)DEFAULT;DECLAREiINTDEFAULT0;WHILEi<nDOSETreturnstr=CONCAT(returnstr,SUBSTRING(charsstr,FLOOR(1+RAND()52),1));SETi=i+1;ENDWHILE;RETURNreturnstr;END

#假如要删除
drop function rand_string;

②随机产生部门编号
delimiter c r e a t e f u n c t i o n r a n d n u m ( ) r e t u r n s i n t ( 5 ) b e g i n d e c l a r e i i n t d e f a u l t 0 ; s e t i = f l o o r ( 100 + r a n d ( ) ∗ 10 ) ; r e t u r n i ; e n d create function rand_num() returns int(5) begin declare i int default 0; set i = floor(100 + rand() * 10); return i; end createfunctionrandnum()returnsint(5)begindeclareiintdefault0;seti=floor(100+rand()10);returni;end

#假如要删除
drop function rand_num;

4、创建存储过程
(1)创建往emp表中插入数据的存储过程
DELIMITER KaTeX parse error: Expected 'EOF', got '#' at position 99: …INT DEFAULT 0; #̲set autocommit …

(2)创建往demp表中插入数据的存储过程
DELIMITER C R E A T E P R O C E D U R E i n s e r t d e p t ( I N S T A R T I N T ( 10 ) , I N m a x n u m I N T ( 10 ) ) B E G I N S E T a u t o c o m m i t = 0 ; R E P E A T S E T i = i + 1 ; I N S E R T I N T O d e p t ( d e p t n o , d n a m e , l o c ) V A L U E S ( ( S T A R T + i ) , r a n d s t r i n g ( 10 ) , r a n d s t r i n g ( 8 ) ) ; U N T I L i = m a x n u m E N D R E P E A T ; C O M M I T ; E N D CREATE PROCEDURE insert_dept(IN START INT(10),IN max_num INT(10)) BEGIN SET autocommit = 0; REPEAT SET i = i + 1; INSERT INTO dept (deptno,dname,loc) VALUES ((START + i),rand_string(10),rand_string(8)); UNTIL i = max_num END REPEAT; COMMIT; END CREATEPROCEDUREinsertdept(INSTARTINT(10),INmaxnumINT(10))BEGINSETautocommit=0;REPEATSETi=i+1;INSERTINTOdept(deptno,dname,loc)VALUES((START+i),randstring(10),randstring(8));UNTILi=maxnumENDREPEAT;COMMIT;END

5、调用存储过程
(1)Dept
delimiter ;#将$$分隔符更改为分号
call insert_dept(100,10);#从100开始插入10条数据
(2)Emp
delimiter ;
call insert_emp(100000,500000);

(4)Show profile
1、是什么:
是mysql提供可以用来分析当前会话中语句执行的资源消耗情况,可以用于SQL的调优的测量
2、官网:
http://dev.mysql.com/doc/refman/5.5/en/show-profile.html
3、默认情况下,参数处于关闭状态,并保存最近15次的运行结果
4、分析步骤
(1)是否支持,看看当期的mysql版本是否支持
Show variables like ‘profiling’;#默认是关闭,使用前需要开启
或者show variables like ‘profiling%’;
(2)开启功能,默认是关闭,使用前需要开启
Show variables like ‘profiling’;#查看是够开启
Set profiling = on;#开启profiling
(3)运行SQL(每条sql后台都会被记录)
①Select * from dept;
②Select * from emp group by id%10 limit 150000;
③Select * from emp group by id%10 order by 5;
(4)查看结果,show profiles;
Show profiles;#记录每条数据的运行时间及操作
(5)诊断SQL,查询一条sql的完整过程,show profile cpu,block io for query上一步前面的问题SQL数字号码;
①show profile cpu,block io for query 3;(3是数字号码)红色可以更换
②参数备注
1)All:显示所有的开销信息
2)BLOCK IO:显示块IO相关开销
3)CONTEXT SWITCHES:上下文切换相关开销
4)CPU:显示CPU相关开销信息
5)IPC:显示发送和接收相关开销信息
6)MEMORY:显示内存相关开销信息
7)PAGE FAULTS:显示页面错误相关开信息
8)SOURCE:显示和source_function,source_file,source_line相关的开销信息
9)SWAPS:显示交换次数相关开销的信息
(6)入场开发需要注意的结论
①Converting help to MyISAM查询结果太大,内存都不够用了往磁盘上搬了
②Creating tmp table 创建临时表
1)拷贝数据到临时表
2)用完在删除
③Coping to tmp table on disk 把内存中临时表复制到磁盘,危险!
④Locked
(5)全局查询日志
1、配置启用
在mysql的my.cnf中,设置如下:
#开启
general_log = 1
#记录日志文件的路径
general_log_file = /path/logfile
#输出格式
log_output = FILE

2、编码启用
命令:
·set global general_log = 1;
·set global log_output = ‘TABLE’;

此后,你所编写的sql语句,将会记录到mysql库里的general_log表,可以用下面的命令查看
select * from mysql.general_log;

3、永远不要在生产环境开启这个功能
4、Mysql锁机制
(1)概述
1、定义
锁是计算机协调多个进程或线程并发访问某一资源的机制

在数据库中,除传统的计算资源(如CPU、RAM、I/O等)的争用以外,数据也是一种供许多用户共享的资源,如何保证数据并发访问的一致性,有效性是所有数据库必须解决的一个问题,锁冲突也是影像数据并发访问心梗的一个重要因素,从这个角度来说,锁岁数据库而言显得尤其重要,也更加复杂。
2、生活购物
打个比方,我们得到淘宝上买一件商品,商品只有一件库存,这个时候如果还有另一个人买,那么如何解决是你买到手还是另一个人买到的问题?

这里肯定要用到事务,我们先从库存表中取出物品数量,然后加入订单,付款后插入付款表信息,然后更新商品数量,在这个过程中,使用锁可以对有限的资源进行保护,解决隔离和并发的矛盾
3、锁的分类
(1)从对数据操作的类型(读/写)分
读锁(共享锁):针对同一份数据,多个读操作可以同时进行而不会互相影响
写锁(排他锁):当前写操作没有完成前,他会阻断其他写锁和读锁
(2)从对数据操作的粒度分
表锁
行锁
(2)三锁(开销、加锁速度、死锁、粒度、并发性能 只读就具体应用的特点来说哪种锁更合适)
①表锁(偏读)
1、特点
偏向MyISAM存储引擎,开销小,加锁块,无死锁;锁定粒度大,发生锁冲突的概率不高,并发度最低。
2、案例分析
(1)建表SQL
#【表级锁分析–建表SQL】
USE test;
CREATE TABLE mylock(
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20)
)ENGINE MYISAM;

INSERT INTO mylock(NAME) VALUES (‘a’);
INSERT INTO mylock(NAME) VALUES (‘b’);
INSERT INTO mylock(NAME) VALUES (‘c’);
INSERT INTO mylock(NAME) VALUES (‘d’);
INSERT INTO mylock(NAME) VALUES (‘e’);

SELECT * FROM mylock;

【查看表上加过的锁】
SHOW OPEN TABLES;
【手动增加表锁】
LOCK TABLE 表名字1 read,表名字2 WRITE;
【释放表】
UNLOCK TABLES;

(2)加读锁(lock table tname read;)
我们为mylock表加read锁(读则赛写例子)
Session_1 Session_2
获得表没有lock的READ索性
连接终端
当前session可以查询该表记录
其他session也可以查询该表的记录

当前session不能查询其他没有锁定的表
其他session可以查询或者更新未锁定的表

当前session中插入或者更新锁定的表都会提示错误
其他session插入或者更新锁定表会一直等待获得锁:

释放锁
Session2获得锁,插入操作完成:

(3)加写锁(lock table tname write;)
我们为mylock表加write锁(MyISAM存储引擎的写阻塞读例子)
session_1 session_2
获得表没有lock的write锁定
带session_1开启写锁后,session_2在连接终端
当前session对锁定表的查询+更新+插入操作都可以执行:
其他session对锁定表的查询被阻塞,需要等待锁被释放

备注:如果可以,请换成不同的id来测试,因为mysql聪明,有缓存,第2次的条件会从缓存取得,影响锁效果演示
释放锁
session_2获得锁,查询返回:

3、案例结论
MyISAM在执行查询语句(select)前,会自动给设计的所有表加读锁,在执行增删改操作前,会自动给涉及的表加锁。
Mysql的表级锁有两种模式:
1、表共享读锁(table read lock)
2、表独占写锁(table wirte lock)
锁类型 可否兼容 读锁 写锁
读锁 是 是 否
写锁 是 否 否
结论:
集合上表,所以对MyISAM表进行操作,会有以下情况:
1、对MyISAM表的读操作(加读锁),不会阻塞其他进程对同一表的读请求,但会阻塞对同一表的写请求,只有当读锁释放后,才会执行其他进程的写操作
2、对MyISAM表的写操作(加写锁),会阻塞其他金层对同一表的读和写操作,只有当写锁释放后,参会执行其他进程的读和写操作
简而言之,就是读锁会阻塞写,但是不会堵塞读,而写锁则会把读和写都堵塞

4、表锁分析
【看看那些表被加锁了】
show open tables;
【如何分析表锁定】
可以通过检查table_locks_waited和table_locks_immediate状态变量来分析系统上的表锁定:
SQL:show status like ‘table%’;

这里有两个恶状态变量记录mysql内部表级锁定情况,两个变量说明如下:;
table_locks_immediate:产生表级锁定的次数,表示可以立即获取锁定查询次数,每立即获取锁值加1;
table_locals_waited:出现表级争用而发生等待的次数(不能立即获取锁的次数,每等待一次锁值加1),此值高则说明存在着较严重的表级锁争用情况;

此外,MyISAM的读写锁调度是写优先,这也是myisam不适合做写为主表的引擎,因为写锁后,其他线程不能做任何操作,大量的更新会使查询很那得到锁,从而造成永远阻塞

②行锁(偏写)
1、特点
(1)偏向InnoDB存储引擎,开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高
(2)InnoDB与MyISAM的最大不同有两点;一是支持事务(transaction);二是采用了行级锁
2、复习老知识(支持行锁事务)
1、事务(transaction)及其ACID属性
事务是由一组SQL语句组成的逻辑处理单元,事务具有以下4个属性,通常简称为事务的ACID属性
1、原子性(Atomicity):事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行
2、一致性(Consistent):在事务开始和完成时,数据都必须保持一状态,这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性;事务结束时,所有的内部数据结构(如B树索引或双向链表)也都是正确的
3、隔离性(Isolation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立环境执行”,这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然
4、持久性(Durable):事务完成之后,他对于数据的修改是永久性的,及时出现系统故障也能够保持
2、并发事务处理带来的问题
(1)更新数据(lost update)
当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事物的存在,就会发生丢失更新问题–最后的跟新覆盖了由其他事物所做的更新

例如,两个程序员修改同一java文件,每程序员独立的更改其副本,然后保存更改后的副本,这样就覆盖了原始文档,最后保存其更改的编辑人员覆盖请一个程序员所做的更改

如果在一个程序员完成并提交事务之前,另一个程序员不能访问同一文件,则可避免此问题
(2)脏读(dirty reads)
一个事务正在对一条数据记录做修改,在这个事务完成并提交前,这条记录的数据就处于不一致状态;这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”数据,并据此做进一步的处理,就会产生未提交的数据依赖关系,这种现象被形象的叫做“脏读”

一句话,事务A读取到了事务B已修改但尚未提交的数据,还在这个数据基础上做了操作,此时,如果B事务回滚,A读取的数据无效,不符合一致性要求
(3)不可重复读(Non-Repeatable reads)
一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了改变、或某些记录已经被删除了!这种现象就叫做“不可重复读”
一句话:事务A读取到了事务B已经提交的修改数据,不符合隔离性
(4)幻读(phantom reads)
一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他数据插入了满足其查询条件的新数据,这种现象就称为“幻读”

一句话:事务A读取到了事务B提交的新增数据,不符合隔离性
多说一句:幻读和脏读有点儿类似

  脏读是事务B里面修改了数据
  幻读是事务B里面新增了数据

3、事务隔离级别
脏读、不可重复读、幻读,其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决
读数据一致性即允许的并发副作用隔离级别 读数据一致性 脏读 不可重复 幻读
为提交读(read uncommitted) 最低级别,只能保证不读取物理上损坏的数据 是 是 是
已提交读(read committed) 语句级 否 是 是
可重复读(repeatable read) 事务级 否 否 是
可序列化(serializable) 最高级别,事务级 是 是 是

数据库的事务隔离越严格,并发副作用越小,但扶持的代价也就越大,因为事务隔离实质上就是使事务在一定程度上“串行化”进行,这显然与“并发”是矛盾的,同时,不同的应用对读一致性和事务隔离程度的要求也是不同的,不如许多应用对“不可重复读”和“幻读”并不敏感,可能更关心数据并发访问的能力

常看当前数据库的事务隔离界别:show variables like ‘tx_isolation’;
3、案例分析
(1)建表SQL
USE test;
CREATE TABLE test_innodb_lock (
a INT (11),
b VARCHAR (16)
) ENGINE = INNODB;

INSERT INTO test_innodb_lock VALUES(1,‘b2’);
INSERT INTO test_innodb_lock VALUES(3,‘3’);
INSERT INTO test_innodb_lock VALUES(4,‘4000’);
INSERT INTO test_innodb_lock VALUES(5,‘5000’);
INSERT INTO test_innodb_lock VALUES(6,‘6000’);
INSERT INTO test_innodb_lock VALUES(7,‘7000’);
INSERT INTO test_innodb_lock VALUES(8,‘8000’);
INSERT INTO test_innodb_lock VALUES(9,‘9000’);
INSERT INTO test_innodb_lock VALUES(1,‘b1’);

CREATE INDEX test_innodb_a_ind ON test_innodb_lock(a);
CREATE INDEX test_innodb_lock_b_ind ON test_innodb_lock(b);

EXPLAIN SELECT * FROM test_innodb_lock;
(2)行锁定基本演示
行锁基本演示
session_1 session_2

更新表并没有提交
session_2只能被阻塞

提交更新
解除阻塞,更新并正常提交

Commit提交 Commit提交
下面试试1号会话会更新 下面试试2号会话会更新

(3)无索引行锁升级为表锁
原因:varchar数据类型一定要加单引号,否则,虽然mysql底层会有数据类型自动转换,但是,建立的索引就会自动失效,会造成sql语句阻塞
(4)间隙锁危害
间隙锁带来的插入问题

         session_1	session_2
产生阻塞,暂时不能插入,

Commit; 阻塞解除,完成插入

【什么是间隙锁】
当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,innoDB会给符合条件的已有数据及记录的索引项加锁,对于键值在条件范围内但并不存在的记录,叫做“间隙”
InnoDB也会对这个“间隙”加锁,这种锁机会就是所谓的间隙锁(next-key锁)
【危害】
因为query执行过程中通过范围查找的话,他会锁定整个范围内所有的 索引键值,及时这个键值并不存在
间隙锁有一个比较致命的弱点,就是当锁定一个范围键值之后,即使某些不存在的键值也会被无辜的锁定,而造成在锁定的时候无法插入锁定键值范围内的任何数据,在某些场景下这可能会对性能造成跟大的危害
(5)面试题常考如何锁定一行
如何锁定一行???

4、案例结论
InnoDB存储引擎由于实现了行级锁定,虽然在锁定机制的实现方面所带来的的性能损耗可能比表级锁定会更高一些,但是在整体并发处理能力方面远远优于MyISAM的表级锁定,当系统并发量较高的时候,InnodbDB的整体性能和MyISAM相比就会有比较明显的优势了

但是,InnoDB的行级锁定同样也有其脆弱的一面,当我们使用不当的时候,可能会让InnoDB的整体性能表现不仅不能比MyISAM高,甚至可能会更差
5、行锁分析
【如何分析行锁定】
通过检查innodb_row_lock状态变量来分析系统上的行锁的争夺情况
Show status like ‘innodb_row_lock’;

对各个状态量的说明如下:
innodb_row_lock_current_waits:当前正在等待锁定的数量
innodb_row_lock_time:从系统启动到现在锁定总时间的长度
innodb_row_lock_time_avg:每次等待所花的平均时长
innodb_row_lock_time_max:从系统启动到现在等待最长的一次说话的时间
innodb_row_lock_waits:系统启动后到现在总共等待的次数

当等待次数很高,而且每次等待时长也不小的时候,我们就需要分析系统中为什么会有如此多的等待,然后根据分析结果着手指定优化计划
6、优化建议
(1)尽可能让所有数据检检索都通过索引来完成,避免无索引行锁升级为表锁
(2)合理设计索引,尽量缩小锁的范围
(3)尽可能减少检索,避免间隙锁
(4)尽量控制事务大小,减少锁定资源量和时间长度
(5)尽可能低级别事务隔离
③页锁
开销和加锁时间介于表锁和行锁之间;会出现死锁;锁定粒度结余表锁和行锁之间,并发度一般(了解一下即可)
5、主从复制
(1)复制的基本原理
Slave会从master读取binlog来进行数据同步

MySQL复制过程分成三步
1、master将改变记录到二进制日志(binary log),这些记录过程叫做二进制日志事件,binary log event;
2、Slave将master的binary log events拷贝到它的中继日志(relay log);
3、Salve重做中继日志中的事件,将该表应用到自己的数据库中,MySQL复制是一步的且串行的
(2)复制的基本原则
1)每个slave只有一个master
2)每个slave只能有一个唯一的服务器ID
3)每个master可以有多个slave
(3)复制的最大问题
网络会有延时
(4)一主一从常见配置
1)mysql版本一直且后台以服务运行
2)主从都配置在[mysqld]节点下,都是小写
3)主机修改my.ini配置文件
1、主服务器唯一ID【必须】
server-id = 1
2、启用二进制日志【必须】
log-bin = 自己的本地路径/mysqlbin
log-bin = D:\bigdataENV\MySql\mysql5.5\data\mysqlbin
3、启用错误日志【可选】
log-err = 自己的本地路径/mysqlerr
log-bin = D:\bigdataENV\MySql\mysql5.5\data\mysqlerr
4、根目录【可选】
basedir = 自己的本地路径
basedir = D:\bigdataENV\MySql\mysql5.5
5、临时目录【可选】
tmpdir = 自己的本地路径
tmpdir = D:\bigdataENV\MySql\mysql5.5
6、数据目录【可选】
datadir = “自己的本地路径”/data/
datadir = D:\bigdataENV\MySql\data
7、read-only = 0
主机,读写都可以
8、设置不要复制的数据库【可选】
binlog-ignore-db = mysql
9、设置需要复制的数据库【可选】
binlog-do-db = 需要复制的主数据库名字
4)从机修改my.cnf配置文件
1、从服务器唯一ID【必须】
2、启用二进制日志【可选】
5)因都修改过配置,请主机+丛机都重启后台mysql服务
6)主从机都关闭防火墙
1、window手动关闭
2、Linux防火墙 service iptables stop
7)在windows主机上建立战虎并授权slave
1、用cmd里面mysql执行授权操作
GRANT REPLICATION SLAVE ON . TO ‘zhangsan’@‘从机器数据库ip’ IDENTIFIED BY ‘123456’
2、刷新
FLUSH PRIVILEGES;
3、查看master状态
SHOW MASTER STATUS;

File:二进制文件
Position:从什么位置开始复制
binlog_do_db:需要复制的数据库
binlog_ignore_db:不需要复制的数据库
4、执行完此步骤之后不要在操作主服务器MySQL,反之主服务器状态值变化
8)在linux丛机上配置需要复制的主机
1、mysql中执行
#配置需要复制的master
CHANGE MASTER TO MASTER_HOST = ‘主机ip’,
MASTER_USER = ‘as’,
MASTER_PASSWORD = ‘123’,
MASTER_LOG_FILE = ‘mysqlbin.具体数字’,
MASTER_LOG_POS = ‘具体值’;

#之后启动从服务器复制功能:
start slave;

2、SHOW SLAVE STATUS\G;
①下面两个参数都是Yes,则说明主从配置成功!!!
②Slave_IO_Running:Yes
③Slave_SQL_Running:Yes

9)主机新建库、新建表、insert记录、丛机复制
10)如何停止从服务复制功能
Stop slave;

----------分析-----------------
1、观察,至少跑1天,看看生产的慢SQL情况
2、开启慢查询日志,设置阈值,比如超过5秒钟的就是慢SQL,并将它抓取出来
3、Explain+慢SQL分析
4、Show profile
5、运维经理 or DBA,进行SQL数据库服务器的参数调优

===总结
1、慢查询的开启并捕获哦
2、Explain+慢SQL分析
3、Show profile查询SQL在mysql服务器里面的执行细节和生命周期情况
4、SQL数据库服务器的参数调优

你可能感兴趣的:(Mysql高级)