zoukankan      html  css  js  c++  java
  • mysql 优化

    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才使用行级锁。

  • 相关阅读:
    mysql用户
    mysql字符集
    tidb之一致性算法raft学习
    更新港资股票数据
    php中的时区设置
    PHP 中的注释
    python下如何处理windows的路径名
    安装第三方模块
    偏函数
    装饰器没学明白,记录一下,以后再学
  • 原文地址:https://www.cnblogs.com/chianw877466657/p/12548009.html
Copyright © 2011-2022 走看看