"

目录

普通索引

唯一索引

主键索引

组合索引

正确使用索引的情况

索引的注意事项

执行计划 axplain

慢日志记录

分页性能相关方案


索引是数据库中专门用于帮助用户快速查找数据的一种数据结构.

类似于字典中的目录,查找字典内容可以根据目录查找到数据的存放位置,然后直接获取.

作用:约束和加速查找

常见的几种索引:

- 普通索引

- 唯一索引

- 主键索引

- 联合索引(多列)

        -- 联合主键索引

       -- 联合唯一索引

       -- 联合普通索引

无索引和有索引的区别:

无索引:从前往后一条一条查询.
有索引:创建索引的本质,就是创建额外的文件,以某种格式存储,查询的时候,先去额外的文件找,确定了位置,然后再去原始表中直接查询,但是创建的索引越多,越会对硬盘有损耗.

———————————

建立索引的目的:

  1. 额外的文件保存特殊的数据结构
  2. 查询快,但是插入更新删除依旧慢
  3. 创建索引之后,必须命中索引才能有效

索引的种类:

hash索引:查询单条快,范围查询慢

btre类索引:b+树,层数增多,数据量指数级增长(InnoDB默认支持btree索引,这里就使用它)

索引名词:

覆盖索引:在索引文件中直接获取数据
(例如:select name from userinfo where name = 'zyk';)

索引合并:把多个单列索引合并使用
(例如:select name from userinfo where name = 'zyk' and sex = 'boy';)



  1. # 查看索引
  2. show index from 表名;
  3. # Key_name字段为定义的索引名
  4. # Column_name字段显示的是创建了索引的字段
  5. # 注意:一个表中默认会有一个主键,主键默认为主键索引.

普通索引

作用:加速查找


  1. # 创建表 + 普通索引
  2. create table userinfo(
  3. nid int not null auto_increment primary key,
  4. name varchar(20) not null,
  5. index ix_name(name) # 定义索引
  6. );
  7. # 添加普通索引
  8. create index 索引名 on 表名(列名);
  9. # 删除索引
  10. drop index 索引名 on 表名;

唯一索引

作用:加速查找和唯一约束(包含null)


  1. # 创建表 + 唯一索引
  2. create table userinfo(
  3. nid int not null auto_increment primary key,
  4. name varchar(20) not null,
  5. unique index ix_name(name) # 添加索引
  6. );
  7. # 添加唯一索引
  8. create unique index 索引名 on 表名(列名);
  9. # 删除索引
  10. drop index 索引名 on 表名;

主键索引

作用:加速查找和唯一约束(不包含null)


  1. # 添加表 + 主键索引
  2. # 方法1:
  3. create table userinfo(
  4. nid int not null auto_increment primary key, # 添加主键索引
  5. name varchar(32) not null
  6. );
  7. # 方法2:
  8. create table userinfo(
  9. nid int not null auto_increment,
  10. name varchar(32) not null,
  11. primary key(nid) # 添加主键索引
  12. );
  13. # 添加主键索引
  14. alter table 表名 add primary key(列名);
  15. # 删除主键索引
  16. alter table 表名 modify 列名 int, drop primary key;

组合索引

组合索引是将n个列组合成一个索引

应用场景:频繁的同时使用n列来进行查询(如:where name = 'zyk' and sex = 'boy')


  1. # 添加联合普通索引
  2. create index 索引名 on 表名(列名1, 列名2);

正确使用索引的情况

数据库中添加索引后确实会让查询速度起飞,但前提必须是正确的使用索引来查询,如果以错误的方式使用,则即使建立索引也不会奏效.

使用索引,我们必须知道:
(1) 创建索引

(2) 命中索引

(3) 正确使用索引

——————————————

