MySQL索引管理

总结

  1. #索引是存在硬盘中的,
  2. #索引的功能,
  3. 1.可以加速查询
  4. 2.但是他会降低写入和删除的速度
  5. 所以不能乱加索引

总结二

  1. 1 最左前缀匹配原则
  2. 2设置的索引,它的字段中的内容占空间尽可能要小
  3. 3设置的所以要区分度尽量高,区分度越高,查找速度越快
  4.  
  5. 能够帮助加速查找的方式是加上适合的索引:
  6. (区分度高, 能够缩小范围的字段)

组合索引总结

  1. 1.写索引时一定要把区分度最高的放在最左位置
  2. 2.sql 语句查找数据时,一定要把区分度最高的(即索引最左边的内容)放到最左边

一 功能

  1. #1. 索引的功能就是加速查找
  2. #2. mysql中的primary key,unique,联合唯一也都是索引,这些索引除了加速查找以外,还有约束的功能

二 MySQL常用的索引

  1. 普通索引INDEX:加速查找
  2.  
  3. 唯一索引:
  4. -主键索引PRIMARY KEY:加速查找+约束(不为空、不能重复)
  5. -唯一索引UNIQUE:加速查找+约束(不能重复)
  6.  
  7. 联合索引:
  8. -PRIMARY KEY(id,name):联合主键索引
  9. -UNIQUE(id,name):联合唯一索引
  10. -INDEX(id,name):联合普通索引
  1. 举个例子来说,比如你在为某商场做一个会员卡的系统。
  2.  
  3. 这个系统有一个会员表
  4. 有下列字段:
  5. 会员编号 INT
  6. 会员姓名 VARCHAR(10)
  7. 会员身份证号码 VARCHAR(18)
  8. 会员电话 VARCHAR(10)
  9. 会员住址 VARCHAR(50)
  10. 会员备注信息 TEXT
  11.  
  12. 那么这个 会员编号,作为主键,使用 PRIMARY
  13. 会员姓名 如果要建索引的话,那么就是普通的 INDEX
  14. 会员身份证号码 如果要建索引的话,那么可以选择 UNIQUE (唯一的,不允许重复)
  15.  
  16. #除此之外还有全文索引,即FULLTEXT
  17. 会员备注信息 如果需要建索引的话,可以选择全文搜索。
  18. 用于搜索很长一篇文章的时候,效果最好。
  19. 用在比较短的文本,如果就一两行字的,普通的 INDEX 也可以。
  20. 但其实对于全文搜索,我们并不会使用MySQL自带的该索引,而是会选择第三方软件如Sphinx,专门来做全文搜索。
  21.  
  22. #其他的如空间索引SPATIAL,了解即可,几乎不用

各种索引的应用场景

三 索引的两大类型hash与btree

  1. #我们可以在创建上述索引的时候,为其指定索引类型,分两类
  2. hash类型的索引:查询单条快,范围查询慢
  3. btree类型的索引:b+树,层数越多,数据量指数级增长(我们就用它,因为innodb默认支持它)
  4.  
  5. #不同的存储引擎支持的索引类型也不一样
  6. InnoDB 支持事务,支持行级别锁定,支持 B-treeFull-text 等索引,不支持 Hash 索引;
  7. MyISAM 不支持事务,支持表级别锁定,支持 B-treeFull-text 等索引,不支持 Hash 索引;
  8. Memory 不支持事务,支持表级别锁定,支持 B-treeHash 等索引,不支持 Full-text 索引;
  9. NDB 支持事务,支持行级别锁定,支持 Hash 索引,不支持 B-treeFull-text 等索引;
  10. Archive 不支持事务,支持表级别锁定,不支持 B-treeHashFull-text 等索引;

