Mysql优化之创建高性能索引(一)

1.索引基础

索引对于良好的性能非常关键。尤其是当表中的数据量越来越大时,索引对性能的影响愈发重要。但是不恰当的索引随着数据量的增加,也会使整个数据库的性能下降。

举个例子:

select a from b where id = 5;

如果在id上建立索引,则Mysql会使用该索引找到id为5的行,也就是说,Mysql现在索引按值进行查找,然后返回所有包含该值的数据行。索引也可以包含一列或者多列,列的顺序也十分重要,因为Mysql只能高效地使用索引的最左前缀列。

索引优化应该是查询性能优化最有效的手段了,一个“最优”的索引有时比一个“好的”索引性能要好两个数量级,所以索引的学习无论对开发者或者DBA来说都极为重要。

2.索引类型

B-Tree索引

人们在谈论索引时,若无指定,一般为B-Tree类型的索引,Mysql大部分引擎支持B-Tree索引,但在不同的存储引擎中,B-Tree也可能以不同存储结构实现,比如InnoDB则使用B+Tree。存储引擎以不同的方式使用B-Tree索引,性能优劣各有不同。

B-Tree通常意味着所有的值都是按顺序存储的,并且每一个叶子页到根的距离相同。下图为B-Tree(B+Tree)索引的抽象表示,大致反映了InnoDB索引是如何工作的。MyISAM使用的结构有所不同,但基本思想是类似的。

这种类型的索引的好处是查询时不需要进行全盘扫描而是从根节点开始搜索,通过比较找到相应的值并进入下层子节点。所以B-Tree比较适合查找范围数据,例如像“找出所有I到K开头的名字”。

假设有如下数据表:

CREATE TABLE People (
       last_name  varcher(50) not null,
       first_name  varcher(50) not null,
       dob date not null,
       gender enum(‘m‘, ‘f‘) not null,
       key(last_name, first_name, dob)
);   

对于表中的每一行数据,索引中包含了last_name,first_name,dob列的值,下图显示了该索引是如何组织数据的存储的。

  • 这里要注意的是,索引对多个值进行排序的依据是CREATE TABLE语句中定义时列的顺序(比如上文的顺序为last_name,first_name,dob)。

下面列举一些B-Tree索引的常用的查询类型:

  • 全值比配 全值匹配指的是和索引中的所有列进行匹配,例如索引可用于查找姓名为Cuba Allen、出生于1960-01-01的人
  • 匹配最左前缀 例如查找所有姓Allen的人,即只使用索引的第一列
  • 匹配列前缀 也可以只匹配某一列的值的开头部分。例如前面提到的索引可用于查找所有以J开头的姓的人。这里也只使用了索引的第一列
  • 匹配范围值 例如前面提到的索引可用于查找姓在Allen和Barrymore之间的人。这里也只使用了索引的第一列
  • 精确匹配某一列并范围匹配另外一列 例如像查找所有姓为Allen,并且名字是字母K开头的人。即第一列last_name全匹配,第二列first_name范围匹配
  • 只访问索引的查询 即查询只需要访问索引,而无须访问数据行。

除了按值查找外,索引还可以用于ORDER BY操作。

下列关于B-Tree索引的一些限制:

  • 如果不是按照索引的最左列开始查找,则无法使用索引。例如上面例子中无法用于查找名字为Bill的人,也无法查找某个特定生日的人,因为这两列都不是最左数据列。
  • 不能跳过索引中的列,例如查找Smith并且在某个特定生日的人,如果不指定first_name,则Mysql只能用上索引的第一列
  • 如果查询中有某个列的范围查询,则其右边的列都无法使用索引优化查找。比如 where last_name=‘Smith‘ AND first_name LIKE ‘%J%‘ AND dob= ‘1976-01-01‘,这个查询只能用上前两列索引,但如果范围查询数量有限,则可以优化为多个等于条件进而使用上索引

哈希索引

哈希索引基于哈希表实现,只有精确匹配索引所有列的查询才有效。在Mysql中只有Memory引擎显式支持哈希索引。

