全国学渣代表  

B+tree mysql 索引底层B+tree

利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入。为了达到这个目的,在实际实现B-Tree还需要使用如下技巧:
每次新建节点时,直接申请一个页的空间,这样就保证一个节点物理上也存储在一个页里,加之计算机存储分配都是按页对齐的,就实现了一个node只需一次I/O。
由于B+Tree内节点去掉了data域,因此可以拥有更大的出度,拥有更好的性能。
B+树扫库、表能力更强
B+树的磁盘读写能力更强
B+树的排序能力更强
B+树的查询效率更加稳定


SHOW GLOBAL STATUS LIKE 'Innodb_page_size' 查看叶子节点的大小 16kb

数据库表存在哪里?

mysql 数据库是存储在磁盘上的,查看命令 show variables like 'datadir';

InnoDB 索引表结构显示

MyISAM 引擎表结构显示

两者引擎区别 :

构成上的区别:

  1. InnoDB支持外键,而MyISAM不支持。

  2. InnoDB支持事务,MyISAM不支持,对于InnoDB每一条SQL语言都默认封装成事务,自动提交

  3. InnoDB表必须有主键,而Myisam可以没有

如何选择:

1. 是否要支持事务,如果要请选择innodb,如果不需要可以考虑MyISAM;

2. 如果表中绝大多数都只是读查询,可以考虑MyISAM,如果既有读也有写,请使用InnoDB。

3. 系统奔溃后,MyISAM恢复起来更困难;

4. MySQL5.5版本开始Innodb已经成为Mysql的默认引擎(之前是MyISAM),说明其优势是有目共睹的,如果你不知道用什么,那就用InnoDB,至少不会差。

5. MYISAM 支持表所,InnoDB支持行锁 颗粒度比较细 (具体还很多就先写这些了)

接下来说一下并发量大、数据量大的互联网业务规范

 1.使用InnoDB,支持事务,并发量大,支持事务,能作用于表锁和行锁,cpu及内存缓存优化资源利用率比较高。

 2.必须使用UTF8字符集 万国码,无需转码,无乱码风险,节省空间

 3.数据表、数据字段必须加入中文注释 

 4.单表列数目必须小于30

 5.表必须有主键,例如自增主键

 6.禁止使用外键,如果有外键完整性约束,需要应用程序控制,外键会导致表与表之间耦合,update与delete操作都会涉及相关联的表,十分影响sql的性能,甚至会造成死锁。

 7.必须把字段定义为NOT NULL并且提供默认值 无论是表还是索引中每行中的null的列都需要额外的空间来标识

 8.必须使用varchar(20)存储手机号

 9.单表索引建议控制在5个以内

 10.禁止在更新十分频繁、区分度不高的属性上建立索引。更新会变更B+树,更新频繁的字段建立索引会大大降低数据库性能

 11.建立组合索引,必须把区分度高的字段放在前面

 12.禁止使用SELECT *,只获取必要的字段,需要显示说明列属性,读取不需要的列会增加CPU、IO、NET消耗

 13.禁止负向查询,以及%开头的模糊查询,负向查询条件:NOT、!=、<>、!<、!>、NOT IN、NOT LIKE等,会导致全表扫描,%开头的模糊查询,会导致全表扫描