准备100万条数据:


  1. #1. 准备表
  2. create table userinfo(
  3. id int,
  4. name varchar(20),
  5. gender char(6),
  6. email varchar(50)
  7. );
  8. # 创建存储过程,实现批量插入记录
  9. delimiter $$ # 声明存储过程的结束符号为$$
  10. create procedure auto_insert1() # 定义存储过程名为:auto_insert1()
  11. begin
  12. declare i int default 1; # 定义i为1
  13. while (i<1000000) do
  14. insert into userinfo
  15. values(i, concat('zyk', i), 'male', concat('zyk', i, '@oldboy'));
  16. set i = i + 1;
  17. end while;
  18. end $$
  19. delimiter ; 重新声明分号为结束符号
  20. # 查看存储过程
  21. show create procedure auto_insert\G
  22. # 调用存储过程
  23. call auto_insert1();

测试:


  1. - like '%xx'
  2. select * from userinfo where name like '%al';
  3. - 使用函数
  4. select * from userinfo where reverse(name) = 'alex333';
  5. - or
  6. select * from userinfo where id = 1 or email = 'alex122@oldbody';
  7. 特别的:当or条件中有未建立索引的列才失效,以下会走索引
  8. select * from userinfo where id = 1 or name = 'alex1222';
  9. select * from userinfo where id = 1 or email = 'alex122@oldbody' and name = 'alex112'
  10. - 类型不一致
  11. 如果列是字符串类型,传入条件是必须用引号引起来,不然...
  12. select * from userinfo where name = 999;
  13. - !=
  14. select count(*) from userinfo where name != 'alex'
  15. 特别的:如果是主键,则还是会走索引
  16. select count(*) from userinfo where id != 123
  17. - >
  18. select * from userinfo where name > 'alex'
  19. 特别的:如果是主键或索引是整数类型,则还是会走索引
  20. select * from userinfo where id > 123
  21. select * from userinfo where num > 123
  22. - order by
  23. select email from userinfo order by name desc;
  24. 当根据索引排序时候,选择的映射如果不是索引,则不走索引
  25. 特别的:如果对主键排序,则还是走索引:
  26. select * from userinfo order by nid desc;
  27. - 组合索引最左前缀
  28. 如果组合索引为:(name,email)
  29. name and email -- 使用索引
  30. name -- 使用索引
  31. email -- 不使用索引

什么是最左前缀:


  1. # 建立组合索引
  2. create index ix_name_email on user info(name, email);
  3. # where name:使用索引
  4. mysql> select * from userinfo where name like 'zyk123456%'; +--------+-----------+--------+------------------+
  5. | id | name | gender | email |
  6. +--------+-----------+--------+------------------+
  7. | 123456 | zyk123456 | male | zyk123456@oldboy |
  8. +--------+-----------+--------+------------------+
  9. 1 row in set (0.00 sec) # 0.00
  10. # where name and email:使用索引
  11. mysql> select * from userinfo where name like 'zyk123456%' and email like 'zyk123456%';
  12. +--------+-----------+--------+------------------+
  13. | id | name | gender | email |
  14. +--------+-----------+--------+------------------+
  15. | 123456 | zyk123456 | male | zyk123456@oldboy |
  16. +--------+-----------+--------+------------------+
  17. 1 row in set (0.00 sec) # 0.00
  18. # where email:不使用索引
  19. mysql> select * from userinfo where email like 'zyk123456%'; +--------+-----------+--------+------------------+
  20. | id | name | gender | email |
  21. +--------+-----------+--------+------------------+
  22. | 123456 | zyk123456 | male | zyk123456@oldboy |
  23. +--------+-----------+--------+------------------+
  24. 1 row in set (0.60 sec) # 注意:0.60

如果使用组合索引如上,name和email组合索引之后,查询:
(1)name and email        # 使用索引
(2)name        # 使用索引
(3)email        # 不使用索引

对于同时搜索n个条件,组合索引的性能好于多个单列索引.


索引的注意事项

  1. 不要使用select *        # 对性能的损耗太大
  2. 应使用 count(1) 或 count(列名) 代替 count(*)  后在查资料发现这些现在都没有区别了
  3. 创建表时尽量使用char代替varchar        # 查询速度
  4. 表的字段顺序:固定长度的字段优先
  5. 经常使用多个条件查询时,应建立组合索引代替多个单列索引
  6. 尽量使用短索引(create index ix_title on tb(title(16)); 特殊的数据类型,如text类型)
  7. 使用链接 join 来代替子查询
  8. 连表时注意条件类型需一致
  9. 索引散列(重复少)不适用于建索引,例如:性别不适合建索引

