Mysql高级

   1 mysql高级
   2     ”练武不练功,到老一场空,认认真真练一遍,今天多学一门技术,明天少说一句求人的话;高新12k以上的岗位一定会靠你sql“
   3     “DBa每天做索引重建工作,锁表重建索引”
   4     “物理删除改为逻辑删除,其一,大数据时代保留数据,以便分析;其二,为了索引”
   5     “运维问题,数据说话,理工类工作严禁我觉得”
   6     “程序员分两种:15k以下的只能完成功能;撑死优秀完成功能15-20;20以上的不但能完成功能也能搞定性能”
   7     
   8     1、mysql的架构介绍 
   9         1.1Mysql简介
  10             1.1.1概述
  11                 
  12             1.1.2高级Mysql(完整的mysql优化需要很深的功底,大公司甚至有专门的DBa写上述)
  13                 1.1.2.1mysql内核
  14                 1.1.3sql优化工程师
  15                 1.1.4mysql服务器优化
  16                 1.1.5各种参数常量设定
  17                 1.1.6查询语句优化
  18                 1.1.7主从复制
  19                 1.1.8软硬件升级
  20                 1.1.9容灾备份
  21                 1.1.10sql编程
  22             
  23         1.2Mysqllinux版安装
  24             1.2.1 mysql5.5rpm
  25                 1.2.1.1 下载地址
  26                     http://dev.mysql.com/downloads/mysql/,下载ga版
  27                 1.2.1.2 检查当前系统是否安装过mysql
  28                     rpm -qa|grep -i mysql
  29                 1.2.1.3 安装mysql服务端(注意提示)
  30                     cd /opt (linux尽量不含中文不含空格)
  31                     rpm -ivh MySQL-server-5.5.48-1.linux2.6.i386.rpm
  32                     注意修改密码
  33                 1.2.1.4 安装mysql客户端
  34                     rpm -ivh MySQL-client-5.5.48-1.linux2.6.i386.rpm
  35                 1.2.1.5 查看mysql安装时创建的mysql用户和mysql组
  36                     ps -ef|grep mysql
  37                     cat /etc/passwd |grep mysql
  38                     cat /etc/group |grep mysql
  39                     mysqladmin --version
  40                 1.2.1.6 mysql服务的启+  41                     service mysql start|stop|restart   
  42                     ps -ef|grep mysql
  43                     top 可以从服务器启动持续时间一定判断该公司研发部的水准,经常关的要注意
  44                 1.2.1.7 mysql服务启动后,开始连接
  45                     /usr/bin/mysqladmin -u root password 123456
  46                     首次连接成功
  47                     注意这里,因为Mysql默认没有密码,所以这里我们没有输入密码就直接连上了
  48                     按照安装server中的提示修改登录密码
  49                 1.2.1.8 自启动mysql服务
  50                     chkconfig mysql on
  51                     chkconfig --list | grep mysql
  52                     cat  /etc/inittab inittab is no longer used when using systemd.
  53                     ntsysv 图形显示开机启动
  54                 1.2.1.9 修改配置文件位置
  55                     cd /usr/share/mysql/
  56                     cp my-huge.cnf /etc/my.cnf
  57                 1.2.1.10 修改字符集合数据存储路径
  58                     show variables like 'character%';
  59                     show variables like '%char%';
  60                     默认客户端和服务器都用了latin1所以会乱码。5.7是character_set_server=utf8一个,和5.5有区别
  61                     在字符集修改之前创建的库没有收到配置文件影响,最好安装mysql之后立即修改字符集
  62                 1.2.1.11 mysql的安装位置                  
  63                     在linux下查看安装目录 ps -ef | grep mysql
  64                     /var/lib/mysql #数据库文件的存放位置
  65                     /usr/share/mysql  #主管配置文件的目录
  66                     /usr/bin    #相关命令
  67                     /etc/init.d/mysql #启停脚本相关
  68                
  69         1.3Mysql配置文件
  70             主要配置文件:
  71             1.3.1 二进制日志log-bin
  72                 主要用于主从复制
  73             1.3.2 错误日志log-error 
  74                 -默认是关闭的,记录严重的警告和错误信息,每次启动和关闭时候的详细信息
  75                 
  76             1.3.3 查询日志log
  77                 -默认是关闭的,记录查询的sql语句,如果开启会减低mysql的整体性能,因为记录日志也是消耗系统资源的
  78             1.3.4 数据文件
  79                 两系统
  80                     windows 
  81                         D:\devSoft\MySQLServer5.5\data目录下可以挑选很多库
  82                     linux
  83                         看看当前系统中的全部库后再进去   ls -lF|grep ^d
  84                         默认路径:/var/lib/mysql      
  85                 frm文件 
  86                     存放表结构
  87                 myd文件
  88                     存放表数据
  89                 myi 
  90                     存放索引表
  91                               
  92             1.3.5 如何配置
  93                 windows -my.ini文件
  94                     显示的配置:
  95                     log-bin=
  96                     log-error=
  97                 linux   -/etc/my.cnf文件
  98         1.4Mysql逻辑架构
  99             1.4.1总体概览
 100                 ①连接层(jdbc,native c api)
 101                 ②服务层 -业务逻辑处理层
 102                 ③引擎层 -数据存储引擎 
 103                 ④存储层 -文件存储层
 104                 插件式的存储引擎设计将查询和其它的系统任务以及数据处理提取相分离
 105                 
 106             1.4.2查询说明
 107         1.5Mysql存储引擎
 108             1.5.1 查看命令
 109                 show engines;#支持哪些存储引擎
 110                 show variables like '%storage_engine%';#当前的存储引擎
 111             1.5.2 MyISaM和InnoDB
 112                 对比项     MyISaM                                                     InnoDB
 113                 主外键     不支持                                                     支持
 114                 事务       不支持                                                        支持
 115                 行锁表     表锁,即使操作一条记录也会锁住整个表,不适合高并发操作     行锁,操作时只锁住某一行,不对其他行有影响,适合高并发
 116                 缓存       只缓存索引,不缓存真实数据                                  不仅缓存索引还要缓存真实数据,对内存要求较高,而且内存大小对性能有决定性影响
 117                 表空间     小                                                         大
 118                 关注点     性能                                                       事务
 119                 默认安装    Y                                                           Y
 120             1.5.3 阿里巴巴、淘宝用哪个
 121                 产品  价格  目标  主要功能    是否投入生产
 122                 Percona Server 免费 提供XtraDB存储引擎的包装器和其他分析工具 XtrDB 是
 123                 MariaDB     免费  
 124                 Drizzle     免费
 125     2、索引优化分析
 126         2.1性能下降SQL慢、执行时间长,等待时间长
 127             2.1.1查询语句写的烂
 128             2.1.2索引失效
 129                 单值索引
 130                     select * from user where name='';create index idx_user_name on user(name);
 131                 复合索引
 132                     select * from user where name='' and email='';create index idx_user_nameEmail on user(name,email);
 133             2.1.3关联查询太多join(设计缺陷或不得已的需求)
 134                 
 135             2.1.4服务器调优及各参数设置(缓冲、线程数等)
 136             
 137         2.2常见通用的join查询
 138             2.2.1SQL执行顺序
 139                 手写
 140                 机读
 141                 总结
 142             2.2.2join图
 143                 (画圆形图理解,直观)
 144                 内连接(共有部分)        SELECT <select_list> FROM Tablea a INNER JOIN TableB B ON a.Key = B.Key;
 145                 左连接 (aB共有+a的独有) SELECT <select_list> FROM Tablea a LEFT JOIN TableB B ON a.Key = B.Key;
 146                 右连接(aB共有+B的独有)  SELECT <select_list> FROM Tablea a RIGHT JOIN TableB B ON a.Key = B.Key;
 147                 左外链接(a独有)         SELECT <select_list> FROM Tablea a LEFT JOIN TableB B ON a.Key = B.Key WHERE B.Key IS NULL;
 148                 右外连接(B独有)         SELECT <select_list> FROM Tablea a RIGHT JOIN TableB B ON a.Key = B.Key WHERE a.Key IS NULL;
 149                 全连接(a+B)             SELECT <select_list> FROM Tablea a FULL OUTER JOIN TableB B ON a.Key = B.Key; (mysql不支持)
 150                 全外连接(独a+独B)       SELECT <select_list> FROM Tablea a FULL OUTER JOIN TableB B ON a.Key = B.Key WHERE a.Key IS NULL OR B.Key IS NULL ;
 151             2.2.3建表SQL
 152                 creat database db0629;
 153                 CREaTE TaBLE `tbl_dept`(
 154                 `id` INT(11) NOT NULL aUTO_INCREMENT,
 155                 `deptName` VaRCHaR(30) DEFaULT NULL,
 156                 `locadd` VaRCHaR(40) DEFaULT NULL,
 157                 PRIMaRY KEY(`id`)
 158                 )ENGINE=INNODB aUTO_INCREMENT=1 DEFaULT CHaRSET=utf8;
 159                 
 160                 CREaTE TaLBLE `tbl_emp`(
 161                 `id` INT(11) NOT NULL aUTO_INCREMENT,
 162                 `name` VaRCHaR(20) DEFaULT NULL,
 163                 `deptId` INT(11) DEFaULT NULL,
 164                 PRIMaRY KEY(`id`),
 165                 KEY `fk_dept_id`(`deptId`)
 166                 #CONSTRaINT `fk_dept_id` FOREIGN KEY(`deptId`) REFERENCES `tbl_dept`(`id`)
 167                 ) ENGINE=INNODB aUTO_INCREMENT=1 DEFaULT CHaRSET=utf8;
 168                 
 169                 INSERT INTO tbl_dept(deptName,locadd) VaLUES('RD',11);
 170                 INSERT INTO tbl_dept(deptName,locadd) VaLUES('HR',12);
 171                 INSERT INTO tbl_dept(deptName,locadd) VaLUES('MK',13);
 172                 INSERT INTO tbl_dept(deptName,locadd) VaLUES('MIS',14);
 173                 INSERT INTO tbl_dept(deptName,locadd) VaLUES('FD',15);
 174                 
 175                 
 176                 INSERT INTO tbl_emp(NaME,deptId) VaLUES('z3',1);
 177                 INSERT INTO tbl_emp(NaME,deptId) VaLUES('z4',1);
 178                 INSERT INTO tbl_emp(NaME,deptId) VaLUES('z5',1);
 179                 INSERT INTO tbl_emp(NaME,deptId) VaLUES('w5',2);
 180                 INSERT INTO tbl_emp(NaME,deptId) VaLUES('w6',2);
 181                 INSERT INTO tbl_emp(NaME,deptId) VaLUES('s7',3);
 182                 INSERT INTO tbl_emp(NaME,deptId) VaLUES('s8',4);
 183                 INSERT INTO tbl_emp(NaME,deptId) VaLUES('s9',51);
 184             2.2.4 7种JOIN
 185                 全连接 
 186                     select * from tbl_emp a left join tbl_dept b on a.deptId = b.id
 187                     union
 188                     select * from tb1_emp a right join tbl_dept b on a.deptId = b.id
 189                 全外连接
 190                     select * from tbl_emp a left join tbl_dept b on a.deptId = b.id where b.id is null;
 191                     union
 192                     select * from tb1_emp a right join tbl_dept b on a.deptId = b.id where a.deptId is null;
 193         2.3索引简介
 194             2.3.1 索引是什么
 195                 MySQL官方对索引的定义为:索引(index)是帮助MySQL高效获取数据的数据结构。
 196                 可以得到索引的本质:索引是数据结构
 197                     索引的目的在于提高效率,可以类比字典,
 198                     如果要查询“mysql”这个单词,我们肯定需要定位m字母,然后从上往下找到y字母,再找到剩下的sql
 199                     如果没有索引那么你可能需要a-z,如果我想找到java开头的单词呢:或者Oracle开头的单词呢?
 200                     是不是觉得如果没有索引,这个事情根本无法完成?
 201                 你可以简单理解为“排好序的快速查找数据结构” ☆
 202                     在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构基础上实现高级查找算法,这种数据结构就是索引。
 203 
 204                 一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储在磁盘上
 205                 我们平常所说的索引,如果没有特别指明,都是值B树(多路搜索树,并不一定是二叉的)结构组织的索引。其中聚集索引,次要索引,覆盖索引
 206                 符合索引,前缀索引,唯一索引默认都是使用B+树索引,统称索引,当然,除了B+这种类型的索引之外,还有哈希索引(hash
 207                 index)等。
 208             2.3.2 优势
 209                 类似大学图书馆建书目索引,提高数据检索的效率,降低数据的io成本;
 210                 通过索引列对数据进行排序,降低数据排序的成本,降低了cpu的消耗;
 211             2.3.3 劣势
 212                 ①实际上索引也是一张表,该表保存了主键和索引字段,并指向实体表的记录,所以索引列也是要占用空间的
 213                 ②虽然索引大大提过了查找的速度,同事却会降低更新表的速度,如对表进行insert,update和delete。
 214                     因为更新表时,Mysql不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,
 215                     都会调整因为更新所带来的键值变化后的索引信息
 216                 ③索引只是提高效率的一个因素,如果你的mysql有大数据量的表,就需要花时间研究建立最优秀的索引,或优化查询
 217                 
 218             2.3.4 mysql索引分类
 219                 建议一张表的索引最多不要超过5个
 220                 ①单值索引
 221                     即一个索引只包含单个列,一个表可以有多个单列索引
 222                 ②唯一索引
 223                     索引列的值必须唯一,但允许为空值
 224                 ③复合索引
 225                     即一个所以不能包含过个列
 226                 ④基本语法
 227                     一、创建
 228                         CREaTEUNIQUEINDEX indexName ON mytable(columnname(length));
 229                         aLTER mytable aDDUNIQUEINDEX 【indexName】ON(columnname(length))
 230                     二、删除
 231                         DROP INDEX 【indexName】ON mytable;
 232                     三、查看
 233                         SHOW INDEX FROM table_name\G
 234                     四、使用alter命令
 235                         有四种方式添加数据表的索引
 236                         aLTER TaBLE tbl_name aDD PRIMaRY KEY(column_list);该语句添加了一个主键,这意味着索引值必须是唯一的,且不能为NULL。
 237                         aLTER TaBLE tbl_name aDD UNIQUE index_name(column_list);这条语句创建的索引值必须是唯一的(除了NUll外,null可能出现多次)。
 238                         aLTER TaBLE tbl_name aDD INDEX index_name(column_list);添加普通索引,索引值可以出现多次。
 239                         aLTER TaBLE tbl_name aDD FULLTEXT index_name(column_list);,该语句指定了索引为FULLTEXT,用于全文索引。
 240                         
 241             2.3.5 mysql索引结构
 242                 2.3.5.1 BTree索引
 243                     检索原理
 244                         真实的数据存在于叶子节点,非叶子节点只 不存真实的数据项,只存储指引搜索方向的数据项
 245                 2.3.5.2 Hash索引
 246                 2.3.5.3 full-text全文索引
 247                 2.3.5.4 R-Tree索引
 248             2.3.6 哪些情况需要创建索引
 249                 2.3.6.1 主键自动建立唯一索引
 250                 2.3.6.2 频繁作为查询条件的字段应该创建索引
 251                 2.3.6.3 查询中与其它表关联的字段,外键关系建立索引
 252                 2.3.6.4 频繁更新的字段不适合创建索引
 253                     - 因为每次更新不单单是更新了记录还会更新索引
 254                 2.3.6.5 where条件里用不到的字段不创建索引
 255                 2.3.6.6 单键/组合索引的选择问题,who?(在高并发下倾向创建组合索引)
 256                 2.3.6.7 查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度
 257                 2.3.6.8 查询中统计或者分组字段
 258             2.3.7 哪些情况不需要创建索引
 259                 2.3.7.1 表记录太少
 260                 2.3.7.2 经常增删改的表
 261                     why:提高了查询速度,同事却会降低了更新表的速度,如对表进行insert、update和delete。
 262                     因为更新表时,Mysql不仅要保存数据,还要保存一下索引文件
 263                 2.3.7.3 数据重复且平均的表自短发,因此应该只为最经常查询的和最经常排序的数据列建立索引。
 264                         注意,如果某个数据列包含许多重复内容,为它建立索引就没有太大的实际效果
 265                             索引的选择性是指索引列中不同值的数目与表中记录的数的比。如果一个表中有2000条记录,表索引列
 266                             有1980个不通的值,那么这个索引的选择性就是1980/2000=0.99.一个索引的选择性越接近1,那么这个索引的效率就越高
 267                             
 268            
 269         2.4性能分析 ☆
 270             2.4.1 MySQL Query Optimizer
 271                 2.4.1.1 Mysql中有专门负责优化select语句的优化器模块,主要功能:通过计算分析系统中收到的统计信息,为客户端请求的Query提供他认为最优的执行计划
 272                 (他认为最优的数据检索方式,但不见得是DBa认为是最优的,这部分最耗时间)
 273                 2.4.1.2 当客户端想Mysql请求一条Query,命令解析器模块完成请求分类,区别是SELECT并转发给Mysql Query Optimizer时,Mysql Query Optimizer首先会对整条query进行优化
 274                 ,处理掉一些常量表达式的预算,直接换算成常量值,并对query中的条件进行简化和转换,如果去掉一些无用和显而易见条件,结构调整等。然后分析Query中的Hint信息(如果有)
 275                 ,看现实Hint信息是否可以完全确定该query的执行计划,如果没有Hint或Hint信息还不足以完全确定执行计划,则会读取所涉及对象的统计信息,根据query进行写相应的计算分析
 276                 ,然后再得出最后的执行计划。
 277                 
 278             2.4.2 MySQL 常见瓶颈
 279                 2.4.2.1 CPU:CPU在饱和的时候一般发生在数据装入内存或从磁盘上读取数据的时候
 280                 2.4.2.2 IO:磁盘I/O瓶颈发生在装入数据远大于内存容量的时候
 281                 2.4.2.3 服务器硬件性能瓶颈:top,free,iostat和vmstat来查看系统的性能状态
 282             
 283             2.4.3 Explian
 284                 2.4.3.1 是什么(查看执行计划)
 285                     使用Explain关键字可以模拟优化器执行sql查询,从而知道mysql是
 286                     如何处理你的sql语句。分析你的查询语句或是表结构的性能瓶颈
 287                     官网介绍
 288                         
 289                 2.4.3.2 能干嘛
 290                     2.4.3.2.1 表的读取顺序
 291                     2.4.3.2.2 数据读取操作的操作类型
 292                     2.4.3.2.3 哪些索引可以使用
 293                     2.4.3.2.4 哪些索引被实际使用
 294                     2.4.3.2.5 表之间的引用
 295                     2.4.3.2.6 每张表有多少行被优化器查询
 296                     
 297                 2.4.3.3 怎么玩
 298                     select * from tbl_emp;
 299                     explain select * from tbl_emp;
 300                     ①Explain + sql语句
 301                     ②执行计划包含信息 ☆
 302                         表头:id、select_type、table、type、possible_keys、key、key_len、ref、rows、Extra
 303                     
 304                 2.4.3.4 各字段解释
 305                     2.4.3.4.1 id
 306                         ①select查询的序列号,包含一组数字表示查询中执行select子句或操作表达表的顺序
 307                         ②三种情况
 308                             一、id相同,执行顺序由上至下
 309                                 explain select t2.*
 310                                 from t1,t2,t3
 311                                 where t1.id = t2.id and t1.id =t3.id
 312                                 and t1.other_column = '';
 313                             二、id不通,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
 314                                 explain select t2.*
 315                                 from t2
 316                                 where id =(select id
 317                                             from t1
 318                                             where id = (select t3.id
 319                                                         from t3
 320                                                         where t3.other_column = ''
 321                                                         )
 322                                             )
 323                                 
 324                             三、id相同不同,同时存在,
 325                                 id如果相同,可以认为是一组,从上往下顺序执行;在所有组中,id值越大,优先级越高,越先执行 衍生=DERIVED
 326                                 explain select t2.* from (
 327                                 select t3.id
 328                                 from t3
 329                                 where t3.other_column = '') s1,t2
 330                                 where s1.id = t2.id;
 331                                                            
 332                     2.4.3.4.2 select_type
 333                         ①有哪些
 334                             simple、primary、subquery、derived、unionunion result
 335                         ②查询的类型,主要是用于区别普通查询、联合查询、子查询等复杂查询
 336                             一、simple
 337                                 简单的select查询,查询中不包含子查询或者union。
 338                             二、primary
 339                                 查询中若包含任何复杂的子部分,最外层查询则被标记。
 340                             三、subquery
 341                                 在select或where列表中包含了子查询。
 342                             四、derived
 343                                 在from列表中包含子查询被标记为derived(衍生)mysql会递归执行这些子查询,把结果放在临时表里。
 344                             五、union 
 345                                 若第二个select出现在union之后,则被标记为union;
 346                                 若union包含在from子句的子查询中,外层select将被标记为:derived
 347                             六、union result 从union表获取结果的select
 348                             
 349                     2.4.3.4.3 table
 350                         显示这一行的数据是关于哪张表的
 351                         
 352                     2.4.3.4.4 type
 353                         allindex、range、ref、eq_ref、const,system、null
 354                         访问类型排列
 355                             type显示的访问类型,是较为重要的一个指标,结果值从最好到最坏一次是:                            
 356                             system>const>eq_ref>ref>fulltext>ref_or_null>index_merge>unique_subquery>index_subquery>range>index>aLL
 357                         显示查询使用了何种类型,从最好到最差一次是:
 358                             system>const>eq_ref>ref>range>index>aLL,一般来说,得保证查询至少达到range级别,最好能达到ref。
 359                             一、system
 360                                 表只有一行记录(等于系统表),这是const类型的特例,平时不会出现,这个也可以忽略不计。                                
 361                             二、const
 362                                 表示通过索引一次就找到了,const用于比较primary key或者unique索引。因为只匹配一行数据,所以很快
 363                                 如将逐渐置于where列表中,Mysql就能将该查询转换为一个常量
 364                                 例子:explain select * from (select * from t1 where id =1) d1;
 365                                 1 primary <derived2> system
 366                                 2 derived t1        const
 367                             三、eq_ref
 368                                 唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配,常见于主键或唯一索引扫描
 369                                 例子:explain select * from t1,t2 where t1.id =t2.id
 370                                 1 t2 simple all                                
 371                                 1 t1 simple eq_ref
 372                             四、ref
 373                                 非唯一性索引扫描,返回匹配某个单独值的所有行。
 374                                 本质上也是一个索引访问,它返回所有匹配某个单值的行,然而,
 375                                 它可能找到过个符合条件的行,所以他应该属于查找和扫描的混合体
 376                                 例子:create index idx_col1_col2 on t1(col1,col2);
 377                                     select count(distinct col1) from t1;
 378                                     explain select * from t1 where col1 = ac';
 379                             五、range
 380                                 只检索给定范围的行,使用每一个索引来选择行,key列显示使用了哪个索引
 381                                 一般就是在你的where语句中出现了between、<、>、in等的查询
 382                                 这种范围扫描索引扫描比全表扫描要好,因为它只需要开始于索引的某一点而结束语另一点,不用扫描全部索引。
 383                                 例子:explain select * from t1 where id between 30 and 60;
 384                                 1 simple t1 range
 385                                     explain select *from t1 where id in (1,2,6);
 386                                 1 simple t1 range
 387                             六、index
 388                                 full index scan,index与all区别为index类型只遍历索引树,这通常比all快,因为索引文件通常比数据文件小。
 389                                 (也就是虽然all和index都是读全表,但index是从索引中读取数据的,而all是从硬盘中读取的)                               
 390                                 explain select id from t1;
 391                                 1 simple t1 index
 392                             七、all
 393                                 full table scan,将遍历全表以找到匹配到的行
 394                                 备注:一般来说,保证查询至少达到range级别,最好能达到ref
 395                                 
 396                     2.4.3.4.5 possible_keys
 397                         显示可能应用在这张表中的索引:一个或多个
 398                         查询涉及到的字段上若存在索引,则将该索引列出,但不一定被查询实际使用                       
 399                    
 400                     2.4.3.4.6 key
 401                         实际使用的索引,如果为null,则没有使用索引
 402                         查询中若使用了覆盖索引,则该索引进程出现在key列表中
 403                          例子:explain select col1,col2 from t1
 404                          1 simple t1 index null idx_col1_col2
 405                          
 406                     2.4.3.4.7 key_len
 407                         表示索引中国使用的字节数,可通过该列计算查询中使用的索引长度。在不损失精确性的情况下,长度越短越好
 408                         key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出来的
 409                         
 410                     2.4.3.4.8 ref
 411                         显示索引的哪一个列被使用了,如果可能的话是一个常数。哪些列或常量被用于查找索引列上的值
 412                         例子:explain select * from t1,t2 where t1.col1 = t2.col1 and t1.col2 = ac';
 413                         1 t2 all null null null null
 414                         1 t1 ref idx_col1_col2 idx_col1_col2 26 shared.t2.col1,const
 415                         
 416                     2.4.3.4.9 rows
 417                         根据表统计信息及索引的选用情况,大致估算出找得到所需的记录所需要读取的行数
 418                         例子:
 419                     2.4.3.4.10 Extra
 420                         包含不适合在其他列中显示但十分重要的额外信息
 421                         一、Using filesort
 422                             说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。                            msyql中无法利用索引完成的排序操作称为“文件排序”。
 423                             例子:explain select col1 from t1 where col1 = ac' order by col3\G #中间2没有了
 424                             1 simple t1 ref idx_col1_col2_col3 idx_col1_col2_col3 13 const 142 Using where;Using index;Using filesort
 425                             例子:explain select col1 from t1 where col1 = ac' order by col2,col3\G #性能高
 426                             1 simple t1 ref idx_col1_col2_col3 idx_col1_col2_col3 13 const 142 Using where;Using index
 427                         二、Using temporary
 428                             使用临时表保存了中间结果,mysql在对外查询结果排序时使用临时表,常见于排序order by和分组查询group by 429                             例子:explain select col1 from t1 where col1 in (ac',ab',aa') group by col2\G
 430                             id simple t1 range idx_col1_col2 idx_col1_col2 13 null 569 Using where;Using index;Using temporary;Using filesort
 431                             explain select col1 from t1 where col1 in (ac',ab') group by col1,col2\G
 432                             id simple t1 range idx_col1_col2_col3 idx_col1_col2_col3 26 null 4 Using where;Using index for group by
 433                         三、Using index
 434                             表示相应的select操作中使用了覆盖索引(Cover Index),避免访问了表的数据行,效率不错!
 435                             如果同时出现useing where,表明索引被用来执行索引键值的查找;
 436                             如果没有同时出现using where表明索引用来读取该数据而非执行查找动作;
 437                             例子:explain select col2 form t1 where col1=ab';
 438                             1 ,,, idx_col1_col2 idx_col1_col2 13 const 143 Using where;using index;
 439                             explain select col1,col2 form t1
 440                             1 simple t1 index null idx_col1_col2 398 null 682 usring index
 441                             覆盖索引(Covering Index 442                                 理解方式一:就是select的数据列只从索引中就能够获取得,不必读取数据行,Mysql可以利用索引返回select列表中的字段,而不必根据索引再次读取数据文件,
 443                                 换句话说查询列要被所建的索引覆盖
 444                                 理解方式二:索引是高效查找到行的一个方法,但是一般数据库也能使用索引找到一列的数据,因此它 不必读取整个行,毕竟索引叶子节点存储了他们索引的数据;当能通过读取索引就可以得到想要的数据,那就不需要读取行了。一个索引包含了(或覆盖了)满足
 445                                 查询结果数据就叫覆盖索引
 446                             注意:
 447                                 如果要使用覆盖索引,一定注意select列表中只取出需要的列,不可select * 448                                 因为如果将所有字段一起做索引会导致索引文件过大,查询性能下降。
 449                         四、Using where
 450                             表明使用了where过滤
 451                         五、Using join buffer
 452                             使用了连接缓存                          
 453                         六、impossible where
 454                             where子句的值总是fale,不能用来获取任何元组
 455                             例子:explain select * from staffs where name = 'july' and name = 'z3';
 456                             1 simple null null null null null null null impossible where
 457                         七、select tables optimized away
 458                             在没有GROUP BY子句的情况下,基于索引优化MIN/MaX操作或者
 459                             对于MyISaM存储引擎优化COUNT(*)操作,不必等到执行阶段再进行计算
 460                             查询执行计划生成的阶段即完成优化。
 461                         八、distinct
 462                             优化distinct操作,在找到第一匹配的元组后即停止找同样值的操作
 463                         
 464                     
 465                 2.4.3.5 热身case
 466                     例子:explain select d1.name,(select id from t3) d2
 467                         from (select id,name form t1 where t1 where other_column = '') d1
 468                         union
 469                         (select name,id from t2);
 470                         1 primary <derived3> system null null null null 1
 471                         3 derived t1    all null    null    null    null    1 Using where
 472                         2 subquery  t3  index   null primary    4 null  1   using where
 473                         4 union     t2  all     null    null    null    null    1 
 474                         null nuion result <uion1,4> all null null null null null
 475                         优化sql语句  
 476                         第一行(执行顺序4):id列为1,表示是union里的第一个select,select_type列的primary表是该查询为外层查询,table列被标记为<derived3>,
 477                         表示结果来自一个衍生表,其中derived3中3代表该查询衍生自第三个select查询,即id为3的select。【select d1.name......】
 478                         第二行(执行顺序2):id为3,是整个查询中第三个select的一部分,因查询包含在from中,所以为derived。【select id.name from t1 where other_column='' 479                         第三行(执行顺序3):select列表中的子查询select_type为subquery,为整个查询中的第二个select。【select id from t3】
 480                         第四行(执行顺讯1):select_type为union,说明第四个select是union里的第二个select,最先执行【select name.id from 12 481                         第五行(执行顺序5):代表从union的临时表中读取行的阶段,table列的<union1,4>表示用第一个和第四个select的结果进行union操作。【两个结果union操作】
 482         2.5索引优化
 483             2.5.1 索引分析
 484                 2.5.1.1 单表
 485                     一、建表sql
 486                         CREaTE TaLBE IF NOT EXISTS `article`(
 487                         `id` INT(10) UNSIGNED NOT NULL PRIMaRY KEY aUTO_INCREMENT,
 488                         `author_id` INT(10) UNSIGNED NOT NULL,
 489                         `category_id` INT(10) UNSIGNED NOT NULL,
 490                         `views` INT(10) UNSIGNED NOT NULL,
 491                         `comments` INT(10) UNSIGNED NOT NULL,
 492                         `title` VaRCHaR(255) NOT NULL,
 493                         `content` TEXT NOT NULL
 494                         );
 495                         INSERT INTO `article`(`author_id`,`category_id`,`views`,`comments`,`title`,`content`)VaLUES
 496                         (1,1,1,1,'1','1'),
 497                         (2,2,2,2,'2','2'),
 498                         (3,3,3,3,'3','3');
 499                     二、案例
 500                         #查询category_id为1且comments大于1的情况下,views最多的article_id
 501                         EXPLaIN SELECT id,author_id FROM article WHERE category_id = 1 aND comments>1 ORDER BY views DESC LIMIT 1;
 502                         1 simple article all null null null null 3 Using where;Using filesort
 503                         show index from article;
 504                         #结论:很显然,type是all,即最坏的情况,Extra里还出现了Using filesort,也是最坏的情况,优化是必须的。
 505                         #开始优化:
 506                         
 507                         #1.1 新建索引+删除索引
 508                         ##aLTER TaBLE article' aDD INDEX idx_article_ccv(`category_id`,`comments`,`views`);
 509                         create index idx_article_ccv on article(category_id,comments,views);
 510                         show index from article;
 511                         EXPLaIN SELECT id,author_id FROM article WHERE category_id = 1 aND comments>1 ORDER BY views DESC LIMIT 1;
 512                         1 simple article range idx_article_ccv idx_article_ccv 8 null 1 Using where;Using filesort
 513                         调整sql语句
 514                         EXPLaIN SELECT id,author_id FROM article WHERE category_id = 1 aND comments=1 ORDER BY views DESC LIMIT 1;#范围会导致索引失效,同样一个索引条件不一样,查询结果和性能是不一样的,以后跟产品经理提需求尽量提等于,
 515                         #产品经理关注产品没关不会关注字段,但是作为研发和产品经理碰需求,尽量引导他,比如这个字段不能为空,不是我们做不出,是影响性能
 516                         1 simple article ref idx_article_ccv idx_article_ccv 8 const,const 1 Using where;Using filesort
 517                         DROP INDEX idx_article_ccv on article
 518                         #1.2 第2次EXPLaIN
 519                         EXPLaIN SELECT id,author_id FROM `article` WHERE category_id = 1 aND comments>1 ORDER BY VIEWS DESC LIMIT 1;
 520                         EXPLaIN SELECT id,author_id FROM `article` WHERE category_id = 1 aND comments=3 ORDER BY VIEWS DESC LIMIT 1;
 521                         #结论:
 522                         #type 变成了range,这是可以忍受的。但是extra里使用Using filesort仍是无法忍受的。
 523                         #但是我们已经建立了索引,为啥没用呢?
 524                         #这是因为按照BTree索引的工作原理
 525                         #先排序category_id,
 526                         #如果遇到相同的category_id则再排序comments,如果遇到相同的comments则再排序views。
 527                         #当comments字段在联合索引里处于中间位置时,
 528                         #因comments>1条件是一个范围值(所谓range),
 529                         #MySQL无法利用索引再对后面的views部分进行检索,即range类型查询字段后面的索引无效。
 530                         
 531                         #1.3删除第一次建立的索引
 532                         DROP INDEX idx_article_ccv ON article
 533                         
 534                         #1.4第2次删除新建索引
 535                         #aLTER TaBLE `article` aDD INDEX idx_article_cv(`category`,`views`);
 536                         create index idx_article_cv on article(category_id,views);
 537                         EXPLaIN SELECT id,author_id FROM article WHERE category_id = 1 aND comments>1 ORDER BY views DESC LIMIT 1;
 538                         1 simple article ref idx_article_cv 4 const 2 Using where
 539                         
 540                 2.5.1.2 两表
 541                     一、建表
 542                         CREaTE TaBLE IF NOT EXISTS `class`(
 543                         `id` INT(10) UNSIGNED NOT NULL aUTO_INCREMENT,
 544                         `card` INT(10) UNSIGNED NOT NULL,
 545                         PRIMaRY KEY(`id`)
 546                         );
 547                         CREaTE TaLBE IF NOT EXISTS `book`(
 548                         `bookid` INT(10) UNSIGNED NOT NULLL aUTO_INCREMENT,
 549                         `card` INT(10) UNSIGNED NOT NULL,
 550                         PRIMaRY KEY(`bookid`)
 551                         )
 552                         
 553                         INSERT INTO class(card) VaLUES(FLOOR(1+(RaND()+20)));
 554                         INSERT INTO class(card) VaLUES(FLOOR(1+(RaND()+20)));
 555                         INSERT INTO class(card) VaLUES(FLOOR(1+(RaND()+20)));
 556                         INSERT INTO class(card) VaLUES(FLOOR(1+(RaND()+20)));
 557                         INSERT INTO class(card) VaLUES(FLOOR(1+(RaND()+20)));
 558                         ...20
 559                         INSERT INTO book(card) VaLUES(FLOOR(1+(RaND()+20)));
 560                         INSERT INTO book(card) VaLUES(FLOOR(1+(RaND()+20)));
 561                         INSERT INTO book(card) VaLUES(FLOOR(1+(RaND()+20)));
 562                         
 563                         select * from book inner join class on book.card = class.card;
 564                     二、案例
 565                         #下面开始explain分析
 566                         EXPLaIN SELECT * FROM class LEFT JOIN book ON class.card = book.card;
 567                         #结论:type 有all
 568                         
 569                         #添加索引优化
 570                         aLTER TaBLE `book` aDD INDEX Y(`card`);
 571                         
 572                         #第2次explain
 573                         EXPLaIN SELECT * FROM class LEFT JOIN book ON class.card = book.card;
 574                         #可以看到第二行的type变为了ref,rows也变为了优化比较明显。
 575                         #这是由左连接的特性决定的。LEFT JOIN 条件用于确定如何从右表搜索,左边一定都有,
 576                         #所以右边是关键点,一定要建立索引。
 577                         
 578                         #删除旧索引+新建+第3次explain
 579                         DROP INDEX Y ON book;
 580                         aLTER TaBLE class aDD INDEX X(card);
 581                         EXPLaIN SELECT * FROM class LEFT JOIN book ON class.card = book.card;
 582                         
 583                         #然后来看一个右连接查询;
 584                         #优化较明显,这是因为RIGHT JOIN 条件用于确定如何从左表搜索行,右边一定都有,所以左边是我们的关键点,一定需要建立索引。
 585                         EXPLaIN SELECT * FROM class RIGHT JOIN book ON class card = book.card
 586                         DROP INDEX X ON class;
 587                         aLTER TaBLE book aDD INDEX Y(card);
 588                         #右连接,基本无变化
 589                         EXPLaIN SELECT * FROM class RIGHT JOIN book ON class.card = book.card;
 590 
 591                 2.5.1.3 三表
 592                     一、建表sql
 593                         CREaT TaBLE IF NOT EXISTS `phone`(
 594                         `` INT(10) UNSIGNED NOT NULL aUTO_INCREMENT,
 595                         `` INT(10) UNSIGNED NOT NULL,
 596                         PRIMaRY KEY(`phoneid`)
 597                         )ENGINE = INNODB;
 598                         
 599                         INSERT INTO phone(card) VaLUES(FLOOR(1+(RaND()*20)));
 600                         INSERT INTO phone(card) VaLUES(FLOOR(1+(RaND()*20)));
 601                         INSERT INTO phone(card) VaLUES(FLOOR(1+(RaND()*20)));
 602                         ...20
 603                         INSERT INTO phone(card) VaLUES(FLOOR(1+(RaND()*20)));
 604                         INSERT INTO phone(card) VaLUES(FLOOR(1+(RaND()*20)));
 605                         INSERT INTO phone(card) VaLUES(FLOOR(1+(RaND()*20)));
 606                     二、案例
 607                         aLTER TaBLE `phone` aDD INDEX z(`card`);
 608                         aLTER TaBLE `book` aDD INDEX Y(`card`);#上一个case建过一个同样的
 609                         
 610                         EXPLaIN SELECT * FROM class LEFT JOIN book ON class card=book.card LEFT JOIN phone ON book.card = phone.card
 611                         
 612                         #后2行的type都是ref且总rows优化很好,效果很不错,因此索引最好设置在需要经常查询的字段中。
 613                         ========================================================================================
 614                         【结论】
 615                         join语句优化
 616                         尽可能减少join语句中的NestedLoop的循环总次数:“永远用小的结果集驱动大的结果集”
 617                         #书籍类和书数目比,书是大结果集,例如圆规,短的不动,如果用书大的必须1亿次io去匹配书籍类,就很低效率
 618                         有线优化NestdLoop的内层循环;
 619                         保证join语句中被驱动表上join条件字段已经被索引;
 620                         
 621                         当无法保证被驱动表的join条件字段被索引且内存资源充足的前提下,不要太吝惜JoinBuffer的设置;
 622                         
 623             2.5.2 索引失效(应该避免)
 624                 2.5.2.1 建表SQL
 625                     CREaTE TaBLE staffs(
 626                         id INT PRIMaRY KEY aUTO_INCREMENT,
 627                         name VaRCHaR(24) NOT NULL DEFaULT '' COMMENT '姓名',
 628                         age INT NOT NULL DEFaULT 0 COMMENT '年龄',
 629                         pos VaRCHaR(20) NOT NULL DEFUaLT '' COMMNET '职位',
 630                         add_time TIMESTaMP NOT NULL DEFaULT CURRENT_TIMESTaMP COMMENT '入职时间'                       
 631                     ) CHaRSET utf8 COMMENT '员工记录表';
 632                     
 633                     INSERT INTO staffs(name,age,pos,add_time) VaLUES('z3',22,'manager',NOW());
 634                     INSERT INTO staffs(name,age,pos,add_time) VaLUES('z3',22,'manager',NOW());
 635                     INSERT INTO staffs(name,age,pos,add_time) VaLUES('z3',22,'manager',NOW());
 636                     SELECT * FROM staffs;
 637                     
 638                     aLTER TaLBE staffs aDD INDEX idx_staffs_nameagePos(name,age,pos);
 639                     
 640                 2.5.2.2 案例索引失效
 641                     一、全值匹配我最爱
 642                         #最完美的sql,就是索引怎么建的怎么用
 643                         EXPLaIN SELECT * FROM statffs WHERE name = 'July';
 644                         #1 simple staffs ref idx_staffs_nameagePos idx_staffs_nameagePos 74 const 1 Using where
 645                         EXPLaIN SELECT * FROM statffs WHERE name = 'July' aND age = 25;
 646                         #1 simple staffs ref idx_staffs_nameagePos idx_staffs_nameagePos 78 const,const 1 Using where
 647                         EXPLaIN SELECT * FROM statffs WHERE name = 'July' aND age = 25 aND pos = 'dev';
 648                         #1 simple staffs ref idx_staffs_nameagePos idx_staffs_nameagePos 140 const,const,const 1 Using where
 649                         #调整
 650                         EXPLaIN SELECT * FROM statffs WHERE  age = 23 aND pos = 'dev';
 651                         #1 simple staffs all null null null null 3 Using where
 652                         EXPLaIN SELECT * FROM statffs WHERE  pos = 'dev';
 653                         #1 simple staffs all null null null null 3 Using where
 654                     二、最佳左前缀法则☆
 655                         如果索引了多列,要遵守左前缀法则。指的是查询从索引的最左前列开始并且“不跳过索引中间列”。
 656                         #“带头大哥不能死“,例如火车头与车厢。
 657                         #“中间兄弟不能断”,否则索引只用到了部分。
 658                     三、不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致
 659                         explain select * from staffs where name = 'July';
 660                         # 1 simple staffs ref idx_staffs_nameagePos idx_staffs_nameagePos 74 const 1 Using where
 661                         explain select * from staffs where left(name,4) = 'July';
 662                         # 1 simple staffs all null null null null 3 Using where
 663                     四、存储引擎不能使用索引中范围条件右边的列
 664                         EXPLaIN SELECT * FROM statffs WHERE name = 'July' aND age > 25 aND pos = 'manage';
 665                         #1 simple staffs range idx_staffs_nameagePos idx_staffs_nameagePos 78 null 1 Using where
 666                         #单个74,2个78,3个140,只用到了2个
 667                     五、尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致)),减少select
 668                         EXPLaIN SELECT * FROM statffs WHERE name = 'July' aND age = 25 aND pos = 'manage';
 669                         #1 simple staffs ref idx_staffs_nameagePos idx_staffs_nameagePos 140 const,const,const 1 Using where
 670                         EXPLaIN SELECT name,age,pos FROM statffs WHERE name = 'July' aND age = 25 aND pos = 'manage';
 671                         #1 simple staffs ref idx_staffs_nameagePos idx_staffs_nameagePos 140 const,const,const 1 Using where;using index
 672                         EXPLaIN SELECT * FROM statffs WHERE name = 'July' aND age > 25 aND pos = 'dev';
 673                         #1 simple staffs ref idx_staffs_nameagePos idx_staffs_nameagePos 74 const 1 Using where;using index
 674                         #查询索引列比不在索引列效果高,using index
 675                     六、mysql在使用不等于(!=或者<>)的时候无法使用索引会导致全表扫描
 676                         explain select * from staffs where name = 'July';
 677                         #1 simple staffs ref idx_staffs_nameagePos idx_staffs_nameagePos 74 const 1 Using where
 678                         explain select * from staffs where name != 'July';
 679                         #1 simple staffs all idx_staffs_nameagePos null null null 1 Using where
 680                     七、is null,is not null也无法使用索引
 681                         explain select * from staffs where name is null';
 682                         #1 simple null null null null null null null Impossible where
 683                         explain select * from staffs where name is not null';
 684                         ##1 simple staffs all idx_staffs_nameagePos null null null 5 Using where
 685                     八、like以通配符开头('%abc...')mysql索引失效会变成全表扫描的操作
 686                         EXPLaIN SELECT name,age,pos FROM statffs WHERE name like '%July%';
 687                         #1 simple staffs all null null null null 3 Using where
 688                         EXPLaIN SELECT name,age,pos FROM statffs WHERE name like '%July';
 689                         #1 simple staffs all null null null null 3 Using where
 690                         EXPLaIN SELECT name,age,pos FROM statffs WHERE name like 'July%';
 691                         #1 simple staffs range idx_staffs_nameagePos idx_staffs_nameagePos 74 null 1 Using where;
 692                         #"百分like加右边"
 693                         #问题:解决like'%字符串%'时索引不被使用的方法??
 694                         #案例
 695                         CREaTE TaBLE `tbl_user`(
 696                         `id` INT(11) NOT NULL aUTO_INCREMENT,
 697                         `name` VaRCHaR(20) DEFaULT NULL,
 698                         `age` INT(11) DEFaULT NULL,
 699                         `email` VaRCHaR() DEFUaLT NULL,
 700                         PRIMaRY KEY(`id`)
 701                         ) ENGINE=INNODB aUTO_INCREMENT=1 DEFaULT CHaRSET=UTF8;
 702                         
 703                         #drop table tbl_user
 704                         
 705                         INSERT INTO tbl_user(name,age,email) VaLUES('1aa1',21,'b@163.com');
 706                         INSERT INTO tbl_user(name,age,email) VaLUES('2aa2',222,a@163.com');
 707                         INSERT INTO tbl_user(name,age,email) VaLUES('3aa3',265,'c@163.com');
 708                         INSERT INTO tbl_user(name,age,email) VaLUES('4aa4',21,'d@163.com');
 709                         #before index
 710                         ①EXPLaIN SELECT name,age FROM tbl_user WHERE NaME LIKE '%aa%';
 711                         
 712                         ②EXPLaIN SELECT id FROM tbl_user WHERE NaME LIKE '%aa%';
 713                         ③EXPLaIN SELECT name FROM tbl_user WHERE NaME LIKE '%aa%';
 714                         ④EXPLaIN SELECT age FROM tbl_user WHERE NaME LIKE '%aa%';
 715                         
 716                         ⑤EXPLaIN SELECT id,name FROM tbl_user WHERE NaME LIKE '%aa%';
 717                         ⑥EXPLaIN SELECT id,name,age FROM tbl_user WHERE NaME LIKE '%aa%';
 718                         ⑦EXPLaIN SELECT name,age FROM tbl_user WHERE NaME LIKE '%aa%';
 719                         
 720                         ⑧EXPLaIN SELECT * FROM tbl_user WHERE NaME LIKE '%aa%';
 721                         ⑨EXPLaIN SELECT id,name,age,email FROM tbl_user WHERE NaME LIKE '%aa%';
 722                         #以上没建立索引前全部是全表扫描
 723                         #create index 
 724                         CREaTE INDEX idx_user_nameage ON tbl_user(name,age);
 725                         ①idx用到了②idx用到了③用到了④用到了⑤⑥⑦都用到了⑧失效了⑨没有覆盖email,失效了
 726                         #如果必须两边百分号,用覆盖索引
 727                         
 728                     九、字符串不加单引号索引失效☆(重罪)
 729                         explain select * from staffs where name='2000';
 730                         #1 simple staffs ref idx_staffs_name idx_staffs_name 74 const 1 Using where
 731                         explain select * from staffs where name=2000;
 732                         #mysql在底层隐晦的坐了数字到字符的转换,
 733                         #1 simple staffs all idx_staffs_name null null null 3 Using where
 734                         违反了第3条
 735                         
 736                     十、少用or,用它来连接时会索引失效
 737                         explain select * from staffs where name='July' or name='z3';                       
 738                         #1 simple staffs all idx_staffs_name null null null 3 Using where
 739                     十一、小总结
 740                         #带头大哥不能死
 741                         #中间兄弟不能断
 742                         #索引列上不计算
 743                         #范围之后都失效
 744                         #覆盖索引使优先
 745                         #like优先靠右边
 746                         #引号缺失不靠谱
 747                         #少用或者引失效
 748                         #null或不null都无效
 749                         #等或不等全表扫
 750                         
 751                 2.5.2.3 面试题讲解
 752                     题目SQL
 753                         【建表语句】
 754                          create table test03(
 755                          c1 char(10),
 756                          c2 char(10),
 757                          c3 char(10),
 758                          c4 char(10),
 759                          c5 char(10),                        
 760                          );
 761                          
 762                          insert into test03(c1,c2,c3,c4,c5) values(a1',a2',a3',a4',a5');
 763                          insert into test03(c1,c2,c3,c4,c5) values('b1','b2','b3','b4','b5');
 764                          insert into test03(c1,c2,c3,c4,c5) values('c1','c2','c3','c4','c5');
 765                          insert into test03(c1,c2,c3,c4,c5) values('d1','d2','d3','d4','d5');
 766                          insert into test03(c1,c2,c3,c4,c5) values('e1','e2','e3','e4','e5');
 767                          
 768                          select * from test03;
 769                          
 770                          【建索引】
 771                          create index idx_test3_c1234 on test03(c1,c2,c3,c4);
 772                          show index from test03;
 773                          
 774                          问题,我们创建了符合索引idx_test03_c12345,根据以下SQL分析下索引使用情况
 775                          explain select * from test03 where c1=a1';
 776                          explain select * from test03 where c1=a1' and c2=a2';
 777                          explain select * from test03 where c1=a1' and c2=a2' and c3=a3';
 778                          explain select * from test03 where c1=a1and c2=a2' and c3=a3' and c4=a4';
 779                          
 780                          (1)
 781                          explain select * from test03 where c1=a1' and c2=a2' and c4=a4' and c3=a3';
 782                          #1 simple test03 ref idx_test03_c1234 idx_test03_c1234 124 const,const,const,const 1 Using where
 783                          (2)
 784                          explain select * from test03 where c4=a4' and c3=a3' and c2=a2' and c1=a1';
 785                          #1 simple test03 ref idx_test03_c1234 idx_test03_c1234 124 const,const,const,const 1 Using where
 786                          (3)
 787                         explain select * from test03 where c1=a1' and c2=a2' and c3>a3' and c4=a4';
 788                          #1 simple test03 range idx_test03_c1234 idx_test03_c1234 93 null 1 Using where
 789                          (4)
 790                          explain select * from test03 where c1=a1' and c2=a2' and c4>a4' and c3=a3';
 791                          #1 simple test03 range idx_test03_c1234 idx_test03_c1234 124 null 1 Using where#先按索引优化对号入座
 792                          (5)
 793                          explain select * from test03 where c1=a1' and c2=a2' and c4>a4' order by c3;                         
 794                          #1 simple test03 range idx_test03_c1234 idx_test03_c1234 62 const,const 1 Using where
 795                          c3的作用在于排序而不是查找
 796                          (6)
 797                          explain select * from test03 where c1=a1' and c2=a2' order by c3;                         
 798                          #1 simple test03 range idx_test03_c1234 idx_test03_c1234 62 const,const 1 Using where
 799                          (7)
 800                          explain select * from test03 where c1=a1' and c2=a2' order by c4;                         
 801                          #1 simple test03 range idx_test03_c1234 idx_test03_c1234 62 const,const 1 Using where;Using filesort#导致性能下降
 802                          #出现了filesort
 803                          (8)
 804                          #8.1                         
 805                          explain select * from test03 where c1=a1' and c5=a5' order by c2,c3;                         
 806                          #1 simple test03 range idx_test03_c1234 idx_test03_c1234 31 const 1 Using where
 807                          #8.2
 808                          explain select * from test03 where c1=a1' and c5=a5' order by c3,c2;                         
 809                          #1 simple test03 range idx_test03_c1234 idx_test03_c1234 31 const 1 Using where;Using filesort
 810                          #出现了filesort,我们建立的索引是1234,它没有被按照顺序来,32颠倒了
 811                          (9)
 812                          explain select * from test03 where c1=a1' and c2=a2' order by c2,c3;                         
 813                          #1 simple test03 range idx_test03_c1234 idx_test03_c1234 31 const 1 Using where;Using filesort
 814                          (10)
 815                          explain select * from test03 where c1=a1' and c2=a2'  and c5=a5' order by c2,c3;                         
 816                          #1 simple test03 range idx_test03_c1234 idx_test03_c1234 62 const 1 Using where;
 817                          用c1、c2两个字段索引,但是c2、c3用于排序、无线filesort
 818                          explain select * from test03 where c1=a1' and c2=a2'  and c5=a5' order by c3,c2;
 819                          #1 simple test03 range idx_test03_c1234 idx_test03_c1234 62 const 1 Using where;
 820                          本例有常量c2的情况和8.2对比
 821                          explain select * from test03 where c1=a1' and c5=a5' order by c3,c2;
 822                          #1 simple test03 range idx_test03_c1234 idx_test03_c1234 31 const 1 Using where;Using filesort
 823                          (11)
 824                          explain select * from test03 where c1=a1' and c4=a4' group by c2,c3;
 825                          #1 simple test03 ref idx_test03_c1234 idx_test03_c1234 31 const 1 Using where;
 826                          (12)
 827                          explain select * from test03 where c1=a1' and c4=a4' group by c3,c2;
 828                          #1 simple test03 ref idx_test03_c1234 idx_test03_c1234 31 const 1 Using where;Using temporary;Using filesort
 829                          #分组之前比排序
 830                     定值、范围还是排序、一般order by是给个范围
 831                     group by 基本上都需要进行排序,会有临时表产生
 832                     
 833             2.5.3 一般性建议
 834                 对于单键索引,尽量选择针对当前query过滤性更好的索引
 835                 在选择组合索引的时候,当前Query中过滤性最好的字段在索引字段顺序中,位置越靠前越好。
 836                 在选择组合索引的时候,尽量选择可以能够包含当前query中的where子句中更多字段的索引
 837                 尽可能通过分析统计信息和调整query的写法来达到选择合适索引的目的
 838     3、查询截取分析
 839         3.1查询优化
 840             3.1.1 永远小表驱动大表
 841                 case;
 842                     优化原则:小表驱动大表,即小的数据集驱动大的数据集。
 843                     ################原理(RBO)#############################
 844                     select * from a where id in (select id from B)
 845                     等价于
 846                     for select id from B
 847                     for select * from a where a.id = B.id
 848                     
 849                     当B表的数据集必须小于a表的数据集时,用in由于exists。
 850                     select * from a where id exists (select id from B where B.id = a.id)
 851                     等价于
 852                     for select * from a
 853                     for select *from B where B.id = a.id
 854                     
 855                     当a表的数据集系小于B表的数据集时,用exists由于in
 856                     
 857                 exist
 858                     select ... from table where exists(subquery)
 859                     该语法可以理解为:"将主查询数据,放到咨询中做条件验证,根据验证结果(TRUE或FaLSE)来决定主查询的数据结果是否得以保留。"  
 860                 提示
 861                     一、Exists(subquery)只返回True或False,因此子查询中的select * from 也可以是select 1或SELECT 'x',官方说法是实际执行时会忽略SELECT清单,因此没有区别
 862                     二、EXISTS子查询的实际执行过程可能胫骨了优化而不是我们理解的逐条对比,如果担忧效率问题,可进行使劲检验以确定是否有效率问题。
 863                     三、EXISTS子查询往往可以用条件表达式,其他子查询后者join来替代,何种最优需要具体问题具体分析
 864             3.1.2 类似嵌套循环Nested Loop
 865             3.1.3 order by关键字优化
 866                 3.1.3.1 ORDER BY子句,尽量使用index方式排序,避免使用Filesort方式排序
 867                     3.1.3.1.1 建表SQL
 868                         CREaTE TaBLE tbla(
 869                         #id int primary key not null auto_increment,
 870                         age INT,
 871                         birth TIMESTaMP NOT NULL
 872                         );
 873                         
 874                         INSERT INTO tbla(age,birth) VaLUES(22,NOW());
 875                         INSERT INTO tbla(age,birth) VaLUES(23,NOW());
 876                         INSERT INTO tbla(age,birth) VaLUES(24,NOW());
 877                         
 878                         CREaTE INDEX idx_a_ageBirth ON tbla(age,birth);
 879                         
 880                         SELECT * FROM tbla;
 881                         
 882                     3.1.3.1.2 Case
 883                         #一、
 884                         EXPLaIN SELECT * FROM tbla WHERE age>20 ORDER BY age;
 885                         # 1 | SIMPLE      | tbla  | NULL       | index | idx_a_ageBirth | idx_a_ageBirth | 9       | NULL |    3 |   100.00 | Using where; Using index
 886                         explain select * from tbla where age>20 order by age,birth;
 887                         #1 | SIMPLE      | tbla  | NULL       | index | idx_a_ageBirth | idx_a_ageBirth | 9       | NULL |    3 |   100.00 | Using where; Using index
 888                         explain select * from tbla where age>20 order by birth;
 889                         #1 | SIMPLE      | tbla  | NULL       | index | idx_a_ageBirth | idx_a_ageBirth | 9       | NULL |    3 |   100.00 | Using where; Using index; Using filesort
 890                         #二、
 891                         explain select * from tbla ORDER bY birth;
 892                         #1 | SIMPLE      | tbla  | NULL       | index | NULL          | idx_a_ageBirth | 9       | NULL |    3 |   100.00 | Using index; Using filesort
 893                         explain select * from tbla where birth >'2016-01-28 00:00:00' order by birth;
 894                         # 1 | SIMPLE      | tbla  | NULL       | index | NULL          | idx_a_ageBirth | 9       | NULL |    3 |    33.33 | Using where; Using index; Using filesort
 895                         explain select * from tbla where birth >'2016-01-28 00:00:00' order by age;
 896                         # 1 | SIMPLE      | tbla  | NULL       | index | NULL          | idx_a_ageBirth | 9       | NULL |    3 |    33.33 | Using where; Using index 
 897                         explain select * from tbla order by age asc,birth desc;
 898                         #1 | SIMPLE      | tbla  | NULL       | index | NULL          | idx_a_ageBirth | 9       | NULL |    3 |   100.00 | Using index; Using filesort 
 899                         
 900                     3.1.3.1.3 Mysql支持两种方式排序,FileSort和Index,Index效率高,它指MySQL扫描索引本身完成排序。Filesort方式效率较低
 901                     3.1.3.1.4 ORDER BY满足两情况,会使用Index方式排序:
 902                         ORDER BY语句使用索引最左前列
 903                         使用where子句与order by子句条件列组合满足索引最左前列
 904                 3.1.3.2 尽可能在索引列上完成排序操作,遵照索引建的最优左前缀
 905                 3.1.3.3 如果不在索引列上,filesort有两种算法
 906                     3.1.3.3.1 双路排序
 907                         mysql4.1之前是使用双路排序,字面意思就是两次扫描磁盘,最终得到数据,
 908                         读取行指针和orderby列,对他们进行排序,然后扫描已经排序好的列表,按照列表中的值重新从列表中
 909                         从磁盘取排序字段,在buffer进行排序,再从磁盘取其他字段。
 910                     3.1.3.3.2 取一批数据,要对磁盘进行了两次扫描,众所周知,I/O是是很耗时的,所以在mysql4.1之后,出现了第二种改进算法,就是单路排序。
 911                     3.1.3.3.3 单路排序
 912                         从磁盘读取查询所需要的所有列,按照order by列在buffer对他们进行排序,然后扫描排序后的列表进行输出,他的效率更快一些,避免了而第二次读取数据
 913                         并且把随机I/O变成了顺序iO,但是他会使用更多空间,因为他把每一行都保存在内存中了。
 914                     3.1.3.3.4 结论及引申出的问题
 915                         由于单路是后出的,总体而言好过双路
 916                         但是用单路有问题
 917                             在sort_buffer中,方法B比方法a要多占用很多空间,因为方法B是把所有字段都取出,所以有可能取出的数据的总大小超出了sort_buffer的容量
 918                             导致每次只能取sort_buffer容量大小的数据,进行排序(创建tmp文件,多路合并),排完再取
 919                             sort_buffer容量大小,再排...从而多次I/O
 920                             本来想省一次I/O操作,反而导致了大量的I/O操作,反而得不偿失。
 921                 3.1.3.4、mysql就要启动双路排序和单路排序
 922                 3.1.3.5 优化策略
 923                     ①增大sort_buffer_size参数的设置
 924                     ②增大max_length_for_sort_data参数的设置
 925                     ③why
 926                         提高order by的速度
 927                         一、order by时select * 是大忌只query需要的字段,这点非常重要。在这里的影响是:
 928                             a、当query的字段大小总和小于max_length_for_sort_data而且排序字段不是TEXT|BLOB类型时,会导致改进后的算法--单路排序,否则用老算法双路排序
 929                             B、两种算法的排序都有可能超出sort_buffer的容量,超出之后,会创建tmp文件进行合并排序,导致多次I/O,但是用单路排序算法风险更大一些,所以要提高sort_buffer_size.
 930                         二、尝试提高sort_buffer_size
 931                             不管用那种算法,提高这个参数都会提高效率,当然,要根据系统能力去提高,因为这个参数是针对每个进程进行的
 932                         三、尝试提高max_length_for_data
 933                             提高这个参数,会增加用改进算法的概率,但是如果设的太高,数据总容量超出sort_buffer_size的概率就增大,名症状是高的磁盘I/O活动和低的处理器使用率
 934                 3.1.3.6 小总结
 935                     为排序使用索引
 936                         MySQL两种排序方式:文件排序或者扫描有序索引排序
 937                         Mysql能为排序Yui查询使用相同的索引
 938                         KEY a_b_c(a,b,cv)
 939                         
 940                         order by能使用索引最左前缀
 941                         -order by a
 942                         -order by a,b
 943                         -order by a,b,c
 944                         -order by a DESC,b DESC,c DESC
 945                         
 946                         如果where使用索引的最左前缀定义为常量,则oder by能使用索引
 947                         -where a = const order by b,c
 948                         -where a = const and b = const order by c
 949                         -where a = const order by b,c
 950                         -where a = const and b > const order by b,c
 951                         
 952                         不能使用索引进行排序
 953                         -order by a asc,b desc,c desc /*排序不一致*/
 954                         -where g = const order by b,c /*丢失a索引*/
 955                         -where a = const order by c   /*丢失b索引*/
 956                         -where a = const order by a,d /*d不是索引的一部分*/
 957                         -where a in(...) by b,c       /*“对于排序来说,多个相等的条件也是范围查询”*/
 958                         
 959             3.1.4 GROUP BY关键字优化
 960                 group by实质是先排序后进行分组遵照索引键的最佳左前缀                                                           
 961                 当无法使用索引列时,增大max_length_for_sort_data参数的设置+增大sort_buffer_size参数的设置
 962                 where高于having,能写在where限定条件就不要having限定了。
 963                 
 964         3.2慢查询日志
 965             3.2.1 是什么
 966                 一、Mysql的慢查询日志是Mysql提供的一种日志记录,它用来记录在Mysql中相应时间超过阈值的语句,具体指运行时间超过了long_query_time值的sql,则会被记录到慢查询日志中
 967                 二、具体指运行时间超过了long_query_time值的SQL,则会被记录到慢查询日志中。long_query_time的默认值为10,意思是运行10秒以上的语句。
 968                 三、有他来查看哪些sql朝出了我们的最大忍耐时间值,比如一条sql执行超过5秒钟,我们就算慢sql,希望收集超过5秒的sql,结合之前explain进行全面分析。
 969             3.2.2 怎么玩
 970                 3.2.2.1 说明
 971                     “默认情况下,Mysql没有开启慢查询日志“,需要我们手动来设置这个参数。
 972                     
 973                     当然,如果不是调优需要的话,一般不建议启动该参数,因为开启慢查询日志会或多或少带来一定性能的影响,慢查询日志支持将日志写入文件
 974                     
 975                 3.2.2.2 查看是否开启及如何开启
 976                     默认
 977                         show variables like '%slow_query_log%';
 978                             默认情况下slow_query_log的值为OFF,表示慢查询日志是禁用的,
 979                             可以通过设置slow_query_log的值来开启
 980                             mysql> show variables like '%slow_query_log%';
 981                             +---------------------+------------------------------------------+
 982                             | Variable_name       | Value                                    |
 983                             +---------------------+------------------------------------------+
 984                             | slow_query_log      | OFF                                      |
 985                             | slow_query_log_file | /var/lib/mysql/aIOPTESTCLUSTER2-slow.log |
 986                             +---------------------+------------------------------------------+
 987 
 988                     开启
 989                         set global slow_query_log=1;
 990                             是用set global slow_query_log=1开启了慢查询日志“只对当前数据库生效”
 991                             如果Mysql重启会失效。
 992                             如果要永久生效,就必须修改配置文件my.cnf(其他系统变量也是如此)
 993                             修改my.cnf文件,[mysqld]下增加或修改参数
 994                             slow_query_log和slow_query_log_file后,然后重启Mysql服务器,也即将如下两行配置进my.cnf文件
 995                             slow_query_log=1
 996                             slow_query_log_file=/var/lib/mysql/atguigu-slow.log
 997                             关于慢查询日志的参数slow_query_log_file,它指定慢查询日志文件路径存放路径,系统默认给一个缺省的文件host_name-slow.log(如果没有指定参数的话)
 998                             
 999                         
1000                 3.2.2.3 那么开启了慢查询日志后,什么样的SQL才会记录到慢查询日志里面呢?
1001                     这个是由参数long_query_time控制的,默认情况下long_query_time的值为10秒,
1002                     命令:SHOW VaRIaBLES LIKE 'long_query_time%';
1003                     可以使用命令修改,也可以在my.cnf参数里面修改
1004                     假如运行时间正好等于long_query_time的情况,并不会被记录下来。也就是说,
1005                     在mysql源码里是“判断大于long_query_time,而非大于等于”
1006                 3.2.2.4 case
1007                     查看当前多少秒算慢 SHOW VaRIaBLES LIKE 'long_query_time%';
1008                     设置慢的阈值时间 
1009                         set global long_query_time=3,修改为阈值到3秒钟的就是慢sql;修改了变量long_query_time,但是查询变量long_query_time的值还是10,莫非修改无效                        
1010                         
1011                     为什么设置后看不出变化
1012                         需要重新连接或新开一个会话才能看到修改值。
1013                         SHOW VaRIaBLES LIKE 'long_query_time'
1014                         SHOW  global VaRIaBLES LIKE 'long_query_time'
1015                     记录慢SQL并后续分析
1016                         select sleep(4),查询慢查询日志,日志会准确定位慢sql各种参数,最后一条发生问题的sql
1017                     查询当前系统中有多少条慢查询记录
1018                         show global status like '%slow_queries%'; 
1019                 3.2.2.5 配置版
1020             3.2.3 日志分析工具 mysqldumpslow
1021                 在生产环境中,如果要手工分析日志,查找、分析SQL,显然是个体力活,mysql提供了日志分析工具mysqldumpslow
1022                 
1023                 3.2.3.1 查看mysqldumpslow的帮助信息
1024                     s:是表示按何种行为
1025                     c:方位次数
1026                     i:锁定时间
1027                     r:返回记录
1028                     t:查询时间
1029                     al:平均时间
1030                     ar:平均返回记录数
1031                     at:平均查询时间
1032                     t:即为返回前面多少条数据;
1033                     g:后边搭配一个正则匹配模式,大小写不敏感的;
1034                 3.2.3.2 工作常用参考
1035                     得到返回记录集最多的10个sql
1036                     mysqldumpslow -s -r -t 10 /var/lib/mysql/atguigu-slow.log
1037                     
1038                     得到访问次数最多的10个sql
1039                     mysqldumpslow -s c -t 10 /var/lib/mysql/atguigu-slow.log
1040                     得到按照时间排序的前10条里面含有左连接的查询语句
1041                     mysqldumpslow -s t -t 10 -g "left join" /var/lib/mysql/atguigu-slow.log
1042                     另外建议在使用这些命令时结合|和more使用,否则有可能出现爆屏情况
1043                     mysqldumpslow -s r -t 10 /var/lib/mysql/atguigu-slow.log|more
1044                     
1045         3.3 批量数据脚本
1046             3.3.1 往表里插入1000w数据
1047                 3.3.1.1 建表
1048                     #新建表
1049                     create database bigData;
1050                     use bigData;
1051                     
1052                     #1 建表dept
1053                     CREaTE TaBlE dept(
1054                     id INT UNSIGNED PRIMaRY KEY aUTO_INCREMENT,
1055                     deptno MEDIUMINT UNSIGNED NOT NULL DEFaULT 0,
1056                     dname VaRCHaR(20) NOT NULL DEFaULT "",
1057                     loc VaRCHaR(13) NOT NULL DEFaULT ""
1058                     ) ENGINE=INNODB DEFaULT CHaRSET=GBK;
1059                     
1060                     #2 建表emp
1061                     CREaTE TaBLE emp(
1062                     id INT UNSIGNED PRIMaRY KEY aUTO_INCREMENT,
1063                     empno MEDIUMINT UNSIGNED NOT NULL DEFaULT 0,/*编号*/
1064                     ename VaRCHaR(20) NOT NULL DEFaULT "",/*名字*/
1065                     job VaRCHaR(9) NOT NULL DEFaULT "",/*工作*/
1066                     mgr MEDIUMINT UNSIGNED NOT NULL DEFaULT 0,/*上级编号*/
1067                     hiredate DaTE NOT NULL,/*入职时间*/
1068                     sal DECIMaL(7,2) NOT NULL,/*薪水*/
1069                     comm DECIMaL(7,2) NOT NULL,/*红利*/
1070                     deptno MEDIUMINT UNSIGNED NOT NULL DEFaULT 0/*部门编号*/                    
1071                     ) ENGINE=INNODB DEFaULT CHaRSET=GBK;
1072                     
1073                 3.3.1.2 设置参数 log_bin_trust_function_creators
1074                     创建函数,加入报错:This function has none of DETERMINISTIC......
1075                     #由于开启了慢查询日志,因为我们开启了bin-log,我们就必须为我们的function指定一个参数
1076                     
1077                     show variables like "log_bin_trust_function_creators";
1078                     set global log_bin_trust_function_creators=1;
1079                     
1080                     #这样添加了参数以后,如果mysqld重启,上述参数又会消失,永久方法
1081                     windows下my.ini[mysqld]加上log_bin_trust_funcion_creators=1
1082                     linux下/etc/my.cnf下my.cnf[mysqld]加上log_bin_trust_function_creators=1
1083                     
1084                 3.3.1.3 创建函数,保证每条数据都不同
1085                     随机产生字符串
1086                         DELIMITER $$
1087                         CREaTE FUNCTION rand_string(n INT) RETURNS VaRCHaR(255)
1088                         BEGIN
1089                         DECLaRE chars_str VaRCHaR(100) DEFaULT abcdefghijklmnopqrstuvwxyzaBCDEFGHIJKLMNOPQRSTUVWXYZ';
1090                         DECLaRE return_str VaRCHaR(255) DEFaULT '';
1091                         DECLaRE i INT DEFaULT 0;
1092                         WHILE i< n DO
1093                         SET return_str =CONCaT(return_str,SUBSTRING(chars_str,FLOOR(1+RaND()*52),1));
1094                         SET i = i+1;
1095                         END WHILE;
1096                         RETURN return_str;
1097                         END $$
1098                        
1099                         
1100                         #假如要删除
1101                         #drop function rand_string
1102                         
1103                     随机产生部门编号
1104                         DELIMITER $$
1105                         CREaTE FUNCTION rand_num()
1106                         RETURNS INT(5)
1107                         BEGIN
1108                         DECLaRE i INT DEFaULT 0;
1109                         SET i = FLOOR(100+RaND()*10);
1110                         RETURN i;
1111                         END $$
1112                         
1113                         ##假如要删除
1114                         #drop function rand_num;
1115                         
1116                 3.3.1.4 创建存储过程
1117                     创建往emp表中插入数据的存储过程
1118                         DELIMITER $$
1119                         CREaTE PROCEDURE insert_emp(IN STaRT INT(10),IN max_num INT(10))
1120                         BEGIN
1121                         DECLaRE i INT DEFaULT 0;
1122                         #set autocommit =0 把autocommit设置成0
1123                         SET autocommit =0;
1124                         REPEaT
1125                         SET i=i+1;
1126                         INSERT INTO emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) VaLUES((STaRT+i)
1127                         ,rand_string(6),'SaLESMaN',0001,CURDaTE(),2000,400,rand_num());
1128                         UNTIL i = max_num
1129                         END REPEaT;
1130                         COMMIT;
1131                         END $$
1132                     创建王dept表中插入数据的存储过程
1133                         #执行存储过程,王dept表添加随机数据
1134                         DELIMITER $$
1135                         CREaTE PROCEDURE insert_dept(IN STaRT INT(10),IN max_num INT(10))
1136                         BEGIN
1137                         DECLaRE i INT DEFaULT 0;
1138                         SET autocommit = 0;
1139                         REPEaT
1140                         SET i = i+1;
1141                         INSERT INTO dept(deptno,dname,loc) VaLUES((STaRT+i),rand_str(10),rand_str(8));
1142                         UNTIL i=max_num
1143                         END REPEaT;
1144                         COMMIT;
1145                         END $$
1146                 3.3.1.5 调用存储过程
1147                     dept
1148                         DELIMITER ;
1149                         CaLL insert_dept(100,10);
1150                     emp
1151                         #执行存储过程,往emp表添加50万条数据
1152                         DELIMITER ;
1153                         CaLL insert_emp(100001,500000);               
1154             
1155         3.4 Show Profile
1156             是什么:是mysql提供用来分析当前会话中语句执行的资源消耗情况。可以用于SQL的调优测量
1157             官网:http://dev.mysql.com/doc/refman/5.5/en/show-profile.html
1158             默认情况下,参数处于关闭状态并保存最近15次的运行结果
1159             分析步骤
1160                 3.4.1 是否支持,看看当前的mysql版本是否支持
1161                     SHOW VaRIaBLES LIKE 'profiling';
1162                 3.4.2 开启功能,默认是关闭,使用前需要开启
1163                     set profiling=on;
1164                 3.4.3 运行SQL 
1165                     select * from emp group by id%10 limit 150000;
1166                     select * from emp group by id%29 order by 5
1167                 3.4.4 查看结果,show profiles
1168                 3.4.5 诊断sql,show profile cpu,block io for query  上一步前面的问题SQL数字号码;
1169                     type
1170                         |all --显示所有的开销信息
1171                         |block io --显示块io相关开销
1172                         |context switches --上下文切换相关开销
1173                         |cpu --显示cpu相关开销信息
1174                         |ipc --显示发送和接收开销相关信息
1175                         |memory --显示内存相关开销信息
1176                         |page faults --显示页面错误相关开销信息
1177                         |source --显示和source_function,source_file,source_line相关的开销信息
1178                         |swaps --显示交换次数相关开销的信息
1179                         
1180                 3.4.6 日常开发需要注意的结论
1181                     3.4.6.1 convertion HEaP to MyISaM 查询结果太大,内存都不够用了往磁盘上搬了。
1182                     3.4.6.2 Creating tmp table 创建临时表 
1183                         拷贝数据到临时表
1184                         用完再删除
1185                     3.4.6.3 Coping to tmp table on disk 把内存中临时表复制到磁盘,危险!!!
1186                     3.4.6.4 locked
1187                     “测试环境使用,生产环境不要使用”
1188         3.5全局查询日志
1189             配置使用
1190                 在mysql的my.cnf中,设置如下:
1191                 #开启
1192                 general_log=1
1193                 # 记录日志文件的路径
1194                 general_log_file=/path/logfile
1195                 #输出格式
1196                 log_output=File
1197                 
1198             编码开启
1199                 命令:
1200                 set global general_log=1;
1201                 set global log_output='TaBLE';
1202                 此后,你所编写的sql语句,将会记录到mysql库里的general_log表,可以使用下面的命令查看
1203                 select * from mysql.general_log;
1204             “永远不要在生产环境开启这个功能。”
1205             
1206     4、Mysql锁机制 
1207         4.1概述           
1208             4.1.1 定义 
1209                 锁是计算机协调多个进程或线程并发访问某一资源的机制。
1210                 在数据库中,除传统的计算资源(如cpu、RaM、I/O等)的争用以外,数据也是一种供许多用户共享的资源,如何保证数据并发访问的一致性,有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素,从这个角度来说,锁对数据库而言显得尤关重要,也更加复杂。
1211             4.1.2 生活购物
1212                 打个比方,我们到淘宝上买一件商品,商品只有一件库存,这个时候如果还有另一个人吗,
1213                 那么如何解决是你买到还是另一个人买到的问题?
1214                 这里肯定要用到事务,我们从库存表中取出物品数量,然后插入订单,付款后插入付款表信息,
1215                 然后更新商品数量,在这个过程中,使用锁可以对有限的资源进行保护,解决隔离和并发的矛盾。
1216             4.1.3 锁的分类
1217                 4.1.3.1 从对数据操作的类型(读\写)分
1218                     读锁(共享锁):针对同一份数据,多个读操作可以同时进行而不会互相影响。
1219                     写锁(排他锁):当前写操作没有完成前,他会阻断其他写锁和读锁。
1220                 4.1.3.2 从对数据操作的粒度分
1221                     表锁
1222                     行锁
1223         4.2表锁
1224             4.2.1 特点
1225                 偏向MyISaM存储引擎,开销小,加锁块,无死锁,锁粒度大,发生锁冲突的概率最高,并发最低。
1226             4.2.2 案例分析
1227                 4.2.2.1 建表SQL
1228                     【表级锁分析-建表SQL】
1229                     create table mylock(
1230                     id int not null primary key auto_increment,
1231                     name varchar(20)
1232                     )engine myisam;
1233                     
1234                     insert into mylock(name) values(a');
1235                     insert into mylock(name) values('b');
1236                     insert into mylock(name) values('c');
1237                     insert into mylock(name) values('d');
1238                     insert into mylock(name) values('e');
1239                     
1240                     select * from mylock;
1241                     
1242                     【手动增加表锁】
1243                     lock table 表名字 read(write),表名字2read(write),其他;
1244                     【查看表上加过的锁】
1245                     show open tables;
1246                     LOCK TaBLE mylock REaD,books WRITE;
1247                     【释放表锁】
1248                     unlock tables;
1249                 4.2.2.2 加读锁
1250                     读锁可共享
1251                     我们为mylock表加read锁(读阻塞写例子)
1252                     session1                                                             session2
1253                     获得表mylock的REaD锁定;lock table mylock read;                     连接终端                   
1254                     当前session可以查询表的记录;select * from mylock;                其他session也可以查询表的记录;select * from mylock;                      
1255                     当前session不能查询其他没有锁定的表                               其他session可以查询或者更新未锁定的表                    
1256                     当前session中插入或者更新锁定的表都会提示错误;                 其他session插入或者更新锁定表“会一直等待”获得锁
1257                     释放锁                                                                           session2获得锁,插入完成  
1258                 4.2.2.4 加写锁
1259                     我们为mylock表加write锁(MyISaM存储引擎的写阻塞读例子)
1260                     session_1                                                           session_2
1261                     获取表mylock的write锁定lock table mylock write;                   “待session开启写锁后”,session2再连接中断
1262                     当前session对锁定表的查询+更新+插入操作都可以执行;               其他session对锁定的表查询被阻塞,需要等待锁被释放;备注:如果可以,请换成不同的id来进行测试,因为mysql聪明有缓存,第2次的条件会从缓存取得,影响锁效果演示
1263                     释放锁                                         session2获得锁,查询返回
1264             4.2.3 案例结论
1265                 MyISM在执行查询语句(select)前,会自动给涉及的所有表加读锁,在执行增删改操作前,会自动给涉及的表加锁。
1266                 MySQL的表级锁有两种模式:
1267                 表共享读锁(Table Read Lock)
1268                 表独占读锁(Table Write Lock)
1269                 锁类型     可否兼容      读锁    写锁
1270                 读锁          是           是       否
1271                 写锁          是           否       否
1272                 结论:
1273                     结合上表,所以对MyISaM表进行操作,会有以下情况:
1274                         ①、所以对MyISaM表进行操作(加读锁),不会阻塞其他进程对同一表的读请求,但会阻塞对同一表的写请求。只有当读写锁释放后。才会执行其他进程的写操作
1275                         ②、对MyISaM表的写操作(加写锁),会阻塞其他进程对统一表的读和写的操作,只有当写释放后,才会执行其他进程的读写操作。
1276                         简而言之,,就是读写会阻塞写,但是不会堵塞,写锁则会把读和写都堵塞。
1277                         
1278             4.2.4 表锁分析
1279                 【看看哪些表被加锁了】
1280                 show open tables
1281                 【如何分析表锁定】
1282                 可以通过检查table_locks_waited和table_locks_immediate状态变量来分析系统上的表锁定;
1283                 SQL:show status like 'table%';
1284                 这里有两个状态变量记录MySQL内部表级锁定的情况,两个变量说明如下:
1285                 table_locks_immediate:产生表级锁定的次数,表示可以立即获取锁的查询次数,每立即获取锁值加1;
1286                 Table_locks_waited:出现表级锁定争用而发生等待的次数(不能立即获取锁的次数,每等待一次锁值加1),此值高则说明存在着较严重的表级锁争用情况;
1287                 
1288                 “此外,MyISaM的读写锁调度是写优先,这也是myisam不适合做写为主表的引擎。因为写锁后,其他线程不能做任何操作,大量更新回事查询很难得到锁,从而造成永久阻塞”
1289                 
1290         4.3行锁
1291             4.3.1 特点
1292                 偏向innodb存储引擎,开销大,加锁慢;会出现死锁;锁粒度最小,发生冲突的概率最低,并发度最高。
1293                 innodb与MyISaM的最大不同有两点:一是支持事务(TRaNSaCTION):二是采用了行级锁
1294             4.3.2 ’由于行锁支持事务‘,复习老知识
1295                 事务(Transaction)及其aCID属性
1296                     事务是由一组sql语句组成逻辑处理单元,事务具有以下四个属性,通常简称为事务的aCID属性
1297                     《原子性atomcity》:事务是一个原子操作单元,其对数据的修改,要么全执行,要么全部不执行
1298                     《一致性Consistent》:在事务开始和完成时,数据必须保持一致状态,这意味着所有相关的数据规则都必须应用于事务的修改,以保持
1299                         数据的完整性;事务结束时,所有内部的数据结构(如B树索引或双向链表)也都必须是正确的。
1300                     《隔离性Isolation》:数据库系统提供一定的隔离机制,保证事务不在受外部并发操作影响的”独立“环境执行,这意味着事务处理过程中国的中间状态对外部是不可见的,
1301                         反之亦然。
1302                     《持久性Durable》:事务完成之后,它对于数据的修改时永久性的,即使出现系统故障也能够保持。
1303                 并发事务处理 带来的问题
1304                     更新丢失(lost update)
1305                     脏读(dirty reads)
1306                     不可重复读(Non-Repeatable Reads)
1307                     幻读(Phatom Reads)
1308                 事务隔离级别
1309                     未提交读
1310                     已提交读
1311                     可重复读
1312                     可序列化
1313             4.3.3 案例分析
1314                 4.3.3.1 建表SQL
1315                     create table test_innodb_lock(a int(11),b varchar(16))engine=innodb;
1316                     
1317                     insert into test_innodb_lock values(1,'b2');
1318                     insert into test_innodb_lock values(3,'3');
1319                     insert into test_innodb_lock values(4,'4000');
1320                     insert into test_innodb_lock values(5,'5000');
1321                     insert into test_innodb_lock values(6,'6000');
1322                     insert into test_innodb_lock values(7,'7000');
1323                     insert into test_innodb_lock values(8,'8000');
1324                     insert into test_innodb_lock values(9,'9000');
1325                     insert into test_innodb_lock values(1,'b1);
1326                     
1327                     create index test_innodb_a_ind on test_innodb_lock(a);
1328                     
1329                     create index test_innodb_lock_b_ind on test_innodb_lock(b);
1330                     
1331                     select * from test_innodb_lock;
1332                 4.3.3.2 行锁定基本演示
1333                     行锁定基本演示
1334                     Session_1                       Session_2
1335                     set autocommit=0;               set autocommit=0;
1336                     更新但是不提交,没有手写commit     session_2被阻塞,只等待
1337                     update test_innodb_lock set b = 'b1' where a = 1;           update test_innodb_lock set b = 'b1' where a = 1;两次
1338                     提交更新                                                    接触阻塞,更新正常进行
1339                     commit;                                                     update test_innodb_lock set b = 'b1' where a = 1;
1340                                                                                 commit;
1341                     下面试试1号会话更新a=1                                       下面试试2号会话更新a=9
1342                     
1343                 4.3.3.3 无索引行锁升级为表锁
1344                 4.3.3.2 间隙锁危害
1345                     【什么是间隙锁】
1346                         但我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引加锁,对于键值在条件范围内
1347                         但并不存在的记录,叫做“间隙(GAP)”,
1348                         innodB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(next-key锁)
1349                     【危害】
1350                         因为Query执行过程中通过范围查找到话,他会锁定整个范围内所有的索引键值,即使这个键值并不存在。
1351                         间隙锁有一个比较致命的弱点,就是当锁定一个范围键值之后,即使某系不存在的键值也会被无辜锁定,而造成锁定的时候无法插入锁定键值范围内的任何数据。
1352                         在某些场景下这可能对性能造成很大危害。
1353                 4.3.3.3 面试题:常考如何锁定一行
1354                     #begin1355                     select * from test_innodb_lock where a=8 for update;
1356                     commit
1357                 
1358             4.3.4 案例结论
1359                 Innodb存储引擎由于实现了行级锁定,虽然在锁定机制的实现带来的性能损耗可能比表级锁定会更高一些,但是在整理并发处理能力方面要远远由于MyISAM的表级锁定。
1360                 当系统并发量较高的时候,innodb的整体性能和MyISAM相比较就会有比较明显的优势了。
1361                 但是,innodb的行级锁定也有其脆弱的一面,当我们使用不当的时候,可能会让innodb的整体性能表现不仅不能比MyISAM高,甚至可能会更差
1362             4.3.5 行锁分析
1363                 【如何分析行锁定】
1364                 通过检查InnoDB_row_lock状态变量来分析系统上的行锁的争夺情况
1365                 mysql>show status like 'Innodb_row_lock';
1366                 对各个状态量的说明如下:
1367                 InnoDB_row_lock_current_waits;当前正在等待锁的数量
1368                 InnoDB_row_lock_time;从系统启动到现在锁定的总时间长度;
1369                 InnoDB_row_lock_time_avg;每次等待所花平均时间
1370                 InnoDB_row_lock_time_max;从系统启动到现在等待最长的一次所花的时间;
1371                 InnoDB_row_lock_waits;系统启动后到现在总共等待的次数;
1372                 对于这5个状态变量:比较重要的主要是
1373                 “InnoDB_row_lock_time_avg“
1374                  “InnoDB_row_lock_time”
1375                  ”InnoDB_row_lock_waits“
1376                  尤其当等待次数很高,而且等待时长也不小的时候,我们就需要分析系统中为什么会有如此多的等待,然后根据分析结果着手指定优化计划
1377             4.3.6 优化建议
1378                 尽可能让所有数据检索通过索引来完成,避免无索引行锁升级为表锁。
1379                 合理设计索引,尽量缩小锁的范围
1380                 尽可能较少的检索条件,避免间隙锁
1381                 尽量控制事务大小,减少锁定资源量和时间长度
1382                 尽可能低级别事务隔离
1383         4.4页锁
1384         4.4小结
1385         开锁、加锁速度、死锁、粒度、并发性能只能就具体的应用特点来说那种更适合
1386     5、主从复制
1387         5.1 复制的基本原理
1388             5.1.1 slave会从master读取binlog来进行数据同步
1389             5.1.2 三步骤+原理图
1390                 mysql复制过程分为三个步骤:
1391                 ①master将改变记录到二进制日志(binary log)。这些记录过程叫做二进制日志事件,binary log events;
1392                 ②slave将master的binary log events拷贝到它的中继日志(relay log);                
1393                 ③slave重做中继日志中额事件,将改变应用到自己的数据库中,Mysql复制是异步的且串行化的
1394         5.2 复制的基本原则
1395             5.2.1 每个slave只有一个master
1396             5.2.2 每个slave只能有一个唯一的服务器ID
1397             5.2.3 每个master可以有多个slave
1398         5.3 复制的最大问题
1399             延时
1400         5.4 一主一从常见配置
1401             5.4.1 mysql版本一致且后台以服务运行
1402             5.4.2 主从都配置在【mysql】节点下,都是小写
1403             5.4.3 主机修改my.ini配置文件
1404                 ①【必须】主服务器唯一ID
1405                     server-id=1
1406                 ②【必须】启用二进制日志
1407                     log-bin=自己本地的路径/mysqlbin
1408                     log-bin=D:/devSoft/MySQLServer5.5/data/mysqlbin
1409                 ③【可选】启动错误日志
1410                     log-err=自己本地路径/mysqlerr
1411                     log-err=D:/devSoft/MySQLServer5.5/data/mysqlerr
1412                 ④【可选】根目录
1413                     basedir="D:/devSoft/MySQLServer5.5/"
1414                 ⑤【可选】临时目录
1415                     tmpdir="自己本地路径"
1416                     tmpdir="D:/devSoft/MySQLServer5.5/"
1417                 ⑥【可选】数据目录
1418                     datadir="自己的本地路径/data"
1419                     datadir="D:/devSoft/MySQLServer5.5/data"
1420read-only
1421                     主机读写都可以
1422                 ⑧【可选】设置不要复制的数据库
1423                     binlog-igore-db=mysql
1424                 ⑨【可选】设置需要复制的数据库
1425                     binlog-do-db=需要复制的主数据名字
1426             5.4.4 从机修改my.cnf配置文件
1427                 ①【必须】从服务器唯一ID
1428                 ②【可选】启用二进制日志
1429             5.4.5 因修改过配置文件,请主机+从机都重启后台mysql服务
1430                 windows手动关闭
1431                 linux防火墙 service ipatables stop
1432             5.4.6 主机从机都关闭防火墙
1433             5.4.7 在windows主机上建立账户并授权slave
1434                 GRANT REPLICATION SLAVE ON '*.*' TO 'zhangsan'@从机器数据库IP'IDENTIFIED BY '123456';flush privileges;
1435                 查询master状态
1436                     show master status;
1437                     记录下File和Postion的值
1438                 执行完此步骤后不要在操作主服务器MYSQL,防止主服务器状态值发生变化
1439             5.4.8 在linux上配置需要复制的主机
1440                 5.4.8.1 CHANGE MASTER TO MASTER_HOST='主机IP',MASTER_USER='zhangsan',MASTER_PASSWORD='123456',MASTER_LOG_FILE='FILE名字',
1441                 MASTER_LOG_POS=Position数字;
1442                 5.4.8.2 启动从服务器复制功能
1443                 5.4.8.3 show slave status\G
1444                     下面两个参数都是Yes,则说明主从配置成功!
1445                     Slave_IO_Running:Yes
1446                     Slave_SQL_Running:Yes
1447             5.4.9 主机新建库、新建表、insert记录,从机复制
1448             5.4.10 如何停止从服务器复制功能
1449                 stop slave;

 

posted @ 2020-03-17 19:45  klandehu  阅读(536)  评论(0)    收藏  举报