一、使用索引的优缺点

索引是数据库用来提高性能的最常用工具,所有的MySQL列都可以被索引,对相关的列进行索引是提高select性能的最佳途径。使用索引的优点和缺点如下:
优点

  • 快速访问数据表中的特定信息,提高检索速度
  • 创建唯一性索引,保证数据库表中每一行数据的唯一性。
  • 加速表和表之间的连接

缺点

  • 创建索引和维护索引需要耗费时间,这个时间随着数据量的增加而增加
  • 索引需要占用物理空间,不光是表需要占用数据空间,每个索引也需要占用物理空间
  • 当对表进行增、删、改、的时候索引也要动态维护,这样就降低了数据的维护速度

二、设计索引的原则

为了提高索引的使用效率,设计索引时应遵循以下规则:

  • 添加索引的列不一定是要搜索的列:最适合索引的列是出现在WHERE子句中的列,或连接子句中指定的列,而不是SELECT关键字后的选择列表中的列。
  • 使用唯一索引:索引的列的基数(不重复数)越大,索引的效果越好。比如出生日期列数据各不相同,适合添加索引,而性别列只含有‘M’和‘F’两个值,则不适合添加索引。
  • 使用短索引:如果对字符串列进行索引,应当制定一个前缀长度,例如,一个CHAR(200)的列如果前10个或者20个字符多数是唯一的,就不要对整个列进行索引。较短的索引涉及的磁盘IO较少,占用空间也小,查询更快。
  • 不要过度索引:每个额外的索引都要占用额外的磁盘空间,并降低写操作性能。在修改表内容时,索引必须进行更新,可能还会重构,从而降低表的修改速度。

三、索引的存储分类

1、分类

索引是在MySQL存储引擎层实现的,而不是在服务器层,所以每种存储引擎的索引都不一定相同,MySQL目前有以下四种索引:

  • B-Tree索引:最常见的索引类型,大部分存储引擎都支持B树索引。
  • HASH索引:只有Memory、Heap引擎支持,使用场景简单。
  • R-Tree索引(空间索引):MyISAM的一个特殊索引类型,使用较少。
  • Full-text(全文索引):特殊索引类型,MyISAM和InnoDB支持。

MyISAM、InnoDB、Memory三个常用引擎支持的索引类型比较:

索引 MyISAM引擎 InnoDB引擎 Memory引擎
B-Tree索引 支持 支持 支持
HASH索引 不支持 不支持 支持
R-Tree索引 支持 不支持 不支持
Full-text索引 支持 支持 不支持

2、HASH索引与B-Tree索引

使用HASH索引时应注意:

  • HASH索引只能用于=或<=>操作符的等式比较。
  • 优化器不能使用HASH索引来加速ORDER BY 操作。
  • HASH索引只能使用整个关键字来搜索一行,而不能使用通配符。

下列范围查询适用于HASH索引和B-Tree索引:

select * from demo where id=2 or id in(4,5,8,9);

下列范围查询只适用于B-Tree索引:

select * from demo where id>5 and id<10;
select * from demo where birthday like '1996-08-%' or salary between 5000 and 10000;

此处如果表类型是Memory/Heap,id是HASH索引,则查询使用全表扫描的方式,不会用到索引。

四、SQL优化中的索引问题

SQL优化中对索引的优化实际上是将对添加了索引,但sql执行计划没有选择使用索引的场景的优化。
以下内容默认使用B-Tree索引。
案例用表:

mysql> show create table demo \G;
*************************** 1. row ***************************Table: demo
Create Table: CREATE TABLE `demo` (`id` int(10) NOT NULL AUTO_INCREMENT,`name` varchar(20) NOT NULL DEFAULT '张三' COMMENT '姓名',`sex` enum('男','女') NOT NULL DEFAULT '男' COMMENT '性别',`age` int(10) DEFAULT NULL,`birthday` date DEFAULT '1970-01-01',`address` varchar(50) DEFAULT NULL,`salary` double DEFAULT '0',PRIMARY KEY (`id`),
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)ERROR:
No query specifiedmysql> select * from demo;
+----+--------+-----+------+------------+---------+--------+
| id | name   | sex | age  | birthday   | address | salary |
+----+--------+-----+------+------------+---------+--------+
|  2 | tom    | 男  |   22 | 1996-08-08 | 武汉    |   2000 |
|  4 | 赵六   | 男  |   60 | 1958-08-08 | 上海    |   3000 |
|  6 | 李四   | 男  |   23 | 1996-08-08 | 武汉    |  50000 |
|  7 | lucy   | 女  |   22 | 1996-07-08 | 武汉    |   8000 |
|  8 | 李四   | 男  |   36 | 1982-06-08 | 杭州    |   6000 |
|  9 | sunnie | 女  |   22 | 1996-08-28 | NULL    |      0 |
| 11 | 王五   | 女  |   30 | 1988-08-08 | 北京    |  10000 |
| 12 | sherly | 女  |   18 | 2000-02-20 | 深圳    |  12000 |
+----+--------+-----+------+------------+---------+--------+
8 rows in set (0.00 sec)