执行计划 axplain

explain + 查询SQL:用于显示SQL执行信息参数,根据参考信息可以进行SQL优化.


  1. mysql> explain select * from userinfo;
  2. +----+-------------+----------+------------+------+---------------+------+---------+------+--------+----------+-------+
  3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  4. +----+-------------+----------+------------+------+---------------+------+---------+------+--------+----------+-------+
  5. | 1 | SIMPLE | userinfo | NULL | ALL | NULL | NULL | NULL | NULL | 997307 | 100.00 | NULL |
  6. +----+-------------+----------+------------+------+---------------+------+---------+------+--------+----------+-------+
  7. 1 row in set, 1 warning (0.00 sec)
  8. mysql> explain select * from (select id,name from userinfo where id < 20) as A;
  9. +----+-------------+----------+------------+------+---------------+------+---------+------+--------+----------+-------------+
  10. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  11. +----+-------------+----------+------------+------+---------------+------+---------+------+--------+----------+-------------+
  12. | 1 | SIMPLE | userinfo | NULL | ALL | NULL | NULL | NULL | NULL | 997307 | 33.33 | Using where |
  13. +----+-------------+----------+------------+------+---------------+------+---------+------+--------+----------+-------------+
  14. 1 row in set, 1 warning (0.00 sec)

各字段参数说明:


  1. select_type:
  2. 查询类型
  3. SIMPLE 简单查询
  4. PRIMARY 最外层查询
  5. SUBQUERY 映射为子查询
  6. DERIVED 子查询
  7. UNION 联合
  8. UNION RESULT 使用联合的结果
  9. table:
  10. 正在访问的表名
  11. type:
  12. 查询时的访问方式,性能:all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const
  13. ALL 全表扫描,对于数据表从头到尾找一遍
  14. select * from userinfo;
  15. 特别的:如果有limit限制,则找到之后就不在继续向下扫描
  16. select * from userinfo where email = 'alex112@oldboy'
  17. select * from userinfo where email = 'alex112@oldboy' limit 1;
  18. 虽然上述两个语句都会进行全表扫描,第二句使用了limit,则找到一个后就不再继续扫描。
  19. INDEX : 全索引扫描,对索引从头到尾找一遍
  20. select nid from userinfo;
  21. RANGE: 对索引列进行范围查找
  22. select * from userinfo where name < 'alex';
  23. PS:
  24. between and
  25. in
  26. > >= < <= 操作
  27. 注意:!= 和 > 符号
  28. INDEX_MERGE: 合并索引,使用多个单列索引搜索
  29. select * from userinfo where name = 'alex' or nid in (11,22,33);
  30. REF: 根据索引查找一个或多个值
  31. select * from userinfo where name = 'alex112';
  32. EQ_REF: 连接时使用primary key 或 unique类型
  33. select userinfo2.id,userinfo.name from userinfo2 left join tuserinfo on userinfo2.id = userinfo.id;
  34. CONST:常量
  35. 表最多有一个匹配行,因为仅有一行,在这行的列值可被优化器剩余部分认为是常数,const表很快,因为它们只读取一次。
  36. select id from userinfo where id = 2 ;
  37. SYSTEM:系统
  38. 表仅有一行(=系统表)。这是const联接类型的一个特例。
  39. select * from (select id from userinfo where id = 1) as A;
  40. possible_keys:可能使用的索引
  41. key:真实使用的
  42. key_len:  MySQL中使用索引字节长度
  43. rows: mysql估计为了找到所需的行而要读取的行数 ------ 只是预估值
  44. extra:
  45. 该列包含MySQL解决查询的详细信息
  46. “Using index”
  47. 此值表示mysql将使用覆盖索引,以避免访问表。不要把覆盖索引和index访问类型弄混了。
  48. “Using where”
  49. 这意味着mysql服务器将在存储引擎检索行后再进行过滤,许多where条件里涉及索引中的列,当(并且如果)它读取索引时,就能被存储引擎检验,因此不是所有带where子句的查询都会显示“Using where”。有时“Using where”的出现就是一个暗示:查询可受益于不同的索引。
  50. “Using temporary”
  51. 这意味着mysql在对查询结果排序时会使用一个临时表。
  52. “Using filesort”
  53. 这意味着mysql会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。mysql有两种文件排序算法,这两种排序方式都可以在内存或者磁盘上完成,explain不会告诉你mysql将使用哪一种文件排序,也不会告诉你排序会在内存里还是磁盘上完成。
  54. “Range checked for each record(index map: N)”
  55. 这个意味着没有好用的索引,新的索引将在联接的每一行上重新估算,N是显示在possible_keys列中索引的位图,并且是冗余的

