Mysql学习笔记(九)索引查询优化

原文:Mysql学习笔记(九)索引查询优化

PS:上网再次看了一下数据库关于索引的一些细节...感觉自己学的东西有点少...又再次的啃了啃索引....

学习内容:

索引查询优化...

上一章说道的索引还不是特别的详细,再补充一些具体的细节...

1.B-Tree索引...

B-tree结构被称为平衡多路查找树...其数据结构为:

 

  这就是其数据结构图。。。我们没必要完全的理解其中的原理。。并且我也不会做过多的原理介绍。。。我们只需要知道数据库是以这种方式进行存储数据的就可以了...

 

mysql> create table title
    -> (
    ->    id int not null,
    ->    title varchar(255) not null,
    ->    from_date date not null,
    ->    key(id),
    ->    key(title),
    ->    key(from_date)
    -> );
//建立一个表格。。。有三个主键..。有主键必然要使用到索引...
介绍一下查询方式...
1.全列匹配...
mysql>expla select * from title where id=1000 and title='gogoing' and from_date='1992-01-01';
+----+-------------+--------+-------+---------------+---------+---------+-------------------+------+-------+
| id | select_type | table  | type  | possible_keys | key     | key_len | ref               | rows | Extra |
+----+-------------+--------+-------+---------------+---------+---------+-------------------+------+-------+
|  1 | SIMPLE      | titles | const | PRIMARY       | PRIMARY | 59      | const,const,const |    1 |       |
+----+-------------+--------+-------+---------------+---------+---------+-------------------+------+-------+
2.最左前缀索引...
explain select * from title where id=1001;
+----+-------------+--------+------+---------------+---------+---------+-------+------+-------+
| id | select_type | table  | type | possible_keys | key     | key_len | ref   | rows | Extra |
+----+-------------+--------+------+---------------+---------+---------+-------+------+-------+
|  1 | SIMPLE      | titles | ref  | PRIMARY       | PRIMARY | 4       | const |    1 |       |
+----+-------------+--------+------+---------------+---------+---------+-------+------+-------+
最左前缀原则是当索引用到多个列的时候,只有组成最左前缀的部分才能被使用到..上面只用到了第一列...
3.匹配的索引列使用了精确匹配。。。但是中间有部分列没有被给出...
explain select * from title where id=1002 and from_date='1998-01-01';
+----+-------------+--------+------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table  | type | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+--------+------+---------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | titles | ref  | PRIMARY       | PRIMARY | 4       | const |    1 | Using where |
+----+-------------+--------+------+---------------+---------+---------+-------+------+-------------+
这样只会走第一个索引id,而from_date将不走索引。。由于没有给出title的值,所以无法构成最左前缀原则,因此from_date成为不走索引...
我们可以使用两种方式解决这个问题....使用IN将title的所有值都包括在其中...
EXPLAIN SELECT * FROM employees.titles
WHERE emp_no='1005'
AND title IN ('title1的值','title2的值'......)
AND from_date='1986-06-26';
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table  | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | titles | range | PRIMARY       | PRIMARY | 59      | NULL |    7 | Using where |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
这样就不会出现不走索引的情况了...但是如果title的值过多,那么in这种方式就不能使用..因此解决这个问题的另一种方式就是建立辅助索引....
4.查询的时候没有指定索引的第一列...
explain select * from title where from_date='1995-01-26';//这个结果很明显,就是不走索引...
5.匹配某列前缀的字符串..
explain select * from title where id=1008 and title like 'S%';
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table  | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | titles | range | PRIMARY       | PRIMARY | 56      | NULL |    1 | Using where |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
6.使用范围查询...
explain select * from title where id>1010;范围列可以使用索引,但是必须是最左前缀..并且如果同一个查询语句使用了两个范围索引,那么后面的范围将成为不走索引..
explain select * from title where id>1010 and title='gogoing' and from_date between '1990-01-01' and '1998-01-01';
还有一种情况就是如下面代码..
explain select * from where id between 1000 and 1010 and title='gogoing' and from_date between '1998-01-01' and '2010-01-01';
上面这种情况就变成了第一个就成为了多值匹配,而后面那个范围成为了范围匹配...同样都是两个范围匹配,和上面的情况就不同了..这个我至今没弄明白..云里雾里的...如果有大牛会的话请告诉我。。。
7.带有表达式的查询方式...
如果查询语句中含有表达式,那么将成为不走索引。。。(除一些特殊方式)。。。
EXPLAIN SELECT * FROM employees.titles WHERE emp_no - 1='10000';
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table  | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | titles | ALL  | NULL          | NULL | NULL    | NULL | 443308 | Using where |
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
不走索引...

 

2.Hash索引..

MySQL中,只有Memory存储引擎显示支持hash索引,是Memory表的默认索引类型,尽管Memory表也可以使用B-Tree索引。 Memory存储引擎支持非唯一hash索引,这在数据库领域是罕见的,如果多个值有相同的hash code,索引把它们的行指针用链表保存到同一个hash表项中。。