1、MySQL中能使用索引的场景

(1)匹配全值。

对索引中所有的列都指定具体值。例如:

mysql> create index member on demo(name,sex,address(10));
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0mysql> explain select * from demo where name='王五' and sex='女' and address='北京' \G;
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: demotype: ref
possible_keys: memberkey: memberkey_len: 96ref: const,const,constrows: 1Extra: Using index condition; Using where
1 row in set (0.00 sec)

explain语句输出结果中type=ref表示使用非唯一索引或唯一索引的前缀进行扫描,key=member表示使用了组合索引member。
Extra中的Using index condition表示使用ICP(Index Condition Pushdown)优化查询。

(2)匹配值的范围查询

对索引值能够进行范围查找。例如:

mysql> explain select * from demo where id>5 and id<10 \G;
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: demotype: range
possible_keys: PRIMARYkey: PRIMARYkey_len: 4ref: NULLrows: 3Extra: Using where
1 row in set (0.00 sec)

type为range说明优化器选择范围查询,key为primary说明使用主键查询。

(3)匹配最左前缀

仅仅使用复合索引中最左边的列进行查找,例如:

mysql> explain select * from demo where name='tom' and address in ('武汉','北京','上海') \G;
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: demotype: ref
possible_keys: memberkey: memberkey_len: 62ref: constrows: 1Extra: Using index condition; Using where
1 row in set (0.00 sec)
mysql> explain select * from demo where sex='男' and address in ('武汉','北京','上海') \G;
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: demotype: ALL
possible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: 7Extra: Using where
1 row in set (0.00 sec)

从(1)中知道创建的member索引包含三列:name、sex、address,只要查询条件包含第一列(最左前缀)时,优化器使用复合索引member进行查询,当查询条件不包含第一列时,执行计划不会利用到复合索引member。

(4)仅仅对索引进行查询

当查询的列都在索引的字段中时,查询效率更高,例如:

mysql> explain select name,sex from demo where name='tom' \G;
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: demotype: ref
possible_keys: memberkey: memberkey_len: 62ref: constrows: 1Extra: Using where; Using index
1 row in set (0.00 sec)

要查询的name字段和sex字段都在member索引中,Extra中Using index,意味着直接访问索引就能获取到所需数据,也就是‘覆盖索引扫描’。Using where表示优化器需要通过索引回表查询数据。

(5)匹配列前缀

仅仅使用索引中的第一列的开头一部分信息进行查询,例如:

mysql> explain select * from demo where name like 'sh%' \G;
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: demotype: range
possible_keys: memberkey: memberkey_len: 62ref: NULLrows: 1Extra: Using index condition
1 row in set (0.00 sec)
(6)索引一部分精确匹配,其他部分范围匹配

例如:

mysql> explain select * from demo where name='李四' and address<'武汉' \G;
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: demotype: ref
possible_keys: memberkey: memberkey_len: 62ref: constrows: 2Extra: Using index condition; Using where
1 row in set (0.00 sec)

key=member说明优化器使用了member索引。

(7)如果列名是索引,那么使用 列名 is null 会使用索引。(区别于oracle)

例如:

mysql> create index city on demo(address);
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0mysql> explain select * from demo where address is null \G;
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: demotype: ref
possible_keys: citykey: citykey_len: 153ref: constrows: 1Extra: Using index condition
1 row in set (0.00 sec)

这里给address列创建一个索引city,使用列名is null 会使用索引。

2、MySQL中存在索引但不能使用索引的场景

(1)以%开头的like查询不能利用B-Tree索引。

例如:

mysql> explain select * from demo where name like '%m' \G;
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: demotype: ALL
possible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: 7Extra: Using where
1 row in set (0.00 sec)

以%或_开头的查询不能利用B-Tree索引的由于B-Tree索引的平衡树结构。
解决办法:
先获得满足条件的主键列表,之后根据主键回表检索记录,这样可以避免全表扫描产生大量的IO请求。
语句如下:

mysql> explain select * from (select id from demo where name like '%m') a,demo b where a.id=b.id \G;*************************** 1. row ***************************id: 1select_type: PRIMARYtable: btype: ALL
possible_keys: PRIMARYkey: NULLkey_len: NULLref: NULLrows: 7Extra: NULL
*************************** 2. row ***************************id: 1select_type: PRIMARYtable: <derived2>type: ref
possible_keys: <auto_key0>key: <auto_key0>key_len: 4ref: test.b.idrows: 2Extra: Using index
*************************** 3. row ***************************id: 2select_type: DERIVEDtable: demotype: index
possible_keys: NULLkey: memberkey_len: 96ref: NULLrows: 7Extra: Using where; Using index
3 rows in set (0.00 sec)

换一个数据量较大的数据库验证情况:

mysql> show profiles;
+----------+------------+---------------------------------------------------------------------------
------------------+
| Query_ID | Duration   | Query|
+----------+------------+---------------------------------------------------------------------------
------------------+
|        3 | 0.03196575 | select * from tb_item where updated like '%30'|
|        4 | 0.01050700 | select * from (select id from tb_item where updated like '%30') a,tb_item
b where a.id=b.id |
|        5 | 0.02138725 | select * from tb_item where id in (select id from tb_item where updated li
ke '%30')         |
+----------+------------+---------------------------------------------------------------------------
------------------+
5 rows in set, 1 warning (0.00 sec)

打开profiling观察语句执行用时,查询3是全表扫描方式,查询4是先得到主键列表,然后连接查询方式,查询5是用子查询方式。结果显示得到主键列表后连接查询最快,子查询次之,全表扫描最慢。

(2)数据类型出现隐式转换时不会使用索引

例如:

mysql> explain select * from demo where name=777 \G;
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: demotype: ALL
possible_keys: memberkey: NULLkey_len: NULLref: NULLrows: 10Extra: Using where
1 row in set (0.00 sec)

name字段类型为字符串,查询时where name=777给的是数值类型,MySQL会发生隐式转换,将777转化为字符串类型,但是即使name字段存在索引,发生隐式转换后不会使用索引。由例子中key=null可见。
加上引号后,没有隐式转换,就会用到索引了:

mysql> explain select * from demo where name='777' \G;
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: demotype: ref
possible_keys: memberkey: memberkey_len: 62ref: constrows: 2Extra: Using index condition
1 row in set (0.00 sec)
(3)复合索引不满足最左原则不会使用索引

见上一节第(3)小节

(4)如果MySQL估计使用索引比全表扫描更慢,则不会使用索引

在查询的时候,筛选性越高越容易用到索引,筛选性越低越不容易用到索引。

mysql> explain select * from demo where name like 's%' \G;
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: demotype: range
possible_keys: memberkey: memberkey_len: 62ref: NULLrows: 2Extra: Using index condition
1 row in set (0.00 sec)

正常情况下,使用索引member。执行以下语句,在name列所有值钱加一个s:

mysql> update demo set name=concat('s',name);

此时MySQL估计使用索引比全表扫描更慢,不使用索引:

mysql> explain select * from demo where name like 's%' \G;
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: demotype: ALL
possible_keys: memberkey: NULLkey_len: NULLref: NULLrows: 10Extra: Using where
1 row in set (0.00 sec)
(5)用or分割条件,如果or前的条件的列有索引,而后面的条件的列没有索引,那么前面的索引也不会被用到
mysql> explain select * from demo where name='tom' or age=22 \G;
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: demotype: ALL
possible_keys: memberkey: NULLkey_len: NULLref: NULLrows: 10Extra: Using where
1 row in set (0.00 sec)

name存在索引,age没有索引,结果没有使用索引。