慢日志记录

开启慢查询日志,可以让MySQL记录查询时长超过指定时间的语句,通过定位分析性能的瓶颈,能更好的优化数据库系统的性能.


  1. (1) 查询是否开启了慢查询日志
  2. mysql> show variables like 'slow_query%';
  3. +---------------------+----------------------------------------+
  4. | Variable_name | Value |
  5. +---------------------+----------------------------------------+
  6. | slow_query_log | OFF |
  7. | slow_query_log_file | /usr/local/mysql/data/MacBook-slow.log |
  8. +---------------------+----------------------------------------+
  9. 2 rows in set (0.01 sec)
  10. # 参数解释:
  11. slow_query_log:慢查询开启状态:OFF为关闭 ON为开启
  12. slow_query_log_file:慢查询日志存放的位置(注意用户权限)
  13. (2) 查看慢查询超时时间
  14. mysql> show variables like 'long%';
  15. +-----------------+-----------+
  16. | Variable_name | Value |
  17. +-----------------+-----------+
  18. | long_query_time | 10.000000 | # 默认为10妙
  19. +-----------------+-----------+
  20. 1 row in set (0.00 sec)
  21. (3) 开启慢日志
  22. mysql> set global slow_query_log = 1; # 1表示开启,0表示关闭
  23. Query OK, 0 rows affected (0.01 sec)
  24. (4) 修改查询超时时间
  25. mysql> set long_query_time = 1; # 直接指定秒
  26. Query OK, 0 rows affected (0.00 sec)

通过配置文件开启慢日志(推荐):


  1. [mysqld]
  2. slow_query_log = 1
  3. slow_query_log_file = /usr/local/mysql/data/localhost-slow.log
  4. long_query_time = 1
  5. 参数说明:
  6. slow_query_log:慢查询开启状态 1为开启
  7. slow_query_log_file:慢查询日志存放的位置
  8. long_query_time:查询时间超过多少秒才记录,默认10秒,这里修改为1秒

分页性能相关方案

(1) 只有上一页和下一页:

做一个记录:记录当前页的最大id或最小id

  • 下一页:select * from userinfo where id>max_id limit 10;
  • 上一页:select * from userinfo where id<min_id order by id desc limit 10;

(2) 中间有页码的情况


  1. select * from userinfo where id in(
  2. select id from
  3. (select * from userinfo where id > pre_max_id
  4. limit (cur_max_id-pre_max_id)*10) as A
  5. order by A.id desc
  6. limit 10
  7. );


"