hash索引就是讲我们存储的数据按照一定的哈希函数来进行保存在一个指针数据中,当我们需要查找的时候,调用hash函数,找到我们需要的数据的指针,通过这个指针,我们就可以访问其中的数据信息了..hash的指针数据是有序的,但对应的数据信息是无序的...

Hash索引有以下一些限制:
(1)由于索引仅包含hash code和记录指针,所以,MySQL不能通过使用索引避免读取记录。但是访问内存中的记录是非常迅速的,不会对性造成太大的影响。
(2)不能使用hash索引排序。
(3)Hash索引不支持键的部分匹配,因为是通过整个索引值来计算hash值的。
(4)Hash索引只支持等值比较,例如使用=,IN( )和<=>。对于WHERE price>100并不能加速查询。

3.索引的使用范围...

那么我们到底什么情况下使用索引呢?有两种判断的方式...

i.看了别人的博客说。。一般当我们存储的数据不超过2000条的时候,我们是没有必要使用索引的...

ii.索引的选择性。。。

索引的选择性=表中列的唯一键的数量/表的行数...这个数值越接近于1越好...就比如说主键,毋庸置疑绝对是1..所以有了主键我们必须要使用索引..

上面说到了辅助索引...

4.那么什么是辅助索引呢?简单的介绍一下....

不同的存储引擎对应的辅助索引的结构图也是不同的。。。其实辅助索引和主索引并没有过大的区别,只是主索引要求key值唯一。。辅助索引的key值可以重复....并且二者构成的存储结构也基本相同,都是一棵b+tree。。。每一个数据记录都保存在一个地址当中,这个地址的获取由地址节点的父节点来存储...一层扣一层。。。就形成了树状结构...

5.聚簇索引..

  Innobe存储引擎支持聚簇索引,这种索引方式也是以b+tree为存储结构,但是他和myisam存储引擎完全不同,因为myisam不支持聚簇索引,支持非聚簇索引...

Innobe的数据文件本身就是索引文件..这个b+tree的data数据域完全保存着数据记录,并且也保存着索引的key值,那么当我们找到了key值的时候,我们就可以直接访问数据文件。。。因为数据文件的本身就是主索引...

而myisam存储引擎的数据文件和索引文件是完全分离的,b+tree的data数据域保存着记录数据文件的地址,当我们要通过索引key的值查找数据的时候,我们需要经过找到这个key对应的data数据域的指针值,然后我们通过指针的值去访问我们想要的数据信息...

聚簇索引和非聚簇索引的区别图...Primary key表示主索引...Secondary key表示辅助索引...

 

6.覆盖索引

简单的介绍一下覆盖索引的有点。。。自己学的也不是特别的透彻,只是做简单的介绍...

如果索引包含满足查询的所有数据,就称为覆盖索引。覆盖索引是一种非常强大的工具,能大大提高查询性能。只需要读取索引而不用读取数据有以下一些优点:
(1)索引项通常比记录要小,所以MySQL访问更少的数据;
(2)索引都按值的大小顺序存储,相对于随机访问记录,需要更少的I/O;
(3)大多数据引擎能更好的缓存索引。比如MyISAM只缓存索引。
(4)覆盖索引对于InnoDB表尤其有用,因为InnoDB使用聚集索引组织数据,如果二级索引中包含查询所需的数据,就不再需要在聚集索引中查找了。
覆盖索引不能是任何索引,只有B-TREE索引存储相应的值。而且不同的存储引擎实现覆盖索引的方式都不同,并不是所有存储引擎都支持覆盖索引(Memory和Falcon就不支持)。

于索引覆盖查询(index-covered query),使用EXPLAIN时,可以在Extra一列中看到“Using
index”。

7.利用索引进行排序...

MySQL中,有两种方式生成有序结果集:一是使用filesort,二是按索引顺序扫描。利用索引进行排序操作是非常快的,而且可以利用同一索引同时进 行查找和排序操作。当索引的顺序与ORDER BY中的列顺序相同且所有的列是同一方向(全部升序或者全部降序)时,可以使用索引来排序。如果查询是连接多个表,仅当ORDER BY中的所有列都是第一个表的列时才会使用索引。其它情况都会使用filesort。

 

create table actor(

actor_id int unsigned NOT NULL AUTO_INCREMENT,

name      varchar(16) NOT NULL DEFAULT '',

password        varchar(16) NOT NULL DEFAULT '',

PRIMARY KEY(actor_id),

 KEY     (name)

) ENGINE=InnoDB

insert into actor(name,password) values('cat01','1234567');

insert into actor(name,password) values('cat02','1234567');

insert into actor(name,password) values('ddddd','1234567');

insert into actor(name,password) values('aaaaa','1234567');

mysql> explain select actor_id from actor order by actor_id;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | actor | index | NULL          | PRIMARY | 4       | NULL |    4 | Using index |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+

mysql> explain select actor_id from actor order by password;
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
|  1 | SIMPLE      | actor | ALL  | NULL          | NULL | NULL    | NULL |    4 | Using filesort |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+

