mysql高级

优化分析

一、存储引擎的对比

mysql高级

 

二、性能下降SQL慢 、执行时间长、等待时间长

  1. 查询语句复杂
  2. 索引失效(单值索引、复合索引)
  3. 关联查询有太多join(设计缺陷或不得已的需求)

三、常见的Join查询

  1. SQL执行顺序:手写、机读
  2. 手写顺序:
    #sql语句的手写顺序
    
    SELECT DISTINCT <select_list>
    FROM <left_table> <join_type>
    JOIN <right_table> ON <join_condition>
    WHERE <where_condition>
    GROUP BY <group_by_list>
    HAVING <having_condition>
    ORDER BY <order_by_condition>
    LIMIT <limit_number>
  3. 机读顺序:

    #机读顺序
    FROM <left_table> 
    ON <join_condition>
    <join_type> JOIN <right_table>
    WHERE <where_condition>
    GROUP BY <group_by_list>
    HAVING <having_condition>
    SELECT 
    DISTINCT <select_list>
    ORDER BY <order_by_condition>
    LIMIT <limit_number>

总结:https://database.51cto.com/art/201911/605471.htm

mysql高级

 

四、七种Join如下所示:

mysql高级

注意:mysql不支持全外连接,但是可以使用union(联合+去重)把左外连接和右外连接联合起来。

 

五、索引

定义:索引(Index)是帮助MySQL高效获取数据的数据结构 。索引的目的在于提高查找效率,类比字典。除了数据本身之外,数据库还维护一个满足特定查找算法的数据结构,这些数据结构以某种方式指向数据,这样就可以在这些数据结构的基础上实现高效的查找算法,这种数据结构就是索引(排序好的快速查找的数据结构)。

一般来说索引本身很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储在磁盘上

索引的优势

  1. 提高数据检索的效率,降低数据库的IO成本,类似大学图书馆建书目索引
  2. 通过索引对数据进行排序,降低数据排序的成本,降低了CPU的消耗

 

索引的劣势:

  1. 索引可以看成一张表,也要占用空间。
  2. 索引会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE,MySQL不仅要保存数据,还要保存一下索引文件每次更新添加的索引列的字段,都会调整因为更新所带来的键值变化后的索引信息。

 索引的分类:

  1. 单值索引:即一个索引只包含单个列,一个表可以有多个单列索引
  2. 唯一索引:索引列的值必须唯一,但允许有空值(比如身份证号就是唯一的,可以做唯一索引)
  3. 复合索引:即一个索引包含多个列

mysql索引结构:

  1. BTree索引
  2. Hash索引
  3. full-test全文索引
  4. R-Tree索引

哪些情况需要创建索引:

  1. 主键自动建立唯一索引
  2. 频繁作为查询条件的字段应该创建索引
  3. 查询中与其他表关联的字段,外键关系建立索引
  4. 频繁更新的字段不适合创建索引(因为每次更新不单单是更新了记录,还会更新索引)
  5. where条件里用不到的字段不创建索引
  6. 在高并发下倾向于创建组合索引
  7. 查询中排序的字段,排序字段若通过索引去访问将大大提高排序的速度
  8. 查询中统计或者分组的字段

 性能分析

1、Explain:使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的,分析你的查询语句或是表结构的性能瓶颈。

2、使用方法:

EXPLAIN SELECT * FROM <table>;

3、explain的作用:

通过EXPALIN,我们可以分析出以下结果:

  • 表的读取顺序
  • 数据读取操作的操作类型
  • 哪些索引可以使用
  • 哪些索引被实际使用
  • 表之间的引用
  • 每张表有多少行被优化器查询

 执行计划各个字段的含义     

mysql高级

1. id: select查询的序列号,表示查询中执行select子句或操作表的顺序

一、id会出现三种结果:

1.id相同,执行顺序由上至下

mysql高级

有上图可见,操作表的id号均为1,所以操作顺序为

d->l->employees

 

  2. id不同时,id值越大优先级越高,越先被执行           

mysql高级                                             

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

 

3. id既有相同的,又有不同的

说明:id如果相同,可以认为是一组,从上往下顺序执行;在所有组中,id值越大,优先级越高,越先执行

注意:执行过程中,衍生的表用derived表示。

 

二、查询类型select_type

作用:用来表示查询的类型,主要用于区别普通查询、联合查询、子查询等复杂查询

  • SIMPLE:  简单的select查询,查询中不包含子查询和UNION
  • PRIMARY:  查询中若包含任何复杂的子部分,最外层查询则被标记为PRIMARY
  • SUBQUERY: 在SELECT或WHERE列表中包含了子查询
  • DERIVED: 在FROM列表中包含的子查询被标记为DERIVED(衍生),MySQL会递归执行这些子查询,把结果放在临时表中
  • UNION:     若第二个SELECT出现在UNION之后,则被标记为UNION;若UNION包含在FROM子句的子查询中,外层的SELECT将被标记为DERIVED
  • UNION RESULT:UNION的最终结果

