网站建设知识
[高性能MySQL]
2025-07-22 11:14  点击:0

[高性能MySQL]-创建高性能的索引。

索引是存储引擎用于快速找到记录的一种数据结构。索引是对 查询性能优化 最有效的手段了,索引能够轻松将查询性能提升几个数量级。索引我们一般都是对某一列加索引。

存储引擎先在索引中找到对应值,然后根据匹配的索引记录找到对应的数据行。比如运行如下查询语句:

SELECT first_name from actor where actor_id=5;

如果在actor_id列上建立有索引, MySQL将使用该索引找到actor_id 为5的行,也就是说,MySQL先在索引上按值查找,然后返回所有包含该值的数据行。

索引可以包含一个或则多个列的值,如果索引包含多个列,那么列的顺序也十分重要,因为MySQL只能高效的使用索引的最左前缀列。创建一个包含两个列的索引和创建两个包含包含一个列的索引是大不相同的。

1.索引的类型:

在MySQL中索引是在存储引擎层而不是在服务器层实现的。

索引有多种类型,根据存储引擎的不同索引的类型也不同,最常见的是B-Tree索引和哈希索引。

(1)B-Tree树索引

一般情况下我们说的索引都是指B-Tree索引,它使用B-Tree数据结构来存储数据。实际上其实是基于B+Tree实现的,在每个叶子结点都包含一个指向下一个叶子结点的指针。

B-Tree意味着所有的值都是按照顺序存储的,并且每一个叶子页到根的距离相同。使用B-Tree索引后,存储引擎不再需要进行全表扫描来获取需要的数据,而是从索引的根节点开始进行搜索,最终结果是要么找到对应的值,要么记录不存在。这样就能够加快访问数据的速度。

B-Tree对索引是顺序组织存储的,所以很适合查找范围数据。(比如查找I-k开头的名字,这样效率会很高)

可以使用B-Tree索引的查询类型:
(1)全值匹配:和索引中的所有列进行匹配。

(2)匹配最左前缀:对于一个索引包含多个列,只使用索引的第一列。

(3)匹配列前缀:匹配某一列的值的开头部分。(比如匹配name字段的时候,只匹配以J开头的姓名)这里只用到了索引的第一列。

(4)匹配范围值:匹配字段在某一个范围内的记录,这里只用到了索引的第一列。

(5)精确匹配某一列并范围匹配另外一列:对于一个索引包含多个字段的情况,比如精确匹配第一列,第二列范围匹配。

(6)只访问索引的查询:之访问索引行而不访问记录中其余字段的数据行。

对于B-Tree的索引也有一些限制:
(1)索引只能从最左列开始查找

(2)如果查询中有某个列的范围查找,则其右边所有列都无法使用索引优化。

看到上面的两个限制应该就能明白关于索引中包含多个列的时候,索引列的顺序是很重要的。

(2)Hash哈希索引

哈希索引是基于哈希表实现的,只有精确匹配索引所有列的查询才有效。对于每一行数据存储引擎都会所有的索引列计算一个哈希码,哈希码是一个较小的值,并且不同键值的行计算出来的哈希码也不一样。

1)哈希索引只存储哈希值和行指针,并不存储具体的字段值,所以一定会存在读取行的过程。

2)哈希索引并不是按照索引值顺序存储的,所以就无法用于排序。

3)哈希索引只支持等值比较查询,不支持范围比较查询,这与哈希表的特性与有关。

4)哈希索引就存在哈希冲突的问题,对于哈希冲突的数据必须遍历链表中的所有行指针。

上面的这些限制,哈希索引只适合于特定的场合,但是一旦适合哈希索引,性能就会特别高。

使用hash索引时,一般情况下还要再查询条件中带上hash前的值,比如:

mysql>select * from words where crc=crc32(‘gnu’) and word=’gnu’;

这里crc字段就是word字段哈希之后的值,因为hash之后可能存在冲突,带上原本的值做上二次比较,就可以精确定位。

2.索引的优点:

索引可以让服务器快速定位到表的指定位置。但是这不是唯一的作用,比如:
(1)对于B-Tree索引,由于B-Tree是按照顺序存储数据的,所以用来做order by 操作或则是 group by操作的效率很高。