四 创建/删除索引的语法

  1. #方法一:创建表时
  2.   CREATE TABLE 表名 (
  3. 字段名1 数据类型 [完整性约束条件…],
  4. 字段名2 数据类型 [完整性约束条件…],
  5. [UNIQUE | FULLTEXT | SPATIAL ] INDEX | KEY
  6. [索引名] (字段名[(长度)] [ASC |DESC])
  7. );
  8.  
  9. #方法二:CREATE在已存在的表上创建索引
  10. CREATE [UNIQUE | FULLTEXT | SPATIAL ] INDEX 索引名
  11. ON 表名 (字段名[(长度)] [ASC |DESC]) ;
  12.  
  13. #方法三:ALTER TABLE在已存在的表上创建索引
  14. ALTER TABLE 表名 ADD [UNIQUE | FULLTEXT | SPATIAL ] INDEX
  15. 索引名 (字段名[(长度)] [ASC |DESC]) ;
  16.  
  17. #删除索引:DROP INDEX 索引名 ON 表名字;
  1. #方式一
  2. create table t1(
  3. id int,
  4. name char,
  5. age int,
  6. sex enum('male','female'),
  7. unique key uni_id(id),
  8. index ix_name(name) #index没有key
  9. );
  10.  
  11. #方式二
  12. create index ix_age on t1(age);
  13.  
  14. #方式三
  15. alter table t1 add index ix_sex(sex);
  16.  
  17. #查看
  18. mysql> show create table t1;
  19. | t1 | CREATE TABLE `t1` (
  20. `id` int(11) DEFAULT NULL,
  21. `name` char(1) DEFAULT NULL,
  22. `age` int(11) DEFAULT NULL,
  23. `sex` enum('male','female') DEFAULT NULL,
  24. UNIQUE KEY `uni_id` (`id`),
  25. KEY `ix_name` (`name`),
  26. KEY `ix_age` (`age`),
  27. KEY `ix_sex` (`sex`)
  28. ) ENGINE=InnoDB DEFAULT CHARSET=latin1

示范

三 在表中已经存在大量数据的前提下,为某个字段段建立索引,建立速度会很慢

四 在索引建立完毕后,以该字段为查询条件时,查询速度提升明显

PS:

1. mysql先去索引表里根据b+树的搜索原理很快搜索到id等于333333333的记录不存在,IO大大降低,因而速度明显提升

2. 我们可以去mysql的data目录下找到该表,可以看到占用的硬盘空间多了

3. 需要注意,如下图

五 总结

  1. #1. 一定是为搜索条件的字段创建索引,比如select * from s1 where id = 333;就需要为id加上索引
  2.  
  3. #2. 在表中已经有大量数据的情况下,建索引会很慢,且占用硬盘空间,建完后查询速度加快
  4. 比如create index idx on s1(id);会扫描表中所有的数据,然后以id为数据项,创建索引结构,存放于硬盘的表中。
  5. 建完以后,再查询就会很快了。
  6.  
  7. #3. 需要注意的是:innodb表的索引会存放于s1.ibd文件中,而myisam表的索引则会有单独的索引文件table1.MYI
  8.  
  9. MySAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在innodb中,表数据文件本身就是按照B+TreeBTreeBalance True)组织的一个索引结构,
    这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此innodb表数据文件本身就是主索引。
  10. 因为inndob的数据文件要按照主键聚集,所以innodb要求表必须要有主键(Myisam可以没有),如果没有显式定义,则mysql系统会自动选择一个可以唯一标识数据记录的列作为主键,
    如果不存在这种列,则mysql会自动为innodb表生成一个隐含字段作为主键,这字段的长度为6个字节,类型为长整型.

七 正确使用索引

一 索引未命中

并不是说我们创建了索引就一定会加快查询速度,若想利用索引达到预想的提高查询速度的效果,我们在添加索引时,必须遵循以下问题

1 范围问题,或者说条件不明确,条件中出现这些符号或关键字:>、>=、<、<=、!= 、between...and...、like、

大于号、小于号

不等于!=

between ...and...

like

2 尽量选择区分度高的列作为索引,区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0,那可能有人会问,这个比例有什么经验值吗?使用场景不同,这个值也很难确定,一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录

 分析原因

3 =和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式

4 索引列不能参与计算,保持列“干净”,比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成create_time = unix_timestamp(’2014-05-29’)

