一.性能下降SQL慢执行时间长等待时间长
(1)查询语句写的烂
(2)索引失效:单值索引:给该表的某一个字段建立索引
多值
(3)关联查询太多join(设计缺陷或不得已的需求)
(4)服务器调优及各个参数设置(缓冲,线程数等)
二、常见通用的Join查询
1.SQL执行顺序
手写
机读
总结
2.Join图
create database db01;
CREATE TABLE `tbl_dept` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `deptName` VARCHAR(30) DEFAULT NULL, `locAdd` VARCHAR(40)
DEFAULT NULL, PRIMARY KEY(`id`) )ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `tbl_emp` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(20) DEFAULT NULL, `deptid` INT(11) DEFAULT NULL, PRIMARY KEY(`id`), KEY `fk_dept_id`(`deptid`) )ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO tbl_dept(deptName, locAdd) VALUES('RD', 11);
INSERT INTO tbl_dept(deptName, locAdd) VALUES('HR', 12);
INSERT INTO tbl_dept(deptName, locAdd) VALUES('MK', 13);
INSERT INTO tbl_dept(deptName, locAdd) VALUES('MIS', 14);
INSERT INTO tbl_dept(deptName, locAdd) VALUES('FD', 15);
INSERT INTO tbl_emp(NAME, deptId) VALUES('z3', 1);
INSERT INTO tbl_emp(NAME, deptId) VALUES('z4', 1);
INSERT INTO tbl_emp(NAME, deptId) VALUES('z5', 1);
INSERT INTO tbl_emp(NAME, deptId) VALUES('w5', 2);
INSERT INTO tbl_emp(NAME, deptId) VALUES('w6', 2);
INSERT INTO tbl_emp(NAME, deptId) VALUES('s7', 3);
INSERT INTO tbl_emp(NAME, deptId) VALUES('s8', 4);
INSERT INTO tbl_emp(NAME, deptId) VALUES('s9', 51);
1. A inner join B
select *from tbl_emp a inner join tbl_dept b on a.deptid = b.id;
2.A left join B
select *from tbl_emp a left join tbl_dept b on a.deptid = b.id;
3.A right join B
select *from tbl_emp a right join tbl_dept b on a.deptid = b.id;
4.左连接,A表独有 A left join B where b.id is null
select *from tbl_emp a left join tbl_dept b on a.deptid = b.id where b.id is null;
5.右连接,B表独有 A right join B where a.deptid is null
select *from tbl_emp a right join tbl_dept b on a.deptid = b.id where a.deptid is null;
6.full outer join -> A left join B union A right join B, union去重
FULL OUTER JOIN mysql不支持这种语法!!
mysql如何查询两张表独有的数据,且能查询两表共有的数据且不重复?
select *from tbl_emp a left join tbl_dept b on a.deptid = b.id union select *from tbl_emp a right join tbl_dept b on a.deptid = b.id;
7.a,b两表独有
select *from tbl_emp a left join tbl_dept b on a.deptid = b.id where b.id is null union select *from tbl_emp a right join tbl_dept b on a.deptid = b.id where a.deptid is null
三、索引是什么
(1)MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构,可以得到索引的本质:索引是数据结构。
索引的目的在于提高查询效率,可以类比字典。
如果要查“mysql”这个单词,我们可定需要定位到m字典,然后从上往下找到y字母,在找到剩下的sql。如果没有索引,那么你可能需要a-z,如果我想找到Java开头的单词呢?或者Oracle开头的单词能?是不是觉得如果没有索引,这个事情根本无法完成?
(2)你可以简单理解为“排好序的快速查找数据结构”
详解:
结论:数据本身之外,数据库还维护着一个满足特定查找算法的数据结构,这些数据结构以某种方式指向数据,这样就可以在浙西数据结构的基础上实现高级查找算法,这种数据结构就是索引。
(3)一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储在磁盘上
(4)我们平常所说的索引,如果没有特别指明,都是指B树(多路搜索树,并不一定是二叉的)结构组织的索引。其中聚簇索引,次要索引,覆盖索引,符合索引,前缀索引,唯一索引默认都是使用B+树索引,统称索引。当然,除了B+树这种类型的索引之外,还有哈希索引(hash index)等。
四、索引优势
(1)类似大学图书馆建书目索引,提高数据库检索的效率,降低数据库的IO成本
(2)通过索引列对数据进行排序,降低数据排序的成本,降低了CPU的消耗
五、索引劣势
(1)实际上索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录索引列也是要占用空间的
(2)虽然索引大大提高了查询速度,同时确会降低更新表的速度,如对表进行INSERT、UPDATE、DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段。都会调整因为更新所带来的键值变化后的索引信息
(3)索引只是高效的一个因素,如果你的MySQL有大数据量的表,就需要花时间研究建立最优秀的索引,或优化查询语句
六、索引分类
1.分类
单值索引:即一个索引只包含单个列,一个表可以有多个单列索引,最多一张表不要超过5个
唯一索引:索引列的值必须唯一,但允许有空值,例如手机号,银行卡号等值必须是唯一
复合索引:即一个索引包含多个列,例如手机号和银行卡号一起,如果一个表中的数据在查询时有多个字段总是同时出现则这些字段就可以作为复合索引
2.基本语法
创建:create [unique] index indexName on tbname(columnname(lenght));
如果是CHAR,VARCHAR类型,length可以小于字段实际长度;如果是BLOB和TEXT类型,必须指定length
alter mytable add [UNIQUE] INDEX [indexName] on (columnname(lenght));
更改:alter table tbname add [unique] index [indexName] on (columnname(length));
更改:alter table tbname add [unique] fulltext [indexName] on (columnname(length));#指定索引为fulltext,用于全文索引
删除:drop index [indexName] on tbname;
查看:show index from tbname\G;
使用ALTER命令:
七、索引结构
BTree索引
检索原理:
Hash索引
full-text全文索引
R-Tree索引
七、哪种情况需要创建索引
1.主键自动建立唯一索引
2.频繁作为查询条件的字段应该创建索引
3.查询中与其他表关联的字段,外键关系建立索引
4.频繁更新的字段不适合创建索引,因为每次更新不单单是更新数据还会更新索引
5.Where条件里用得到的字段适合创建索引
6.单键/组合索引的选择问题,在高并发下倾向创建组合索引
7.查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度
8.查询中统计或者分组字段
八、哪种情况不需要建索引
1.表记录太少(一般生产环境下,三百万条记录性能就可能开始下降,官方说的是五百万到八百万)
2.经常增删改的表(Why:提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件)
3.数据重复且分布平均的表字段,因此应该只为最经常查询和最经常排序的数据列建立索引。
注意,如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果。
九、性能分析
1.MySQL Query Optimizer(查询优化器)
1.1MySQL中有专门负责优化select语句的优化器模块,主要功能:通过计算分析系统中收集到的统计信息,为客户端请求的query提供它认为最有的执行计划(它认为最优的数据检索方式,但不见得是DBA认为是最优的,这部分是最耗时间的)
1.2当客户端向MySQL请求一条query,命令解析其模块完成请求分类,区别是select并转发给MySQL Query Optimizer时,MySQL Query Optimizer首先会对整条Query进行优化,处理掉一些常量表达式的预算,直接转换成常量值,并对query中的查询条件进行简化和转换,如去掉一些无用或显而易见的条件,结构调整等,然后分析query中的Hint信息(如果有),看显示Hint信息是否可以完全确定该query的执行计划,如果没有Hint或Hint信息不足以完全确定执行计划,则会读取所涉及对象的统计信息,根据query进行写相应的计算分析,然后再得出最后的执行计划。
2.MySQL常见瓶颈
CPU:CPU在饱和的时候一般发生在数据装入内存或从磁盘读取数据时候
IO:磁盘IO瓶颈发生在装入数据远大于内存容量的时候
服务器硬件的性能瓶颈,top,free,iostat和vmstat来查看系统的性能状态
3.Explain
(1)是什么(查看执行计划):使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是表结构的性能瓶颈
官网介绍
(2)能干嘛:
表的读取顺序(数字大的先读,相同的则由上而下读取)
数据读取操作的操作类型
哪些索引可以使用
哪些索引被实际使用
索引总长度
表之间的引用
每张表有多少行被优化器查询
额外的信息(出现using index较好,出现using filesort较差)
(3)explain+SQL语句
执行计划包含以下的信息
id | select_type | table | type | possible_keys | key | key_len | ref | rows | extra |
(4)各字段解释
[1]id介绍:select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序
三种情况:id相同,执行顺序由上至下
id不同:如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
id相同不同,同时存在
[2]select_type
有哪些:
查询的类型,主要是用于区别普通查询、联合查询、子查询等的复杂查询
[3]table:显示这一行的数据是关于哪张表的
[4]type:访问类型排列,显示查询使用了何种类型,是较为重要的一个指标,从最好到最差依次是:system>const>eq_ref>ref>range>index>ALL
当前,type其实还有很多种。system>const>eq_ref>ref>fulltext>ref_or_null>index_merge_unique_subquery>index_subquery>range>index>ALL。
一般来说,得保证查询至少达到range级别,最好能达到ref。
type的详解:
system:表只有一行记录(等于系统表),这是const类型的特例,平时不会出现,这个也可以忽略不计。
const:表示通过索引一次就找到了,const用于比较primary key或者unique索引。因为只匹配一行数据,所以很快。如将逐渐置于where列表中,MySQL就能将该查询转换为一个常量
system const举例:其实就是单行单表这样查询速度的确最快。
eq_ref:唯一索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描
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]possiable_keys:显示可能应用在这张表中的索引,一个或多个。查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被使用。
[6]key:实际使用的索引。如果为NULL,则没有使用索引。
查询中若使用了覆盖索引,则该索引仅出现在key列表中
[7]key_len:表示索引中使用的字节数,而通过该列计算查询中使用的索引的长度。在不损失精确性的情况下,长度越短越好。
显示的值为索引字段的最大可能长度,并非实际使用长度。即key_len是根据表定义计算而得,不是通过表内检索出
的
[8]ref显示索引的哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值
[9]rows:根据表统计信息及索引选用情况,大致估算出找到所需的记录所需的行数
[10]Extra:包含不适合在其他列中显示但十分重要的额外信息
using filesort九死一生:说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。MySQL中无法利用索引完成的排序操作称为“文件排序”
using temorary十死无生:用不上索引还产生了临时表。使用了临时表保存中间结果,MySQL在对查询结果排序时使用临时表,常见排序order by和分组查询group by
use index不错
表示相应的select操作中使用了覆盖索引(convering index),避免访问了表的数据行,效率不错
如果同时出现using where,表明索引被用来执行键值的查找;
如果没有同时出现using where,表明索引用来读取数据而非执行查找动作