(2)因为索引中存储了实际的列值,所以有些查询只需要索引就可以完成全部查询。

总结来说就是3点:
(1)索引大大减少服务器需要扫描的数据量;

(2)索引可以帮助服务器避免排序和临时表;

(3)索引可以将随机IO变为排序IO。

3.高性能的索引策略

(1)独立的列

所谓独立的列是指:索引列不能是表达式的一部分,也不能是函数的参数。

比如对于下面的一个例子:

select actor_id from actor where actor_id+1=5;

对于这样的一个SQL,where语句后面 是一个表达式,其实很明显是actor_id=4的条件,但是MySQL却无法解析,索引无法正却使用索引。

还有一种是函数参数:也是无法正常的使用索引的

select ... where TO_DAYS(CURRENT_DATE) - TO_DAYS(date_col)<=10;

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

前缀索引:有时候需要索引的列可能会很长,这时候会导致索引大而且很慢,。我们可以通过只索引列开始的部分(也就是只索引某一列的前面几个字符),这样可以大大节省索引空间也能加快索引的速度,但是也会降低索引的选择性(也就是索引查出来的结果会变多)。

索引的选择性是指:不重复的索引值(基数)和数据表中的记录总数(#T)的比值,范围从1/#T之间。索引的选择性越高则查询效率越高,因为选择性高的索引可以让MYSQL在查找时过滤掉更多的行。
唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。

(3)多列索引

注意这里要区分:为每个列创建独立的索引和为多个列创建一个索引的区别。

比如下面这种情况:

CREATE TABLE t{c1 int,c2 int,c3 int,key(c1),key(c2),key(c3)}

这一种就是为表中的3个列都创建了索引。

但是多个列创建索引就是:创建了一个索引,包含customer_id,和staff_id

alter table payment add KEY(customer_id, staff_id);

(4)选择合适的索引列顺序

在为多个字段创建一个索引的时候(多列索引),最大的困惑就是怎么排列索引中多个字段的顺序。

在一个多列B-Tree中,索引列的顺序意味着索引首先按照最左列进行排序,其次是第二列,所以索引的第一列是查询是最高效的。为了精确满足列顺序的ORDER BY、GROUP BY和DISTINCT等查询的需要,索引列的排列顺序至关重要。

关于索引的排序有一个规则:将选择性最高的列放在索引的最前列。

当不需要考虑分组和排序的时候,将选择性最高的列放在前面是最好的,这时候索引的作用仅仅只是优化where条件的查询,

以下面的查询为例:

SELECT * FROM item WHERE staff_id=2 AND customer_id=584;

这时候应该创建(staff_id, customer_id)的索引还是应该创建(customer_id,staff_id)的索引呢?这时候就应该确认一下那个字段的选择性更高,先查询一下staff_id和customer_id的总数,哪个小就将哪个放在前面。

(5)聚簇索引

聚簇索引并不是一种单独的索引类型,而是一种数据存储方式。在InnoDB的聚簇索引实际上是在同一个结构中保存额B-tree索引和数据行。

(6)覆盖索引

如果一个索引包含(或则说覆盖)所有需要查询的字段的值,我们就称之为覆盖索引。

覆盖索引是非常有用的工具,对于索引来说,只需要扫描索引就能在索引的叶子节点中获得所有的数据,而不需要回表查询,这就能极大的提高性能。带来的好处也很多:

(1)索引条目通常远远小于数据行的大小,如果只需要读取索引那MySQL就会极大的减少数据访问量,这对缓存的负载非常重要。

(2)因为索引是按照列值顺序存储的,所以对于IO密集型的范围查找会比随机从磁盘中读取每一行数据的Io要少得多、

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

MySQL有两种方式可以生成有序的结果:
(1)通过order by 排序操作;

(2)按索引顺序扫描;

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

(9)压冗余和重复索引

(10)未使用的索引

(11)索引和锁

4.索引学习案例

(1)支持多种过滤条件

(2)避免多个范围条件

(3)索优化排序

5.维护索引和表

(1)索找到并修复顺坏的表

(2)更新索引统计信息

(3)减少索引和数据碎片