5 and/or

  1. #1、and与or的逻辑
  2. 条件1 and 条件2:所有条件都成立才算成立,但凡要有一个条件不成立则最终结果不成立
  3. 条件1 or 条件2:只要有一个条件成立则最终结果就成立
  4.  
  5. #2、and的工作原理
  6. 条件:
  7. a = 10 and b = 'xxx' and c > 3 and d =4
  8. 索引:
  9. 制作联合索引(d,a,b,c)
  10. 工作原理:
  11. 对于连续多个andmysql会按照联合索引,从左到右的顺序找一个区分度高的索引字段(这样便可以快速锁定很小的范围),加速查询,即按照d—>a->b->c的顺序
  12.  
  13. #3、or的工作原理
  14. 条件:
  15. a = 10 or b = 'xxx' or c > 3 or d =4
  16. 索引:
  17. 制作联合索引(d,a,b,c)
  18.  
  19. 工作原理:
  20. 对于连续多个ormysql会按照条件的顺序,从左到右依次判断,即a->b->c->d

在左边条件成立但是索引字段的区分度低的情况下(name与gender均属于这种情况),会依次往右找到一个区分度高的索引字段,加速查询

经过分析,在条件为name='egon' and gender='male' and id>333 and email='xxx'的情况下,我们完全没必要为前三个条件的字段加索引,因为只能用上email字段的索引,前三个字段的索引反而会降低我们的查询效率

6 最左前缀匹配原则(详见第八小节),非常重要的原则,对于组合索引mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配(指的是范围大了,有索引速度也慢),比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。

二 其他注意事项

  1. - 避免使用select *
  2. - count(1)或count(列) 代替 count(*)
  3. - 创建表时尽量时 char 代替 varchar
  4. - 表的字段顺序固定长度的字段优先
  5. - 组合索引代替多个单列索引(经常使用多个条件查询时)
  6. - 尽量使用短索引
  7. - 使用连接(JOIN)来代替子查询(Sub-Queries)
  8. - 连表时注意条件类型需一致
  9. - 索引散列值(重复少)不适合建索引,例:性别不适合

八 联合索引与覆盖索引

一 联合索引

联合索引时指对表上的多个列合起来做一个索引。联合索引的创建方法与单个索引的创建方法一样,不同之处在仅在于有多个索引列,如下

  1. mysql> create table t(
  2. -> a int,
  3. -> b int,
  4. -> primary key(a),
  5. -> key idx_a_b(a,b)
  6. -> );
  7. Query OK, 0 rows affected (0.11 sec)

那么何时需要使用联合索引呢?在讨论这个问题之前,先来看一下联合索引内部的结果。从本质上来说,联合索引就是一棵B+树,不同的是联合索引的键值得数量不是1,而是>=2。接着来讨论两个整型列组成的联合索引,假定两个键值得名称分别为a、b如图

可以看到这与我们之前看到的单个键的B+树并没有什么不同,键值都是排序的,通过叶子结点可以逻辑上顺序地读出所有数据,就上面的例子来说,即(1,1),(1,2),(2,1),(2,4),(3,1),(3,2),数据按(a,b)的顺序进行了存放。

因此,对于查询select * from table where a=xxx and b=xxx, 显然是可以使用(a,b) 这个联合索引的,对于单个列a的查询select * from table where a=xxx,也是可以使用(a,b)这个索引的。

但对于b列的查询select * from table where b=xxx,则不可以使用(a,b) 索引,其实你不难发现原因,叶子节点上b的值为1、2、1、4、1、2显然不是排序的,因此对于b列的查询使用不到(a,b) 索引

联合索引的第二个好处是在第一个键相同的情况下,已经对第二个键进行了排序处理,例如在很多情况下应用程序都需要查询某个用户的购物情况,并按照时间进行排序,最后取出最近三次的购买记录,这时使用联合索引可以帮我们避免多一次的排序操作,因为索引本身在叶子节点已经排序了,如下

博客引子老男孩最帅的老师egon 原创博客 http://www.cnblogs.com/linhaifeng/articles/7274563.html  如有合作意向请联系老男孩教育

