关于mysql索引的一些学习笔记

1.什么是索引

一种高效的查询方式

2.为什么用索引

	索引大大减少了服务器需要扫描的数据量。
	索引可以帮助服务器避免排序和临时表。
	索引可以将随机I/O变为顺序I/O。

3.索引是最好的解决方案吗?

	不是,需要看需求和数据量。
	(1)对于非常小的表,大部分情况下简单的全表扫描更高效。
	(2)对于中到大型的表,索引就非常有效。
	(3)对于特大型的表,建立和使用索引的代价将随之增长

4.高效的索引策略

(1)独立的列

		不要在列上做计算、函数、装换

(2)前缀索引和索引选择性

索引的选择性越高则查询效率越高,因为选择性高的索引可以让MySQL在查找时过滤掉更多的行。唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。
如果前缀的选择性能够接近0.031,基本上就可用了。在一个查询中针对不同前缀长度进行计算,这对于大表非常有用。

(3)多列索引

多列索引的缺点
- 多个And--相交操作--以为着需要一个包含所有相关列的多列索引,而不是多个独立的单例索引
- 多个OR--联合查询--需要耗费大量CPU和内存资源在算法的缓存、排序和合并操作上。特别是当其中有些索引的选择性不高,需要合并扫描返回的大量数据的时候。

(4)索引列顺序

		将选择性最高的列放到索引最前列。这个建议有用吗?在某些场景可能有帮助,但通常不如避免随机IO和排序那么重要,考虑问题需要更全面(场景不同则选择不同,没有一个放之四海皆准的法则。这里只是说明,这个经验法则可能没有你想象的重要)。
		当不需要考虑排序和分组时,将选择性最高的列放在前面通常是很好的。这时候索引的作用只是用于优化WHERE条件的查找。在这种情况下,这样设计的索引确实能够最快地过滤出需要的行,对于在WHERE子句中只使用了索引部分前缀列的查询来说选择性也更高。然而,性能不只是依赖于所有索引列的选择性(整体基数),也和查询条件的具体值有关,也就是和值的分布有关。这和前面介绍的选择前缀的长度需要考虑的地方一样。可能需要根据那些运行频率最高的查询来调整索引列的顺序,让这种情况下索引的选择性最高。
		在一个多列B-Tree索引中,索引列的顺序意味着索引首先按照最左列进行排序,其次是第二列,等等。所以,索引可以按照升序或者降序进行扫描,以满足精确符合列顺序的ORDER BY、GROUP BY和DISTINCT等子句的查询需求。

(5)聚簇索引

		聚簇索引:不是一种单独的索引类型,而是一种数据存储方式
		
		存储的id的三种情况
			- InnoDB将通过主键聚集数据。
			- 如果没有定义主键,InnoDB会选择一个唯一的非空索引代替。
			- 如果没有这样的索引,InnoDB会隐式定义一个主键来作为聚簇索引。
			
		聚簇索引优点:
			- 可以把相关数据保存在一起
				例如实现电子邮箱时,可以根据用户ID来聚集数据,这样只需要从磁盘读取少数的数据页就能获取某个用户的全部邮件。如果没有使用聚簇索引,则每封邮件都可能导致一次磁盘I/O。
			- 数据访问更快
				聚簇索引将索引和数据保存在同一个B-Tree中,因此从聚簇索引中获取数据通常比在非聚簇索引中查找要快。
			- 使用覆盖索引扫描的查询可以直接使用页节点中的主键值。
		如果在设计表和查询时能充分利用上面的优点,那就能极大地提升性能。
		
		聚簇索引缺点:
		- 吃内存
				聚簇数据最大限度地提高了I/O密集型应用的性能,但如果数据全部都放在内存中,则访问的顺序就没那么重要了,聚簇索引也就没什么优势了。
		- 插入速度严重依赖于插入顺序。
				按照主键的顺序插入是加载数据到InnoDB表中速度最快的方式。但如果不是按照主键顺序加载数据,那么在加载完成后最好使用OPTIMIZE TABLE命令重新组织一下表。
		- 更新聚簇索引列的代价很高
				因为会强制InnoDB将每个被更新的行移动到新的位置。
		- 页分裂问题
				基于聚簇索引的表在插入新行,或者主键被更新导致需要移动行的时候,可能面临“页分裂(page split)”的问题。当行的主键值要求必须将这一行插入到某个已满的页中时,存储引擎会将该页分裂成两个页面来容纳该行,这就是一次页分裂操作。页分裂会导致表占用更多的磁盘空间。
		- 聚簇索引可能导致全表扫描变慢
				聚簇索引可能导致全表扫描变慢,尤其是行比较稀疏,或者由于页分裂导致数据存储不连续的时候。
		- 二级索引的问题
				二级索引(非聚簇索引)可能比想象的要更大,因为在二级索引的叶子节点包含了引用行的主键列。
				二级索引访问需要两次索引查找,而不是一次。
				为什么二级索引需要两次索引查找?
				因为二级索引中保存的“行指针”的实质。二级索引叶子节点保存的不是指向行的物理位置的指针,而是行的主键值。这意味着通过二级索引查找行,存储引擎需要找到二级索引的叶子节点获得对应的主键值,然后根据这个值去聚簇索引中查找到对应的行。这里做了重复的工作:两次B-Tree查找而不是一次。对于InnoDB,自适应哈希索引能够减少这样的重复工作。