eg.

explain
select * from employees e left join departments d on e.department_id = d.department_id
union
select * from employees e right join departments d on e.department_id = d.department_id;

mysql高级

 

三、table 

table就是操作表

 

四、type

type表示使用了那种类型的查询,分为以下几种:

  1. ALL
  2. index
  3. range
  4. ref
  5. eq_ref
  6. const
  7. system
  8. NULL

查询效率从高到低依次为:

system > const > eq_ref > ref > range > index > all

一般来说,需要保证查询至少达到range级别,最好能达到ref。

  • system:表只有一行记录,很少出现
  • const:表通过索引一次就找到了,const用于比较primary key或者unique索引。
    select * from table where id(主键) = XX;

     

  • eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。
  • ref:非唯一性索引扫描,对于每个索引键,表中可以找到多个符合条件的行。
  • range:只检索给定范围的行,比如在where语句中出现between、<、>、in等查询
    select * from table where id between 30 and 60;

     

  • index:index与all的区别在于index类型只遍历索引树,这通常比all快,因为索引文件通常比数据文件小(也就是说all和index都是读全表,但index根据索引扫描然后回表取数据,而all是从硬盘中读取)
    select employee_id from employees;

     

  • all:遍历全表
    select * from employees;

     

 五、ref

将列与索引进行比较,主要用来表示表的连接条件(即哪些列或常量被用于查找索引列上的值)

#案例:查找部门编号为1700的员工信息
explain
select *
from employees e, departments d
where e.department_id = d.department_id
and d.location_id = 1700;

mysql高级

 分析结果可以看出:d表的location_id索引列匹配了一个常量(1700);e表的department_id索引列匹配了d表的department_id。他们之间的匹配关系我们可以清楚地从ref中查看到

 

六、rows

根据表的统计信息和索引的选用情况,大致估算出找到所需记录所需要读取的行数,rows列中的值,越小越好。

 

七、Extra

  1. Using filesort:说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取,这种无法利用表内索引进行的排序操作为“文件排序”。(不好)
    explain
    select last_name, department_id
    from employees
    order by salary;

     

  2. Using temporary:说明使用了临时表保存中间结果,常见于order by 和group by。(不好) 
  3. Using index:select操作中使用了覆盖索引(Covering Index)。
    覆盖索引,也叫索引覆盖:select的数据列只用从索引中就能够取得,不必从数据表中读取。mysql可以利用索引返回select列表的字段,即查询的列要被所建的索引覆盖
    explain
    select employee_id from employees;
    1,SIMPLE,employees,null,index,,dept_id_fk,5,null,107,100,Using index 
  4.  Using where:使用了where过滤
  5. Using join buffer:多表join的次数非常多
  6. impossible where:where逻辑错误

 八、索引优化

 索引优化的总结

  • 永远用小的结果集(主表)驱动大的结果集(驱动表)
  • 优先优化内层的
  • 保证join语句中被驱动表上的join条件字段被索引

九、索引失效

  • 全职匹配:查询的语句的字段和顺序恰好和建立的索引的字段和顺序一致,否则索引会失效;
  • 最佳左前缀法则:如果索引了多列,要遵守最左前缀法则(查询从索引的最左前列开始并且不能跳过索引中的列);
  • 不在索引上做任何操作,包括计算、函数、(手动或自动)的类型转换,会导致索引失效,进而进行全表扫描;
  • 不能使用索引中的范围条件右边的列;
  • 减少使用select *,尽量使用索引的查询即索引列和查询列一致;
  • 在使用不等于!= 、<> 的时候无法使用索引导致全表扫描;
  • like以通配符开头(‘%abc’)时,索引会失效变成全表扫描; 解决方法可以使用覆盖索引,但是该方法具有一定的局限性;
  • is null, is not null也无法使用索引;
  • 字符串不加单引号会导致索引失效;
  • 少用or,用它来连接时会失效;

 十、查询优化

  • 小表驱动大表
# 小表驱动大表
use myemployees;
# 员工表有107条数据
select count(*) from employees;
# 部门表有27条数据
select  count(*) from departments;

# 案例1.
# 88ms
select * from employees e
where e.department_id in (
    select d.department_id
    from departments d
);

# 107ms
select * from employees e
where exists(select 1 from departments d where d.department_id = e.department_id);

# 当d表的数据小于e表时,采用in要由于exists
# in后面跟的是小表,exists后面跟的是大表(in后小,exists大)
# select ...from table where exists(subquery)的理解:将主查询中的数据放入子查询中做条件验证,根据验证的结果(true/false)来决定主查询的数据是否保留
  • order by关键字优order 

    原则:尽量使用Index方式排序,避免使用FileSort方式排序。链接一

    filesort的原理,以及两种算法。链接二

 

 

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               

 

mysql高级

上一篇:php在iis上配置时报Fatal error: Call to undefined function mysql_connect() in 错误解决办法


下一篇:整型数据在内存中如何存储?