比如: SELECT A FROM B WHERE name=‘PETER‘;

Mysql会先计算‘PETER‘的哈希值,并使用该值寻找对应的指针记录。因为索引自身只需存储对应的哈希值,所以哈希索引查找速度非常快,但是也有一些限制:

  • 哈希索引只包含哈希值和行指针,不存储字段值,所以不能使用索引中的值来避免读取行
  • 哈希索引不是顺序存储,无法用于排序
  • 哈希索引也不支持索引列匹配查找,例如KEY(A,B),如果查询只有数据列A则无法使用该索引
  • 哈希索引只支持等值比较查询
  • 当出现哈希冲突时,存储引擎必须便利链表中所有的行指针,直到找到匹配的行
  • 哈希冲突很多的话,一些索引维护操作的代价也会很高

因为这些限制,哈希索引使用的场景有限,而一旦适合哈希索引时,则它带来的性能提升将非常高。

当然,对于InnoDB来说也可以创建一个伪哈希列来进行排序查找也是可以的。

下面有个实例,例如需要存储大量URL,如果使用B-Tree来存储URL,存储的内容会很大,因为URL本身很长,正常情况下会有如下查询:

SELECT ID FORM URL WHERE url=‘http://www.baidu.com‘

若删除原来的URL列上的索引,而新增一个被索引的url_crc列,使用CRC32做哈希,就可以使用下面的方式查询:

SELECT ID FROM URL WHERE url=‘http://www.baidu.com‘ AND url_crc=CRC32("http://www.baidu.com");

这样做的性能会比单独在url列上开索引高很多,但缺陷就是需要维护哈希值,可以手动维护,也可以使用触发器实现,例如:

//创建表
CREATE TABLE pseudo hash(
        id int unsigned not null auto_increment,
        url archer(255) not null,
        url_crc int unsigned not null default 0,
        primary key(id)
);
//创建触发器
DELIMITER //
CREATE TRIGGER pseudohash_crc_ins BEFORE INSERT ON pseudohash FOR EACH ROW BEGIN
SET NEW.url_crc=crc32(NEW.url);
END;
//
CREATE TRIGGER pseudohash_crc_upd BEFORE UPDATE ON pseudohash FOR ROW BEGIN
SET NEW.url_crc=crc32(NEW.url);
END;
//
DELIMITER ;

如果数据表非常大,crc32可能也会出现大量的哈希冲突,这个时候也可以使用其他方案代替,比如md5

处理哈希冲突时,必须在WHERE子句中包含常量值:

SELECT ID FROM URL WHERE url_crc=crc32(‘http://www.baidu.com‘) AND url=‘http://www.baidu.com‘;

还有一些其他的索引类型,例如空间数据索引,全文索引,这里暂时不介绍了,大家可以自行搜索。

时间: 2024-12-16 02:03:53

Mysql优化之创建高性能索引(一)的相关文章

MySQL 创建高性能索引

一.索引类型 B-Tree索引: B-Tree通常间意味着以后有的值都是按顺序存储的,并且每一个叶子页到根的距离相同. B-Tree索引 列是顺序组织存储的,所以很适合查找 范围数据. B-Tree索引对如下类型的查询有效: 全值匹配.匹配最左前缀.匹配列前缀.匹配范围值.精确匹配某一列并范围匹配别外一列.只访问索引的查询 B-Tree索引的限制: 如果不是按照索引的最左列开始查找,刚无法使用索引. 不能跳过索引中的列. 如果查询中某个列的范围查询,刚其右边所有列都无法使用索引优化查询. HAS

[MySQL-笔记]创建高性能索引

索引,MySQL中也叫"键",是存储引擎中用于快速找到记录的一种数据结构,具体的工作方式就像书本中的索引一样,但是具体的实现方式会有差别. 一.索引分类 B-Tree索引: 优点: MyISAM中,索引根据数据的物理位置引用被索引的行,InnoDB中根据主键引用被索引的行. B-Tree索引能够加快访问数据的速度,因为存储引擎不再需要进行全表扫描来获取需要的数据,而是从索引的根节点开始进行搜索. B-Tree对索引列是顺序组织存储的,所以很适合查找范围数据. 一般来说,B-Tree可以

mysql优化实战(explain && 索引)

实验环境: 1.sql工具:Navicat 2.sql数据库,使用openstack数据库作为示例 一.mysql索引查询 show index from instances 结果字段解释: Table:数据库表名 Non_unique:索引不能包括重复词,则为0.可以,则为1. Key_name:索引的名称. 索引中的列序列号,从1开始. 列名称 列以什么方式存储在索引中.在MySQL中,有值'A'(升序)或NULL(无分类). 索引中唯一值的数目的估计值.通过运行ANALYZE TABLE或

第五章:创建高性能索引(上)

索引是存储引擎用于快速找到记录的一种数据结构,这也是索引的基本功能.在MySQL中也叫"键key".良好的性能少不了索引.换句话说,索引优化能够将查询性能轻松提高几个数量级. 1. 索引基础 select first_name from actor where actor_id = 5; 运行上面的查询:如果在actor_id列上有索引,MySQL将使用该索引去查找actor_id为5的列,也就是说:MySQL先在索引上按值查找,然后返回包含该值的数据行. 索引可以包含一个或多个列,列

MySQL 创建高性能索引-->空间索引(R—Tree)

全文索引 全文索引是一种特殊类类型索引,它查找的是文本中的关键词,而不是直接比较索引中的值. 全文索引 更类似于搜索引擎做的事情,而不是简单的WHERE条件匹配. 全文搜索和其他几类索引 的匹配方式完全不一样.它有许多需要注意的细节,如停用词,词干,复数.布尔搜索等. 全文索引 适用于MATCH AGAINST操作,而不是普通的WHERE条件操作.

MySQL 优化之 index merge(索引合并)

MySQL5.0之前,一条语句中一个表只能使用一个索引,无法同时使用多个索引.但是从5.1开始,引入了 index merge 优化技术,对同一个表可以使用多个索引.理解了 index merge 技术,我们才知道应该如何在表上建立索引. 相关文档:http://dev.mysql.com/doc/refman/5.6/en/index-merge-optimization.html (注意该文档中说的有几处错误) The Index Merge method is used to retrie

[MySQL优化案例]系列 — 典型性索引引发CPU负载飙升问题

收到一个mysql服务器负载告警,上去一看,load average都飙到280多了,用top一看,CPU跑到了336%,不过IO和内存的负载并不高,根据经验,应该又是一起索引引起的惨案了. 看下processlist以及slow query情况,发现有一个SQL经常出现,执行计划中的扫描记录数看着还可以,单次执行耗时为0.07s,还不算太大.乍一看,可能不是它引发的,但出现频率实在太高,而且执行计划看起来也不够完美: mysql> explain SELECT count(1) FROM a

MySQL 优化之 index_merge (索引合并)

深入理解 index merge 是使用索引进行优化的重要基础之一.理解了 index merge 技术,我们才知道应该如何在表上建立索引. 1. 为什么会有index merge 我们的 where 中可能有多个条件(或者join)涉及到多个字段,它们之间进行 AND 或者 OR,那么此时就有可能会使用到 index merge 技术.index merge 技术如果简单的说,其实就是:对多个索引分别进行条件扫描,然后将它们各自的结果进行合并(intersect/union). MySQL5.

MySQL优化器不使用索引的情况

优化器选择不适用索引的情况 有时候,有乎其并没有选择索引而去查找数据,而是通过扫描聚集索引,也就是直接进行全表的扫描来得到数据.这种情况多发生于范围查找.JOIN链接操作等情况.例如 SELECT * FROM orderdetails WHERE orderid>10000 and orderid<102000; 通过SHOW INDEX FROM orderdetails可以看到 可以看到orderdetails有(orderID,ProductID)的联合主键.此外还有对于列OrderI