#mysql5.7 innodb默认存储引擎

一、关于索引
二、最佳实践
三、避坑实践

一、关于索引
   1.索引的作用
          -提高查询效率
          -数据分组、排序
          -避免回表查询
          -优化聚集查询
          -用于多表join关联查询
          -利用唯一性约束、保证数据唯一性
          -innodb行锁实现

    #索引的“作用”(副作用)
                -增加io成本
                -增加磁盘空间
                -不适合的索引,或索引过多,都不是好事

    

    #索引类型
          -BTREE (B+ tree或B-tree),INNODB &MYISAM
          -Fractal TREE,TokuDB
          -HASH(用于内存的存储引擎),HEAP,NDB,INNODB AHI
          -RTEE
          -FULLTEXT
    #针对b+tree索引

    #聚集索引

            -一种特殊的索引,其key值顺序决定了表数据行的物理顺序(相对)顺序
            -每张表只能建一个聚集索引,除了tokudb引擎
            -innodb中,聚集索引即表,表即聚集索引(innodb存储了整行的数据)
            -myisam没有聚集索引的概念

      #聚集索引优先选择列
                   -int、bigint
                   -数据连续(单调顺序)递增、自增

      #不建议的聚集索引类型
                  -频繁的修改列
                  -新增数据太过随机或离散
                  -uuid、字符串、随机数。不建议设置聚集索引

      #主键索引(具体的索引列)
                  -由一个列或多个列组成
                  -用于唯一表示表中的某一条记录&外键约束
                  -主键值不能重复,也不能包含null

      #主键选择建议:
                  -对业务透明,无意义,免受业务变化的影响
                  -几乎不修改和删除
                  -自增int、bigint最佳
      #innodb聚集索引选择次序原则
                  1.显示声明的主键
                  2.第一个not nullable的唯一索引
                  3.上述两者都没,则选择内置rowid作为聚集索引(实例级,6bytes
      #全局rowID
            rowid作为聚集索引缺点:
                        1)整个实例来分配的rowid
                        2)不是每个表单独分配的rowid
                        3)rowid是全局的rowid,每个表的rowid都是跳跃的

      #innodb主键特点:
                -索引定义时,不管有无显式包含主键,实际都会存储主键值;
                -在5.6.9以后,优化器异能自动识别索引末尾的主键值(index Extensions)
                -,在这之前则需要显式加上主键才可以被识别;

                -where c1=? and pk=?
                -where ci=? order by pk(主键列)

      #辅助索引
                -又称为非聚集索引,或者二级索引,俗称普通索引
                -当通过innodb辅助索引查找数据时,辅助索引会通过页级的指针找到主键索引的主键,
                -然后通过该主键索引找到相应的行数据

                ex:c1=>(c1.pk)=>pk=>row data

      #聚集索引
            ex:
              create table x(
              id int(10) unsigned not null auto_increment,
              uid int(10) unsiged not null default ‘0’, #uid为辅助索引
              user varchar(20) not null default ‘‘,
              passwd varchar(40) not null default ‘‘,
              primary key(id), #id为聚集索引
              unique key uid(uid),#唯一的辅助索引
              )ENGINE=Innodb
              --------------------------------------------

            以下视图是开了,innodb—monitor内部结构显示的信息
                   TABLE:....
            COLUMNS:...
                uid:...
               user:...
             DB_ROW_ID:...
          DB_ROLL_PTR:...
             INDEX:name PRIMARY,id 54,fields 1/6,uniq 1,tyep 3 #聚集索引选择主键为聚集索引,总共6个列,显示定义一个列
             root page 3,appr.key vals 0,leaf pages 1,size pages 1
             FILEDS:id DB_TRX_ID DB_ROLL_PTR uid user passwd #聚集索引后面跟着两个隐藏列分别为:DB_TRX_ID事物ID,DB_ROLL_PTR回滚指针,还有其他的功能列
             INDEX:name uid.id 55,fields 1/2,uniq 2,type 2 #辅助索引,总共2个类,定义了一个列。实际存储为两个列。辅助索引总是跟着主键的值,才能根据uid找到主键的值。
              root page 4,appr.key vals 0,leaf pages 1,size pages 1
             FIELDS:uid id

    #innodb索引图

                    [ ]
                  +---+---+ internal nodes
                  |    |   |
                 [     ] [    ]  [   ]

              -------------------------------------------

              [3 ]       [ ]        [99 ]        [ ]       [4700]
                                      --> [TID] --> [ ] --> [TID] --> [ ] --> [TID ] -->      inndb clustered
                                             [RP ]       [ ]       [RP ]        [ ]       [RP ]              indexleaf nodes
                                           【93 】   【 】   【8 】     【 】    【13 】

                                      [ ]Primary key columns (col1)
          [TID]Transaction ID
          [RP ]Rollback Pointer
          【 】Non-Pk columns(col2)

      #联合索引
            -多列组成,所以也叫多列索引
            -适合where条件中的多列组合
            -有时候,还可以用于避免回表(覆盖索引)
            -MySQL还不支持多列不同排序规则(MySQL8.0起支持)
            nnodb_table_monitor
            -联合索引建议:
                    -where条件中,经常同时出现的列放在联合索引中
                    -把选择性(过滤性、基数)大的列放在联合索引的最左边
                ex:
                  a=? and b=? and c=?
                  a>? and b=? and c=?
                  建议:(b,c,a)
      #部分索引
            - 部分索引的原因
                    -char/varchar太长全部做索引的话,效率太差,存在浪费
                    -或者blob/text类型不能整列作为索引列,因此需要使用前缀索引
            -部分说要选择建议
                    -统计平均值
                    -满足80%~90%覆盖度就够
            -缺点
                    -无法利用前缀索引完成排序
              ex:
                  username varchar(50)
                  统计平均长度
                  selelct avg(length(username)) from tt;
                  50*3=150
                  username(18) 18*3=54
                  *3-表示utf8以三个字节表示的
      #覆盖索引
            -通过索引数据结构,即可直接返回数据,不需要回表
            -执行计划中,Extra列会显示关键字using index


      #innodb索引特点
                - 索引最大长度767bytes
                -启用innodb_large_prefix,增加到3072bytes,只针对DYNAMIC、COMPRESSED格式管用
                ex:
                  show table status like ‘x1‘\G
                  --------------1.row---------------
                        Name:x1
                        Engine:innodb
                         Version:10
                     Row_format:Dynamic
                        Rows:14
                   Avg_row_length:1170


              -对于REDUNDANT、COMPACT格式,最大索引长度还是767bytes
              -MyISAM表索引最大长度是1000bytes
              -最大排序长度默认是1024(max_sort_length)

        #索引统计
              -show index from table
              -select * from information_sechma.statistics
              -mysql.innodb_index_stats

              -innodb_stats_auto_recalc
                -默认启用,当修改数据量>10%,自动更新统计信息
              -innodb_stats_persistent
                -统计信息持久化存储,默认启用
              -innodb_stats_persistent_sample_pages
                -统计信息持久化存储时,每次采集20个page
            ex:
              随机采集,不连续。五个索引,采集100page。每个表,每个分区,每个索引采集20个page

              -inoodb_stats_on_metadata
                -默认禁用,访问meta data时更新统计信息

              -innodb_stats_persistent=0
                -统计信息不持久化,每次动态采集,存储在内存中,重启实效(需要新统计),不推荐
              -innodb_stats_transient_sample_pages
                -动态采集page,默认8个
              -每个表设定统计模式
                -create/alter table ...stats_persistent=1,stats_auto_recalc=1,
                  stats_sample_pages=200;
                -参考:细说ANALZE TABLE

      #EXPLAIN之type
                -all
                  -全表扫描,最糟糕的情况
                -index
                  -全索引扫描,大部分情况下,一样糟糕

      #EXPLAIN之key_len
                -正常的等于索引列字节长度
                -字符串类型需要同时考虑字符集因素
                -若允许null,再+1
                -变长类型(varchar),在+2
                -key_len只计算利用索引完成数据过滤时索引长度
                -不包括用于GROUP BY/ORDER BY 的索引长度

              ex:
                -int 4 bigint 8
                -index:(int_col1,bigint_col2)
                -where int_col1=? order by bigint_col2 #key_len 长度为4,不是4+8=12。key_len不包括order by后面的长度
    #EXPLAIN之extra
              -Using filesort
                -没有办法利用现有索引进行排序,需要额外排序
                -建议:根据排序需要,创建相应合适的索引
              -Using index
                -利用覆盖索引,无需回表即可取得结果数据
              -Using temporary
            -需要用临时表存储结果集,通常是因为group by的列上没有索引。也有可能是因为同时有group by和order by,但group by和order by的列又不一样

      #查看索引利用率
              -查看每个索引使用情况
              #select index_name,rows_selected,rows_updated,
              rows_deleted from schema_index_statistics where
              table_schema=’world’ and table_name=’city’;
              +---------------+----------------+----------------+--------------+
              |index_name     | rows_selected| rows_updated | rows_deleted |
              | PRIMARY     |            33131 |                      0 |                     0 |
              | CountryCode |                103 |        0 |        0 |
               |+---------------|----------------+-----------------+--------------+

              #mysql 5.7 默认启用p_s

      #查看冗余索引

            #select * from schema_redundant_indexes where
            table_schema=’test’ and table_name=’tutf8’\G
            *******************1.row***********************
                table_schema:test
                 table_name:t1
           redundant_index_name:c2_2
            redundant_index_columns:c2
        redundant_index_non_unique:1
            dominant_index_name:c2
            doinant_index_columns:c2
          dominant_index_non_unique:1
                 subpart_exists:1
                  sql_drop_index:ALTER TABLE ‘test’.’t1’ DROP INDEX ‘c2_2’


                ex:
                  index1:c1
                  index2:c1,c2
                  index1是index2的冗余索引
                    #冗余索引不一定可以删除,特殊场景视情况分析

              -index k1(a,b,c)
              -index k2(a,b)
              -一般认为,k2是k1的冗余索引
              -但下面的sql则只有k2才管用
                  - where a=? and b=? and pk=?;
                  -where a=? and b=? order by pk;

      #查看无用索引
              #select * from schema_unused_indexes
                where object_schema=’test’ and object_name=’t1’;
                  +------------------+------------------+-------------+
                  | object_schema   | objdect_name | index_name |
                  +------------------+------------------+--------------+
                  | test        |        t1 |      k1 |
                  +------------------+-------------------+-------------+

      #索引为何不可用
              -通过索引扫描的记录数超过20%~30%,可能会变成全表扫描
              -联合索引中,第一个查询条件不是最左索引列
              -模糊查询条件列最左以通配符%开始
              -HEAP表使用HASH索引时,使用范围检索或者ORDER BY
              -多表关联时,排序字段不属于驱动表,无法利用索引完成排序
              -JOIN查询时,关联列数据类型(字符集)不一定也会导致索引不可用

      #类型隐式转换
              #desc select * from t1 where u2=123\G
              *****************1.row***************
                      id:1
                  select_type:SIMPLE
                      table:t1
                    partitions:NULL
                      type:ALL
                  possible_keys:u2
                        key:NULL
                      key_len:NULL
                        ref:NULL
                      rows:102176
                     filtered:10.00
                      Extra:Using where
              #us=123 出现隐式转换无法利用到索引,视为ASCII
              us=’123’ 可以利用索引,支持字符串

      #MYSQL 5.6/5.7
      #desc select * from t1 where gmt_create between date_add(now(),interval - 1 minute)
        and date_add(now(),interval 15 minute)\G
        **************1.row**********************
                    id:1
              select_type:SIMPLE
                        table:t1
                      type:ALL
          possible_keys:ind_gmt_create
                           key:NULL
                        rows:2849555
                        Extra:Using where

      |Warning | 1739 | Cannot use range access on index ‘index_gmt_create’
        due to type or collation conversion on field ‘gmt_create’

        #gmt_create 日期时间会出现隐式转换,在底层被修改为int类型