mysql> explain select actor_id from actor order by name;
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | actor | index | NULL          | name | 34      | NULL |    4 | Using index |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+

 

时间: 2024-10-31 00:43:08

Mysql学习笔记(九)索引查询优化的相关文章

Mysql学习笔记(八)索引

原文:Mysql学习笔记(八)索引 PS:把昨天的学习内容补上...发一下昨天学的东西....五月三日...继续学习数据库... 学习内容: 索引.... 索引的优点: 1.通过创建唯一索引,可以保证数据库每行数据的唯一性... 2.使查找的速度明显加快... 3.当使用分组和排序进行查询时,可以缩短时间... 索引的缺点: 1.维护索引需要耗费数据库的资源... 2.索引需要占用磁盘空间... 3.对表进行增删改的时候,由于索引的存在,时间会有所增加... 索引的分类... 普通索引和唯一索引

Mysql学习笔记(十一)临时表+视图

原文:Mysql学习笔记(十一)临时表+视图 学习内容: 临时表和视图的基本操作... 临时表与视图的使用范围... 1.临时表   临时表:临时表,想必大家都知道这个概念的存在...但是我们什么时候应该使用到临时表呢?当一个数据库存在着大量的数据的时候,我们想要获取到这个数据集合的一个子集,那么我们就可以使用临时表来保存我们想要的数据..然后对临时表进行操作就可以了...使用临时表必然是有原因的..使用临时表会加快数据库的查询性能.... create temporary table tmp_

Mysql学习笔记(一)数据类型

原文:Mysql学习笔记(一)数据类型 学习内容: Mysql基本数据类型. 1.数字类型.. i.整型     Mysql数据类型             含义(有符号)     tinyint(m) 一个字节 范围(-128~127)     smallint(m) 两个字节 范围(-32768~32767)     mediumint(m) 三个字节 范围(-8388608~8388607)     int(m) 四个字节 范围(-2147483648~2147483647)     bi

Mysql学习笔记(二)数据类型 补充

原文:Mysql学习笔记(二)数据类型 补充 PS:简单的补充一下数据类型里的String类型以及列类型... 学习内容: 1.String类型 2.列类型存储需求   String类型: i.char与varchar char与varchar的类型相似,但是他们的保存方式和检索方式不同... char的存储结构是固定长度的存储...即指定了几个字节,那么就占用几个字节,如char(4),那么无论存入的是什么字串,那么都占用四个字节...char的 可表示长度范围为0-255的任何值,当保存的字

MySQL学习笔记之数据的增、删、改实现方法_Mysql

本文实例讲述了MySQL学习笔记之数据的增.删.改实现方法.分享给大家供大家参考,具体如下: 一.增加数据 插入代码格式: insert into 表明 [列名-] values (值-) create table test21(name varchar(32)); insert into test21 (name) values ('huangbiao'); 插入原则: 1.插入的数据应与字段的数据类型相同 2.数据的大小应该在列的规定范围内 3.在values中列出的数据位置必须与被加入的列

MySQL学习笔记之数据定义表约束,分页方法总结_Mysql

本文实例讲述了MySQL学习笔记之数据定义表约束,分页方法.分享给大家供大家参考,具体如下: 1. primary key 主键 特点:主键是用于唯一标识一条记录的约束,一张表最多只能有一个主键,不能为空也不能重复 create table user1(id int primary key,name varchar(32)); mysql> insert into user1 values(1,'hb'); Query OK, 1 row affected (0.10 sec) mysql>

MySQL学习笔记之创建、删除、修改表的方法_Mysql

本文实例讲述了MySQL学习笔记之创建.删除.修改表的方法.分享给大家供大家参考,具体如下: 创建表: create table users( id int, name varchar(64), sex bit(1), birthday date, Entry_date date, job varchar(32), salary float, resume text ); 1 添加列: alter table 表名 add 列名 数据类型 alter table users add image

Mysql学习笔记(六)增删改查

原文:Mysql学习笔记(六)增删改查 PS:数据库最基本的操作就是增删改查了... 学习内容: 数据库的增删改查 1.增...其实就是向数据库中插入数据.. 插入语句 insert into table_name values("要插入的数据"); 比如说,我们先创建一个宠物表,用来记录宠物的基本信息以及所有者... create table pet ( name varchar(20), owner varchar(20), species varchar(20), sex cha

Mysql学习笔记(十)存储过程与函数 + 知识点补充(having与where的区别)

原文:Mysql学习笔记(十)存储过程与函数 + 知识点补充(having与where的区别) 学习内容:存储程序与函数...这一章学的我是云里雾里的... 1.存储过程...   Mysql存储过程是从mysql 5.0开始增加的一个新功能.存储过程的优点其实有很多,不过我觉得存储过程最重要的优点就是实现了SQL代码的封装,那么我们为什么需要封装SQL语句呢?原因就是当我们在面对一个庞大的数据库的时候,当我们使用外部程序去访问数据库的时候...我们总不能在外部程序中内嵌很多的SQL语句吧...