(6)覆盖索引

		1.什么是覆盖索引
			“如果一个索引包含(或者说覆盖)所有需要查询的字段的值,我们就称之为“覆盖索引”
		2.覆盖索引有什么好处
			1.查出的索引的数据少,减小数据访问量,减少数据拷贝
				索引条目通常远小于数据行大小,所以如果只需要读取索引,那MySQL就会极大地减少数据访问量。这对缓存的负载非常重要,因为这种情况下响应时间大部分花费在数据拷贝上。覆盖索引对于I/O密集型的应用也有帮助,因为索引比数据更小,更容易全部放入内存中(这对于MyISAM尤其正确,因为MyISAM能压缩索引以变得更小)。
			2、索引的有序性对IO密集型的范围查询比随机从磁盘读取每一行数据的IO要变得少
				因为索引是按照列值顺序存储的(至少在单个页内是如此),所以对于I/O密集型的范围查询会比随机从磁盘读取每一行数据的I/O要少得多。对于某些存储引擎,例如MyISAM和Percona XtraDB,甚至可以通过OPTIMIZE命令使得索引完全顺序排列,这让简单的范围查询能使用完全顺序的索引访问。
			3.某些存储引擎在内存中只能缓存索引,缓存和磁盘存储数据。
				一些存储引擎如MyISAM在内存中只缓存索引,数据则依赖于操作系统来缓存,因此要访问数据需要一次系统调用。这可能会导致严重的性能问题,尤其是那些系统调用占了数据访问中的最大开销的场景。
			4.innodb聚簇索引的二级索引在叶子节点存储的是行主键,如果没有覆盖索引,需要做回表查询
				由于InnoDB的聚簇索引,覆盖索引对InnoDB表特别有用。InnoDB的二级索引在叶子节点中保存了行的主键值,所以如果二级主键能够覆盖查询,则可以避免对主键索引的二次查询。”
		3.覆盖索引失效
			不是所有类型的索引都可以成为覆盖索引。覆盖索引必须要存储索引列的值,而哈希索引、空间索引和全文索引等都不存储索引列的值,所以MySQL只能使用B-Tree索引做覆盖索引。
			没有任何索引能够覆盖这个查询
			不能在索引中执行LIKE操作

(7)使用索引扫描来做排序

		两种方式可以生成有序的结果
			- 通过排序操作
			- 按索引顺序扫描
		如果EXPLAIN出来的type列的值为“index”,则说明MySQL使用了索引扫描来做排序(不要和Extra列的“Using index”搞混淆了)
		扫描索引本身是很快的,因为只需要从一条索引记录移动到紧接着的下一条记录。但如果索引不能覆盖查询所需的全部列,那就不得不每扫描一条索引记录就都回表查询一次对应的行。这基本上都是随机I/O,因此按索引顺序读取数据的速度通常要比顺序地全表扫描慢,尤其是在I/O密集型的工作负载时。
		MySQL可以使用同一个索引既满足排序,又用于查找行。因此,如果可能,设计索引时应该尽可能地同时满足这两种任务,这样是最好的。
		只有当索引的列顺序和ORDER BY子句的顺序完全一致,并且所有列的排序方向(倒序或正序)都一样时,MySQL才能够使用索引来对结果做排序(14)。如果查询需要关联多张表,则只有当ORDER BY子句引用的字段全部为第一个表时,才能
	使用索引做排序。ORDER BY子句和查找型查询的限制是一样的:需要满足索引的最左前缀的要求;否则,MySQL都需要执行排序操作,而无法利用索引排序。
	有一种情况下ORDER BY子句可以不满足索引的最左前缀的要求,就是前导列为常量的时候。如果WHERE子句或者JOIN子句中对这些列指定了常量,就可以“弥补”索引的不足。

(8)压缩(前缀压缩)索引

		MyISAM使用前缀压缩来减少索引的大小,从而让更多的索引可以放入内存中,这在某些情况下能极大地提高性能。

(9)冗余和重复索引

		重复索引是指在相同的列上按照相同的顺序创建的相同类型的索引。应该避免这样创建重复索引,发现以后也应该立即移除。
		冗余索引和重复索引有一些不同。如果创建了索引(A,B),再创建索引(A)就是冗余索引,因为这只是前一个索引的前缀索引。

(10)未使用的索引

		有一些服务器永远不用的索引。这样的索引完全是累赘,建议考虑删除

(11) 索引和锁

		索引可以让查询锁定更少的行。如果你的查询从不访问那些不需要的行,那么就会锁定更少的行,从两个方面来看这对性能都有好处。首先,虽然InnoDB的行锁效率很高,内存使用也很少,但是锁定行的时候仍然会带来额外开销;其次,锁定超过需要的行会增加锁争用并减少并发性。
		InnoDB在二级索引上使用共享(读)锁,但访问主键索引需要排他(写)锁。这消除了使用覆盖索引的可能性,并且使得SELECT FOR UPDATE比LOCK IN SHARE MODE或非锁定查询要慢很多。

5.索引类型

	主键索引 primary key
	唯一索引 unique key
	普通索引 key
	全文索引 fulltext key

6.索引数据结构类型

hash

		基于哈希表实现
		只有精确匹配索引所有列的查询才有效
		对于每一行数据,存储引擎都会对所有的索引列计算一个哈希码(hash code),哈希码是一个较小的值,并且不同键值的行计算出来的哈希码也不一样。哈希索引将所有的哈希码存储在索引中,同时在哈希表中保存指向每个数据行的指针。”
		代表:Memory引擎

B-tree

B+tree

空间数据索引(R-Tree)

猜你喜欢

转载自blog.csdn.net/tsj11514oo/article/details/117638825
今日推荐