二、索引最佳实践
        -mysqld进程cpu占用长期较高时,99.99%时因为索引不当导致
        #top 执行时:
              %CPU 362.3 121.7
              COMMAND mysqld
              这种现象基本都是用不到索引,高频度列用不到索引


-mysql内用户线程状态经常看到Sending data,也基本上是因为索引不当导致
#mysqladmin pr|grep -v Sleep
+----+-------+--------------+--------+-----------+-------+-------------+------------+
| id | user | host | db | command | time | state | info |
+-----+-------+--------------|+-----+|---------+-------+-------------+--------------|
| 25 | x | 10.x.8519 | db | Query | 68 |Sending data | select ...|
| 26 | x | 10.x.8520 | db | Query | 65 |Sending data | select ...|
| 28 | x | 10.x.8522 | db | Query | 130 |Sending data | select ...|
| 27 | x | 10.x.8521 | db | Query | 167 |Sending data | select ...|
| 36 | x | 10.x.8727 | db | Query | 174 |Sending data | select ...|
+|-----+------+---------------|------|-----------|------|---+-------+---|----------+-|

三、避坑实践
-所有主要列都创建单独索引
-长varchar列创建索引
-基数低的列单独创建索引,或者放在联合索引的最左边
-mysql不支持位图索引

#相关参数优化
-sort-buffer-size/join-buffer-size/read-rnd-buffer-size,4~8MB为宜
-optimizer_swich=”index_condition_pushdown=on,mrr=on,mrr_cost_based=off,batched_key_access=on”
-tmp-table-size=max-heap-table-size,100MB左右为宜
-log-queries-not-using-indexes& log_throttle_queries_not_using_indexes