【MySQL】索引相关的更多相关文章

  1. mysql 索引相关

    引言: MYSQL由于其免费和开源的性质,在项目中用处广泛.大家都知道,一个MySQL数据库能够储存大量的数据,如果要在大量的数据中查找某一个数据,如果使用全表检索的话,即费时间又费力气,这时,就需要 ...

  2. 面试小知识:MySQL索引相关

    前言 本模板主要是一些面试相关的题目,对于每一道问题,我会提供简单的解答,答案的来源主要是基于自己看了各方资料之后的理解,如果有错的,欢迎指点出来. 1. 什么是最左前缀原则? 以下回答全部是基于My ...

  3. mysql 索引相关知识

    由where 1 =1 引发的思考 最近工作上被说了 说代码中不能用 where 1=1,当时觉得是应该可以用的,但是找不到什么理据, 而且mysql 语句优化这方面确实很薄弱   感觉自己mysql ...

  4. mysql索引相关

    索引有主键索引.唯一索引.普通索引 单列索引,复合索引. 复合索引(a,b,c),可以理解是有三个索引,分别是a.b.c三个索引 前缀不是a的话,复合索引都不起作用,前缀用函数或者是范围,比如< ...

  5. mysql 索引相关问题

    mysql中key .primary key .unique key 与index区别 https://blog.csdn.net/nanamasuda/article/details/5254317 ...

  6. mysql索引相关理解

    1.索引是高效获取数据的数据结构, 2.唯一索引,索引值不重复unique create unique index 索引名 on 表名(字段) alter table 表名 add unique in ...

  7. 【逐步完善】MySql索引相关

    在表中对某个字段添加索引: alter table tablename add index (columnname);

  8. Mysql——索引相关

    索引失效的情况: 随着表的增长,where条件出来的数据太多,大于20%左右,使得索引失效(会导致CBO计算走索引花费大于走全表)

  9. mysql开发相关

    1.mysql事务原理,特性,事务并发控制2.如何解决高并发场景下的插入重复3.乐观锁和悲观锁4.常用数据库引擎之间区别5.mysql索引6.B-Tree7.mysql索引类型8.什么时候创建索引9. ...

  10. 如何向女朋友介绍MySQL索引

    目录 一.前言 二.正文 三.索引的类型 四.动态查找树 五.B-Tree 1.B-Tree特征 2.B-Tree的查找(select) 3.B-Tree的插入(insert) 4.B-Tree的删除 ...

随机推荐

  1. C语言-宏定义与使用分析

    1.C语言中的宏定义 #define是预处理器处理的单元实体之— #define定义的宏可以出现在程序的任意位置 #define定义之后的代码都可以使用这个宏 2.定义宏常量 #define定义的宏常 ...

  2. C++ 实例练习-替换原生数组

    C++ 实例练习-替换原生数组 main.cpp #include <stdio.h> #include "intarray.h" int main(int argc, ...

  3. 在MyEclipse中修改文件名出现问题

    问题描述:An exception has been caught while processing the refactoring 'Rename Compilation Unit'. 问题原因:项 ...

  4. javascript 循环读取数组中的值

    //数组 var a = ["#F85C6F", "#78B0F0", "#DB83ED", "#8EC656", &q ...

  5. L1-2 倒数第N个字符串

    思路 这题就是一道进制转换,用26进制表示一个数,以及26进制下的数的加减操作. 代码 #include <bits/stdc++.h> using namespace std; int ...

  6. 解决:配置虚拟主机,重启apache,[warn] _default_ VirtualHost overlap on port 80, the first has precedence

    http://blog.csdn.net/kaizhu_qin/article/details/17506293 很多第一次配置apache的虚拟主机的时候,以为配置第一个虚拟主机完成以后,以后就不会 ...

  7. DOM的方法和属性

    HTML DOM 方法是我们可以在节点(HTML 元素)上执行的动作. HTML DOM 属性是我们可以在节点(HTML 元素)设置和修改的值. 编程接口 可通过 JavaScript (以及其他编程 ...

  8. python项目虚拟环境搭建

    一. 虚拟环境搭建目的 一个项目一个环境,防止各个项目互相干扰,项目更加简洁,利于打包.... 二.使用 pip install virtualenv 安装 创建虚拟环境 cd my_project_ ...

  9. 在同一个tomcat下部署多个springboot项目时,springboot项目无法正常启动的问题

    这个问题是基于,不使用springboot内置的tomcat会产生(即使用自己的tomcat时). 今天在部署springboot项目的时候遇到了一个问题,怎么部署都访问不了,在网上查了很多原因,什么 ...

  10. 题解【洛谷P3385】【模板】负环

    题目描述 暴力枚举/\(SPFA\)/\(Bellman-ford\)/奇怪的贪心/超神搜索 寻找一个从顶点1所能到达的负环,负环定义为:一个边权之和为负的环. 输入输出格式 输入格式 第一行一个正整 ...