课程目的:写出高质量SQL语句,数据库参数调优,建立使用索引
1.MySQL架构介绍
高级内容包括:内核可以优化改写,服务器配置文件可以优化改写,参数常量优化,sql优化,主从复制,软硬件升级,容灾备份,sql编程
linux安装mysql:储存位置
图片.pngMysql配置文件
log-bin:二进制日志,用于主从复制
log-error:默认关闭,记录严重的警告和错误信息
log:默认关闭,记录查询的sql语句,用于查询分析
数据文件:
- /var/lib/mysql 或用语句查询 ls -lF | grep ^d
- frm文件:存放一个数据库的表结构
- myd文件:数据
- myi文件:数据索引
如何配置:win:my.ini linux:/etc/my.cnf
Mysql逻辑架构
- 连接层
- 服务层
- 引擎层
- 存储层
Parser:将SQL语句重组过滤,从from开始解析( 转化为关系代数表达式?)
optimizer:优化器。找到更好的等价的关系代数表达式。仅仅优化为mysql自己认为好的,可导致索引失效
cache & buffer:缓存缓冲。
存储引擎:可插拔式的存储引擎将查询处理和其他的系统任务以及数据存储提取相隔离。常用的是MyISAM和InnoDB。
存储引擎介绍
图片.pngInnoDB支持事务,行锁,表锁,外键
MyISAM关注读
InnoDB关注写
2.索引优化分析
性能下降
四个原因:
- 查询语句写的烂
- 索引失效
- 关联查询太多join(设计缺陷或不得已的需求)
- 服务器调优及各个参数的设置(缓冲、线程数等)
join相关
SQL执行顺序
手写顺序:
图片.png机读顺序:
图片.png总结:
图片.png七种JOIN理论
图片.png 图片.png注:Mysql不支持FULL OUTER全连接查询。要得到这个结果需要使用UNION(能把两个查询结果并起来而且去重)
select 语句1 UNION select 语句2
索引
官方定义:帮助MySQL高效获取数据的数据结构。
即:
排好序的快速查找数据结构(两大功能:查的块,排好序)
类比于字典 :如果要查找”mysql“这个单词,先定位到m字母,再往下找到y,再找到剩下的sql。
索引会影响到:
- where后面的条件
- order by 后面的排序字段
数据库系统维护着满足特定查找算法的数据结构,这种数据结构以某种方式指向数据。
图片.png二叉查找树的每一个节点包含 索引键值 和 一个指向对应数据记录物理地址的指针。这就能快速地检索符合要求的记录。
我们平常说的索引,如果没有特别指明,都是指B树(多路搜索树,不一定是二叉的)结构组织的索引。其中聚集索引、次要索引、覆盖索引、复合索引、前缀索引、唯一索引默认都是用B+数。此外还有哈希索引。
索引优势:
- 提高数据库检索效率,降低数据库IO成本
- 通过索引列对数据进行排序,降低数据排序成本,降低了CPU消耗
索引劣势:
- 实际上索引也是一张表,此表保存了主键和索引字段,并指向实体表的记录,所以索引列也是要占空间的
- 降低了表的更新速度,如insert、updata、delete。因为不仅要保存数据,还要改动索引文件。
- 索引只是提高效率的一个因素,如果有大数据量的表,需要花时间研究建立最优秀的索引。
索引分类
-
单值索引:一个索引只包含单个列,一个表可以有多个单列索引(复合索引优于单值索引)(一张表索引不要超过5个)(一次查询只能用一个索引)
-
唯一索引:索引列的值必须唯一,但允许有空值
-
复合索引:一个索引包含多个列
-
基本语法:
- 创建:create [unique] index indexName ON mytable(columnName(length)); alter mytable add [unique] index [indexName] ON (columnName(length));
- 删除:drop index [indexName] on mytable;
- 查看:show index from table_name;
索引结构
四种索引结构:BTree索引、Hash索引、full-text全文索引、R-TREE索引
BTREE:
图片.png 图片.png需要与不需要建立索引的情况
需要建立:
- 主键自动作为唯一索引
- 频繁作为查找条件的字段
- 查询中与其他表关联的字段,外键关系建立索引。
- 频繁更新的字段不应该建立索引
- where条件里用不到的字段不适合建立索引
- 高并发情况应该建立组合索引
- 查询中排序的字段。(排序字段通过索引去访问能大大提高排序速度)
- 查询中统计和分组的字段(分组之前必须排序)
不需要建立:
- 表记录太少(三百万以上效率就开始下降)
- 经常增删改的表。
- 数据重复且分布平均的字段。(如果某个数据列包含太多重复的内容,建立索引没太大效果)
- 索引的选择性:索引列中不同值的数目与表中记录数的比。越接近1,索引效率就越高。
性能分析
优化器模块的作用: 通过计算分析系统中收集到的统计信息,为客户端请求的Query提供它认为最优的执行计划
MySQL常见瓶颈:
- CPU:CPU饱和经常发生在数据装入内存或从磁盘读取数据的时候
- IO:IO瓶颈发生在装入数据量远大于内存的时候
- 服务器硬件性能瓶颈:用top、free、iostat和vmstat来查看系统的性能状态
explain(查看执行计划):模拟优化器执行sql查询语句,从而知道mysql是如何处理sql语句的,分析性能瓶颈。
能查出:
- 表的读取顺序:id
- 数据读取操作的操作类型:select_type
- 哪些索引可以使用:possible_keys
- 哪些索引被实际使用:key
- 表之间的引用:ref
- 每张表有多少行被优化器查询:rows(越小越好)
- id:序列号,表示查询中执行select子句或操作表的顺序
- id相同,执行顺序由上至下
- 如果是子查询,id的序号会递增,id越大优先级越高,越先被执行
- id如果相同,可以认为是一组,从上往下执行。所有组中,id越大,优先级越高。
- select_type:查询类型
- SIMPLE:简单的select查询,不包含子查询或者UNION
- PRIMARY:****最外层的查询(包含复杂子查询的情况)
- SUBQUERY:在Select或where列表中包含了子查询
- DERIVED:在from中包含的子查询被标记为“衍生”,mysql会递归地执行这些子查询,把结果放在临时表里。后面的数字,指的是前面的id序列号。
- UNION: 若第二个select出现在union后,则被标记为union。若union包含在from子句的子查询中,外层的select将被标记为:DERIVED。
- UNION RESULT:从UNION获取的result
- table : 显示这一行数据是关于哪张表的。
- type:访问类型,显示查询使用了何种类型。最好到最差依次是:system >const>eq_ref>range>index >ALL.
- 大查询至少达到range级别,最好能达到ref
- system:表只有一行记录,等于系统表,const类型的特例
- const:表示通过索引一次就找到了。用于比较primary key或者unique索引。因为只匹配一行数据,所以很快。如将主键置于where列表中,mysql就能将该查询转化为一个常量。
- eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于 主键索引或唯一索引扫描。
- ref:非唯一性索引扫描。返回匹配某个单独值的所有行。(希望达到的级别)
- range:检索给定范围的列,使用一个索引来选择行。key显示使用了哪个索引。一般就是在where语句里出现了 between、<>、in等的查询。它开始于索引的某一点,结束语另一点,不用扫描全部索引。
- index:只遍历索引树,通常比all全表查快。
- all:遍历全表。超过百万就明显慢了。
- possible_keys:显示可能应用到这个表上的索引,可能有一个或多个。但该索引不一定被使用
- key:实际使用的索引。如果为null,则没有使用索引。 查询中若使用了覆盖索引,则该索引仅出现在key列表中,possible_keys里没有。( 覆盖索引:所查的字段正好与索引字段个数、顺序一致,或者where条件字段加上所查字段正好是复合索引字段,直接从索引里读数据)
- key_len:表示索引中使用的字节数,可通过该列计算查询中使用的索引长度。在不损失精确性的情况下,长度越短越好。为最大可能长度,并非实际使用长度。通过表定义计算得到,非通过表内检索找到。
- ref:显示索引的哪一列被使用了,如果可能的话,是一个常数。 哪些列或者常量被用于查找索引列上的值。
- rows:根据表的统计信息和索引选用情况,大致估计出找到所需记录所需要读取的行数。越小越好!!
- Extra:其他重要的信息。
- Using filesort:表示mysql会对数据使用一个外部的索引排序,而不是用表内的索引顺序。表示排序时没有用上索引!!! 常见于:建了组合索引,order by或group by 没有全部用上索引的字段。
- Using temporary:使用临时表保存了中间结果。常见于order by 和group by。绝对不好!!!
- Using index:表示相应的select操作使用了覆盖索引,避免了访问表的数据行, 效率不错! 如果同时出现了using where 表示索引被用来执行索引键值的查找;如果没有同时出现using where,表明索引用来读取数据而非执行查找。
- Using where:使用了where
- Using join buffer:使用了连接缓存
- impossible where:where子句的值总是false 不能用于获取值
索引优化
单表优化:
题目:查询category_id为1且comments大于1的情况下,views最多的article_id
建立索引1:针对category_id、comments、views建立复合索引
结果1:type变为range,key字段显示了索引,但Extra出现了Using filesort,说明针对views排序时,索引失效。
原理1:按照B树工作原理,先排序category_id,遇到相同时再排序comments,相同时再排序views。当comments字段在联合索引中处于中间位置时,因comments>1是一个范围条件(range),Mysql无法里利用索引再对后面的views部分进行检索,即range类型查询字段后的索引失效。
建立索引2:只针对category_id、views建立索引
结果2:type变为ref,Extra中的using filesort也消失了,结果理想
两表优化:
题目:左连接的时候,索引应该加在左表的id列还是右表的id列?
结果1:加在右表,右表的type变成ref,rows变成了1,结果理想
结果2:加在左表,左表的type变成index,row还是没变,结果不理想
原理:这是由左连接的特性决定的,left join条件用来决定如何从右表搜索行,左边一定都有,左表一定都是all。所以右表是关键点,一定要在右表建立索引。
同理,right join on 条件用于确定如何从左表搜索行,右边一定都有。所以索引一定要建在左表上。
三表优化:
结论:**如多个left join 并列 ,则在两个右表上建立索引。 ** 永远用小表驱动大表,因为主表全扫描是不可避免的。
原则:
- 减少join嵌套的次数,用小表驱动大表
- 优化嵌套的内层循环
- 保证join语句中被驱动表上的条件字段已经被索引
- 当无法保证被驱动表上的条件字段被索引时,不要太吝惜于joinbuffer的设置
避免索引失效
-
1.确保搜索条件与索引全值匹配。杜绝“空中楼阁”
-
2.最佳左前缀法则:如果使用了复合索引,查询从索引的最左前列开始并且不跳过索引中的列。
-
3.不要在索引列上做任何操作(计算,函数,类型转换)
-
4.范围条件后面(> \ < \ like)的索引字段会失效。(但是like 左边没有百分号的,后面的索引不会失效)
-
5.尽量使用覆盖索引(索引列和查询列一致)
-
6.使用不等于的时候无法使用索引
-
7.is null 或 is not null 无法使用索引
-
8.like 以 通配符开头(“%..”)会导致索引失效(最好在右边写通配符)
如果一定要使用通配符开头,用覆盖索引来弥补。(建的索引和所查字段个数、顺序上一致)
例子:在建立(name,age)复合索引的情况下,以下都用到了索引:
SELECT id FROM t WHRER name like "%aa%" (id 是自带的主键索引)
SELECT name, age FROM t WHRER name like "%aa%"
SELECT name FROM t WHRER name like "%aa%"
SELECT age FROM t WHRER name like "%aa%"
SELECT id,name, age FROM t WHRER name like "%aa%"
(当查询字段超过name和age,或者用* 的时候 索引失效)
-
9.字符串不加单引号会导致索引失效
-
10.少用or,用它连接时会导致索引失效
注意:
一般情况下 where和order by 的条件要遵循最佳左前缀法则,才能用的上索引。但有个特殊情况,当order by的条件字段有一个常量时,虽然顺序不对,仍然能用索引排序,不会filesort。
例如:对c1,c2,c3建立索引,select * from table where c1="a1" and c2="a2" order by c3, c2。虽然order by的顺序乱了,但是c2等于一个常量,order by c2 其实就对一个值排序,等于没排序。所以order by c3仍然能用索引,没有文件内排序。
group by 分组之前必排序,索引规则等同于order by。如果不用索引,会有临时表的产生。
使用覆盖索引能变快的原因:索引表中字段少了,储存得更加紧密,虽然总得行数和全表一样,但是储存的块少了,导致需要的IO变少,所以速度会快一点。
对于选择率低的字段,比如性别,建立一个索引,统计一个性比的人数时会有一倍的提升。因为索引表中,男女分开,只用读一半的数据就能统计出人数。但是一般只有提速10倍,才算不错的索引。
针对一个字段是不是要建索引,要在实际业务中,看一天的修改该字段的事物占(修改事务+查询事务)之比,大于20%就不要建索引。
网友评论