#MySQL8.0+新变化
-倒叙索引 #(a asc,b desc)
-不可见索引 #不常用索引

#附资料
-由浅入深理解innodb的索引实现
-mysql索引值聚集索引
-B+ 树索引和哈希索引的区别
-10分钟让你明白mysql是如何利用索引的
-老斯基带你解锁mysql8.0索引新姿势
-mysql排序内部原理探秘
-index extensions特性介绍
-细说ANALZE TABLE
-解读EXPLAIN执行计划中的key_len
-innblock|innodb page 观察利器
-听说join的列类型一定要一样
-UPDATE能走索引还会锁全表吗
-索引、提交频率对innodb表写入速度的影响
-为什么innodb表要建议自增列做主键
-典型性索引引发CPU负载飙升问题
-UPDATE时主键冲突引发的思考
-单节点可用方案http://github.com/zhishutech/

Mysql索引最佳实践笔记0524的更多相关文章

  1. mysql索引最佳实践

    索引最佳实践使用的表CREATE TABLE `employees` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `name` varchar(24) NOT ...

  2. [译] MYSQL索引最佳实践

    近日整理文档时发现多年前的这个文档还是蛮实用的,然后在网络搜索了一下并没有相关的译文,所以决定把它翻译过来,如有不当的地方请多包涵和指正.原文地址:https://www.percona.com/fi ...

  3. MySQL 索引最佳实践

    原文请关注 这里 这是 文章 的翻译,在翻译过程中,会对其中涉及到的语句加上一些个人理解以及 SQL 语句的执行,并进行特别的标注. 1. 你做了一个很棒的选择,因为: 对于普通开发者和 DBA,理解 ...

  4. 【大数据和云计算技术社区】分库分表技术演进&最佳实践笔记

    1.需求背景 移动互联网时代,海量的用户每天产生海量的数量,这些海量数据远不是一张表能Hold住的.比如 用户表:支付宝8亿,微信10亿.CITIC对公140万,对私8700万. 订单表:美团每天几千 ...

  5. MySQL索引知识学习笔记

    目录 一.索引的概念 二.索引分类 三.索引用法 四 .索引架构简介 五.索引适用的情况 六.索引不适用的情况 继我的上篇博客:Oracle索引知识学习笔记,再记录一篇MySQL的索引知识学习笔记,本 ...

  6. web前端开发最佳实践笔记

    一.文章开篇 由于最近也比较忙,一方面是忙着公司的事情,另外一方面也是忙着看书和学习,所以没有时间来和大家一起分享知识,现在好了,终于回归博客园的大家庭了,今天我打算来分享一下关于<web前端开 ...

  7. mysql 查询最佳实践

    (1)负向条件查询不能使用索引 select * from order where status!=0 and stauts!=1 not in/not exists都不是好习惯 (2)前导模糊查询不 ...

  8. 【译】索引进阶(十七): SQL SERVER索引最佳实践

    [译注:此文为翻译,由于本人水平所限,疏漏在所难免,欢迎探讨指正] 原文链接:传送门. 在本章我们给出一些建议:贯穿本系列我们提取出了十四条基本指南,这些基本的指南将会帮助你为你的数据库创建最佳的索引 ...

  9. PHP核心技术与最佳实践--笔记

    <?php error_reporting(E_ALL); /* php 5.3引入 延迟静态绑定 */ /* php5.4引入trait,用来实现多层继承 trait Hello{} trai ...

随机推荐

  1. [NOI 2021] 轻重边 题解

    提供一种和不太一样的树剖解法(一下考场就会做了qwq),尽量详细讲解. 思路 设重边为黑色,轻边为白色. 首先,先将边的染色转化为点的染色(即将 \(u\) 节点连向父节点的边的颜色转化为 \(u\) ...

  2. Django中F对象,Q对象与运算符

    在Django的模型中F对象与Q对象比较常用的,所以单独说一下: F对象 F对象位于django.dc.models模板下,使用的时候记得首先导入!!! 作用:F对象主要用于当模型的字段A与字段B进行 ...

  3. 看视频学SignalR—在微软虚拟学院学习SignalR

    SignalR把实时Web功能变得异常简单. 如果您希望在几个小时内对SignalR有一个直观的了解,观看微软虚拟学院(MVA)的视频教学Lighting Up Real-Time Web Commu ...

  4. joomla 3.7.0 (CVE-2017-8917) SQL注入漏洞

    影响版本: 3.7.0 poc http://192.168.49.2:8080/index.php?option=com_fields&view=fields&layout=moda ...

  5. 🔥 LeetCode 热题 HOT 100(41-50)

    102. 二叉树的层序遍历 思路:使用队列. /** * Definition for a binary tree node. * public class TreeNode { * int val; ...

  6. 🏆(不要错过!)【CI/CD技术专题】「Jenkins实战系列」(3)Jenkinsfile+DockerFile实现自动部署

    每日一句 没有人会因学问而成为智者.学问或许能由勤奋得来,而机智与智慧却有懒于天赋. 前提概要 Jenkins下用DockerFile自动部署Java项目,项目的部署放心推向容器化时代机制. 本节需要 ...

  7. HotSpot 对象

    概述 当Java虚拟机遇到一条字节码new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用, 并且检查这个符号引用代表的类是否已被加载.解析和初始化过.如果没有,那必须先执行相 ...

  8. Android面试大揭秘!从技术面被“虐”到征服CTO,全凭这份强到离谱的pdf

    在笔者面试这一个月,看了不少文章,也刷了不少面试题,但真正有深度,适合4年及以上Android高工的内容少之又少 在面试准备阶段,笔者准备了三个月左右的时间,结合相关资料及源码,完成了一系列的深度学习 ...

  9. 解决Win10用户VS Code的C/C++更新到1.6.0后无法调试的问题

    今天突然遇到一个问题 Win10上 vscode C++突然无法正常调试 在运行调试后 编译成功后没有任何提示 直接就停止了 没有错误 不运行程序 尝试重新写一遍launch.json 自动生成lau ...

  10. 定制bash命令提示符

    使用shell时经常要知道当前路径,如果将它写在提示符里很节省很多敲pwd的动作,方法是在启动文件(.bash_profile, .bashrc)里加上: export PS1="[\u@\ ...