MySQL索引的设计、使用与优化相关推荐

  1. MySQL索引使用方法和性能优化

    关于MySQL索引的好处,如果正确合理设计并且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索引的MySQL就是一个人力三轮车.对于没有索引的表,单表查询可能几十万数据就是瓶颈,而通常大型 ...

  2. mysql索引空间太大_MySQL优化索引

    1.  MySQL如何使用索引 索引用于快速查找具有特定列值的行.如果没有索引,MySQL必须从第一行开始,然后遍历整个表以找到相关的行.表越大,花费越多.如果表中有相关列的索引,MySQL可以快速确 ...

  3. 13、MySQL索引的设计原则

    索引的设计可以遵循一些已有的原则,创建索引的时候应尽量考虑符合这些原则,便于提升索引的使用效率,更高效的使用索引.本节将介绍一些索引的设计原则. 1. 选择唯一性索引 唯一性索引的值是唯一的,可以更快 ...

  4. mysql索引怎么设计,MySQL如何设计索引

    MySQL改善性能最好的方式,就是通过数据库中合理地使用索引,换句话说,索引是提高 MySQL 数据库查询性能的主要手段.在下面的章节中,介绍了索引类型.强制索引.全文索引. MySQL 索引可以分为 ...

  5. mysql索引怎么设计_mysql索引设计

    mysql索引设计 1.B树与B+树的区别? B-Tree:一个节点可以拥有大于2个子节点的平衡多叉树,所有关键字在整颗树中出现,包括在非叶子节点也能命中, 叶子节点之间没有链表 B+Tree:每个叶 ...

  6. mysql索引的使用和优化

    参考: http://blog.csdn.net/xluren/article/details/32746183 http://www.cnblogs.com/hustcat/archive/2009 ...

  7. Mysql 索引 与 多表查询性能优化

    最近做项目需要用到Luence Whoosh,要定时从数据库中索引出数据来供检索,但是在索引中设计多表查询,速度较慢,因为强迫症,想要做性能优化,因此把Mysql的核心又翻出来研究一遍. 关于MySQ ...

  8. mysql索引总结----mysql 索引类型以及创建

    文章归属:http://feiyan.info/16.html,我想自己去写了,但是发现此君总结的非常详细.直接搬过来了 关于MySQL索引的好处,如果正确合理设计并且使用索引的MySQL是一辆兰博基 ...

  9. 数据库:MySQL索引总结

    20多条数据源随机生成200万条数据,平均每条数据源都重复大概10万次,表结构比较简单,仅包含一个自增ID,一个char类型,一个text类型和一个int类型,单表2G大小,使用MyIASM引擎.开始 ...

最新文章

  1. MFC遍历窗体所有的控件
  2. 百度知道回答的依赖注入
  3. 技术人写作和写代码一样重要
  4. 们--加强斐波那契【递推】
  5. aⅴgo安装包下载_Mysql 安装
  6. ht for web(图扑)加载模型
  7. 水泥行业超低排放政策频发,企业如何完成超低排放改造?
  8. SFB 项目经验-11-为某上市企业的Skype for Business规划与实施
  9. matlab中三维数组,维数转换
  10. Word2013制作中国的传统福字在屋门上贴的福字(福倒了)
  11. 1051 复数乘法(JAVA)
  12. 帝国cms tag生成html,帝国cms如何自动填写tag标签【亲测】
  13. 更改cadence617 schematic和visualizationAnalysis界面背景颜色
  14. ARP代理(Proxy ARP)
  15. 【智能物流】200亿规模的制造企业,如何规划供应链物流体系?
  16. 本地生活商家和达人注意了,如何提高核销率
  17. python蜂窝状六边形_CSS-蜂窝状展示区域(多个六边形)的一种实现方式
  18. Java时间戳与日期格式转换工具类
  19. Win32下利用_beginthread函数创建一个线程
  20. Chrome-谷歌浏览器多开教程

热门文章

  1. npm、nrm两种方式查看源和切换镜像
  2. 类的构造方法编程训练2—设置信用卡密码
  3. 龙芯平台python答案_使用 go-cqhttp 在龙芯和其他平台搭建qq机器人
  4. TFS 掩蔽或取消掩蔽工作区中的文件夹
  5. c语言 string code,ctestcode C语言代码实例助手下载
  6. Android玩乐系列:修改汇编代码支持原生高清来电大头贴(一)
  7. 温州市劳动和社保局信息系统集成招标3000万
  8. java简拼_javascript实现根据汉字获取简拼
  9. 电话发明背后的浪漫爱情故事
  10. Google Logo的秘密