sql 优化 (官方文档 https://dev.mysql.com/doc/refman/5.7/en/select-optimization.html)

# 状态命令 
SHOW FULL PROCESSLIST / SHOW PROCESSLIST 
kill id 进行抹杀 
sleep 等待客户端发送信息 (查看状态命令大全显示 https://dev.mysql.com/doc/refman/5.7/en/general-thread-states.html)
![](https://img2020.cnblogs.com/blog/1359266/202003/1359266-20200323095802845-1209718167.png)

# 缓存 
    SHOW VARIABLES LIKE '%query_cache%' ;  show status like 'Qcache%' 命令可查看缓存情况
    query_cache_type
    值:0 -– 不启用查询缓存,默认值;
    值:1 -– 启用查询缓存,只要符合查询缓存的要求,客户端的查询语句和记录集
    都可以缓存起来,供其他客户端使用,加上 SQL_NO_CACHE将不缓存
    值:2 -– 启用查询缓存,只要查询语句中添加了参数:SQL_CACHE,且符合查询
    缓存的要求,客户端的查询语句和记录集,则可以缓存起来,供其他客户端使用
    query_cache_size
    允许设置query_cache_size的值最小为40K,默认1M,推荐设置 为:64M/128M;
    query_cache_limit
    限制查询缓存区最大能缓存的查询记录集,默认设置为1M
  
    #缓存不会出现的情况  
       1.当查询语句中有一些不确定的数据时,则不会被缓存。如包含函数NOW(),
        CURRENT_DATE()等类似的函数,或者用户自定义的函数,存储函数,用户变量等都不会被缓存
        
       2.当查询的结果大于query_cache_limit设置的值时,结果不会被缓存


       3.对于InnoDB引擎来说,当一个语句在事务中修改了某个表,那么在这个事务
        提交之前,所有与这个表相关的查询都无法被缓存。因此长时间执行事务,
        会大大降低缓存命中率
       
       4.查询的表是系统表


       5.查询语句不涉及到表


   #为什么默认关闭缓存 
    为什么mysql默认关闭了缓存开启??


    1.在查询之前必须先检查是否命中缓存,浪费计算资源
    

    2.如果这个查询可以被缓存,那么执行完成后,MySQL发现查询缓存中没有这
        个查询,则会将结果存入查询缓存,这会带来额外的系统消耗
    
    3.针对表进行写入或更新数据时,将对应表的所有缓存都设置失效。
    
    4.如果查询缓存很大或者碎片很多时,这个操作可能带来很大的系统消耗

 #缓存使用的场景 ?
    以读为主的业务,数据生成之后就不常改变的业务 比如门户类、新闻类、报表类、论坛类等

explain操作命令 解读 ?

    执行计划select_id
    1、id相同,执行顺序由上至下
    2、id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
    3、id相同又不同即两种情况同时存在,id如果相同,可以认为是一组,从上往下顺序执行;在所有组中,id值越大,优先级越高,越先执行
    执行计划select_type
    4、SIMPLE:简单的select查询,查询中不包含子查询或者union
    5、SUBQUERY/MATERIALIZED:SUBQUERY表示在select 或 where列表中包含了子查询 MATERIALIZED表示where 后面in条件的子查询
    6、UNION:若第二个select出现在union之后,则被标记为union;
    7、UNION RESULT:从union表获取结果的select
    执行计划type
    访问类型,sql查询优化中一个很重要的指标,结果值从好到坏依次是:
    system > const > eq_ref > ref > range > index > ALL
    system:表只有一行记录(等于系统表),const类型的特例,基本不会出现,可以忽略不计
    const:表示通过索引一次就找到了,const用于比较primary key 或者 unique索引
    eq_ref:唯一索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键 或 唯一索引扫描
    ref:非唯一性索引扫描,返回匹配某个单独值的所有行,本质是也是一种索引访问
    range:只检索给定范围的行,使用一个索引来选择行
    index:Full Index Scan,索引全表扫描,把索引从头到尾扫一遍
    ALL:Full Table Scan,遍历全表以找到匹配的行
    执行计划--possible_keys 
    possible_keys 可能用到的索引 
    key  实际使用的索引 如果是null 则没有索引 
    rows 根据表统计信息或者索引选用情况,大致估算出找到所需的记录所需要读取的行数    
    filtered
    它指返回结果的行占需要读到的行(rows列的值)的百分比
    表示返回结果的行数占需读取行数的百分比,filtered的值越大越好 
    
    # 执行计划-Extra  
    1、Using filesort :
    mysql对数据使用一个外部的文件内容进行了排序,而不是按照表内的索引进行排序读取
    2、Using temporary:
    使用临时表保存中间结果,也就是说mysql在对查询结果排序时使用了临时表,常见于order by 或 group by
    3、Using index:
    表示相应的select操作中使用了覆盖索引(Covering Index),避免了访问表的数据行,效率高
    4、Using where :
    使用了where过滤条件
    5、select tables optimized away:
    基于索引优化MIN/MAX操作或者MyISAM存储引擎优化COUNT(*)操作,不必等到执行阶段在进行计算,查询执行
    计划生成的阶段即可完成优化


  #如何定位慢的sql?            
    1、业务驱动

    2、测试驱动

    3、慢查询日志 

   配置慢sql 命令 
    show variables like 'slow_query_log'
    set global slow_query_log = on
    set global slow_query_log_file = 'D:/develop/mysql-5.7.22-winx64/lib/mysql/hechuan-slow.log'
    set global log_queries_not_using_indexes = on
    set global long_query_time = 0.1 (秒)

    Time :日志记录的时间
    User@Host:执行的用户及主机
    Query_time:查询耗费时间 Lock_time 锁表时间 Rows_sent 发送给请求方的记录条数 Rows_examined 语句扫描的记录条数
    SET timestamp 语句执行的时间点
    select .... 执行的具体语句
    ![](https://img2020.cnblogs.com/blog/1359266/202003/1359266-20200323103621403-1488079534.png)

 
 #select 优化 
 1 SELECT WHERE 查询更快,前提判断字段是否添加了索引 (可以使用EXPLAIN语句来确定用于的索引 SELECT)
 2 调整MySQL用于缓存的内存区域的大小和属性。通过有效地使用 InnoDB 缓冲池,重复查询的运行速度更快,因为第二次及其后的结果是从内存中检索的。
    (SHOW VARIABLES LIKE '%query_cache%';set global query_cache_size = 1024 * 1024 * 32;set global query_cache_type= 1)
 #where 优化  
    ORDER BY或GROUP BY 包含了其他表的列 则产生一个临时表 
    select id from t where num is null  子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描  
    应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描
    应尽量避免在 where 子句中使用 or 来连接条件    
    in 和 not in 也要慎用,否则会导致全表扫描  like  
 很多时候用 exists 代替 in 是一个好的选择:select num from a where exists(select 1 from b where num=a.num)

mysqlInnoDB锁类型

行锁级别: 有共享锁Shared Locks和排他锁 Exclusive Locks
共享锁:都能访问到,只能读 不可以修改 。
#-- 共享锁加锁
SET AUTOCOMMIT=ON;
BEGIN;
select id,hc_name from hc_car_info WHERE id=1 LOCK IN SHARE MODE;(LOCK IN SHARE MODE 设置了共享锁)
#-- 排它锁(行锁)Exclusive Locks
只有该获取了排他锁的事务是可以对数据行进行读取和修改
delete / update / insert 默认加上X锁
SELECT * FROM table_name WHERE ... FOR UPDATE

innodb 行锁到底锁了什么?

innodb是用于锁定索引,只有通过索引条件进行数据检索InnoDB才使用行级锁。

posted on 2020-03-23 11:10  全国学渣代表  阅读(145)  评论(0编辑  收藏  举报