day44 数据库学习 索引 引用自egon 老师博客的更多相关文章

  1. day43 数据库学习 转自egon 老师博客 单表查询和多表查询

    一 单表查询的语法 SELECT 字段1,字段2... FROM 表名 WHERE 条件 GROUP BY field HAVING 筛选 ORDER BY field LIMIT 限制条数 二 关键 ...

  2. python老师博客

    前端基础之HTML http://www.cnblogs.com/yuanchenqi/articles/6835654.html 前端基础之CSS http://www.cnblogs.com/yu ...

  3. ibatis 学习笔记 3 - pfpfpfpfpf的专栏 - 博客频道 - CSDN.NET

    body { font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI ...

  4. Spring Boot学习记录(二)--thymeleaf模板 - CSDN博客

    ==他的博客应该不错,没有细看 Spring Boot学习记录(二)--thymeleaf模板 - CSDN博客 http://blog.csdn.net/u012706811/article/det ...

  5. 201771030103-陈正丽 实验一 软件工程准备—<快速浏览 邹欣老师博客—读后感>

    项目 内容 <软件工程> 代祖华老师博客 作业要求 邹欣老师博客 学习目标 具体目标 在大概阅读邹欣老师的博客时,发现老师写了关于很多方面的内容,有基础的也有比较深奥的,这次阅读过程中主要 ...

  6. myssql数据库表名转驼峰 - PLAY - ITeye博客

    原文:myssql数据库表名转驼峰 - PLAY - ITeye博客

  7. 想学习找不到好的博客?看这里>>

    想学习找不到好的博客?看这里>> (ps:内容 + 作者) 基础数论知识整理--gyh 进阶数论知识整理--又是gyh 关于SPFA--lyj(终于不是gyh) 证明二次探测定理-Line ...

  8. OpenGL ES 学习笔记 - Overview - 小旋的博客

    移动端图形标准中,目前 OpenGL ES 仍然是比较通用的标准(Vulkan 则是新一代),这里新开一个系列用于记录学习 OpenGL ES 的历程,以便查阅理解. OverView OpenGL ...

  9. android学习系列:jercy——AI3 的博客

    [android学习之十七]——特色功能2:桌面组件(快捷方式,实时文件夹) 二.桌面组件 1.快捷方式 Android手机上得快捷方式的意思可以以我们实际PC机器上程序的快捷方式来理解.而andro ...

随机推荐

  1. Mysql数据库操作语句总结

    简单复习下: 增insert into -- 删 delete from  -- 改 update table名字 set -- 查 select * from  -- 一.SQL定义 SQL(Str ...

  2. idea自动生成serialVersionUID(转)

    原文链接:http://blog.sina.com.cn/s/blog_54b09dc90101d9bu.html Setting->Plugins 找到一个叫  GenerateSerialV ...

  3. vue-router + ElementUI实现NavMenu 导航菜单 选中状态的切换

    elemen-ui官方网站:http://element.eleme.io/#/zh-CN/component/menu 新手小白利用vue+element-ui尝试搭建后台管理系统, 效果是这样的, ...

  4. pl/sql developer中dbms_output.put_line函数的运用

    pl/sql developer中dbms_output.put_line函数可以打印想显示在屏幕上的信息,运用时需要注意几点: 1 必须处于begin   ...  end: 2 需要先执行 set ...

  5. day 53 练习

    1  <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8&qu ...

  6. ubuntu Cairo图形库 环境搭建

    Cairo官网:http://cairographics.org/ 根据官网指示,我使用如下语句安装好cairo库 sudo apt-get install libcairo2-dev 从官网拷贝代码 ...

  7. ob 函数的使用

    ob 函数的使用1. 页面静态化 $id = isset($_GET['id'])?$_GET['id']-0:0; $filename = "html/".date(" ...

  8. 配置JAVA 环境变量

    首先 下载好JDK后 打开环境变量配置 配置JAVA_HOME: C:\Program Files\Java\jdk1.8.0_144(也就是jdk下载后的文件夹)   之后配置PATH:这时用到%J ...

  9. 支付宝异步通知(notify_url)与return_url.

    支付宝接口使用文档说明 支付宝异步通知(notify_url)与return_url. 现支付宝的通知有两类. A服务器通知,对应的参数为notify_url,支付宝通知使用POST方式 B页面跳转通 ...

  10. 2017-2018-2 20165228 实验二《Java面向对象程序设计》实验报告

    2017-2018-2 20165228 实验二<Java面向对象程序设计>实验报告 相关知识点 三种代码 伪代码:注释,与具体编程语言无关 产品代码:由伪代码翻译而来的具体编程语言语法相 ...