索引的价值,在于提高一个海量数据的检索速度。常见索引分为主键索引、唯一索引、普通索引、全文索引
。如果没有索引,查询需要耗费大量时间,如果放在公网中,很可能会导致死机,所以需要创建索引。
alter table emp add index(empno);
MySQL 给用户提供存储服务,而存储的都是数据,数据在磁盘这个外设当中。磁盘是计算机中的一个机械设备,相比于计算机其他电子元件,磁盘效率是比较低的,在加上IO本身的特征,可以知道,如何提交效率,是 MySQL 的一个重要话题。
数据库文件,本质就是保存在磁盘的盘片中,就是我们经常说的扇区。数据库文件很大,也很多,一定需要占据多个扇区。扇区都是默认的512字节,保证一个扇区多大,是由比特位密度决定的。
柱面(磁道): 多盘磁盘,每盘都是双面,大小完全相等。那么同半径的磁道,整体上便构成了一个柱面
每个盘面都有一个磁头,那么磁头和盘面的对应关系便是1对1的所以,我们只需要知道,磁头(Heads)、柱面(Cylinder)(等价于磁道)、扇区(Sector)对应的编号。即可在磁盘上定位所要访问的扇区。这种磁盘数据定位方式叫做 CHS 。不过实际系统软件使用的并不是 CHS (但是硬件是),而是 LBA ,一种线性地址,可以想象成虚拟地址与物理地址。系统将 LBA 地址最后会转化成为 CHS ,交给磁盘去进行数据读取。不过,我们现在不关心转化细节,知道这个东西,让我们逻辑自洽起来即可
随机访问:效率远远慢于连续访问。因为本次IO和上次IO所给出的扇区地址不连续,这样的话磁头在两次IO操作之间需要作比较大的移动动作才能重新开始读写
连续访问:当此IO和上次的扇区地址是连续的,这样磁头就能很快的开始这次IO操作
因此尽管相邻的两次IO操作在同一时刻发出,但如果他们的请求的扇区地址相差很大的话也只能随机访问
为了提高效率,MySQL进行IO的基本单位是16kb。这个基本数据单元,在mysql中叫做page
CURD
操作,本质就是操作文件内容,都需要通过计算,找到对应的插入位置,或者找到对应要修改或者查询的数据MySQL
服务器在内存中运行的时候,在服务器内部,就申请了Buffer Pool
的大内存空间,来进行各种缓存,就是很大的内存空间来和磁盘数据进行IO交互create table if not exists user (
id int primary key, // 一定要添加主键,只有这样才会默认生成主键索引
age int not null,
name varchar(16) not null
);
// 插入多条记录,注意,我们并没有按照主键的大小顺序插入
mysql> insert into user (id, age, name) values(3, 18, '杨过');
Query OK, 1 row affected (0.01 sec)
mysql> insert into user (id, age, name) values(4, 16, '小龙女');
Query OK, 1 row affected (0.00 sec)
mysql> insert into user (id, age, name) values(2, 26, '黄蓉');
Query OK, 1 row affected (0.01 sec)
mysql> insert into user (id, age, name) values(5, 36, '郭靖');
Query OK, 1 row affected (0.00 sec)
mysql> insert into user (id, age, name) values(1, 56, '欧阳锋');
Query OK, 1 row affected (0.00 sec)
如上面5条记录,如果MySQL要查找id=2的记录,第一次加载id=1,第二次加载id=2,一次一条记录,那么就需要两次IO,如果要找id=5,就需要5次IO。但是,如果这5条都被保存在一个page中,那么第一次IO查找id=2时,整个page会被加载到mysql的buffer pool中,完成了一次IO,后续再查找时,就不需要进行IO,而是直接在内存中进行了。但是怎么保证用户要查找的数据一定在这个page里面?无法保证,但是有很大的概率。IO的效率低下,最主要的不是IO单次数据量的大小,而是IO的次数。
MySQL 中要管理很多数据表文件,而要管理好这些文件,就需要 先描述,在组织
,我们目前可以简单理解成一个个独立文件是有一个或者多个Page构成的
不同的page,在mysql中,都是16kb,使用prev和next构成双向链表。因为有主键的问题,mysql会默认按照主键给我们的数据进行排序,从上面的page内数据记录可以看到数据是有序且彼此关联的。
为什么数据库在插入数据时要对其进行排序呢?我们按正常的顺序插入数据不是也挺好的吗?
插入数据时排序的目的就是优化查询的效率。页内部存放数据的模块,实质上是一个链表结构,链表的特点就是增删快,查询修改慢,所以优化查询的效率是必须的。正因为有序,在查找的时候,从头到后都是有效查找,没有任何一个查找是浪费的。
上面页模式中,只有一个功能,就是在查询某条数据的时候直接将一整页的数据加载到内存中,以减少硬盘IO次数,从而提高性能。但是,我们也可以看到,现在的页模式内部,实际上是采用了链表的结构,前一条数据指向后一条数据,本质上还是通过数据的逐条比较来取出特定的数据。
如果有1千万条数据,一定需要多个Page来保存1千万条数据,多个Page彼此使用双链表链接起来,而且每个Page内部的数据也是基于链表的。那么,查找特定一条记录,也一定是线性查找。这效率也太低了。
目录,就是一种以空间换时间的做法
在一个page内部,我们引入了目录,就能够直接通过目录定位新的起始位置,提高了效率。所以需要通过键值自动排序
多页的时候需要进行管理,就可以给page也带上目录。
键值+指针
MyISAM
存储引擎-主键索引
MyISAM
引擎同样使用B+树作为索引结果,叶节点的data域存放的是数据记录的地址。下图为MyISAM
表的主索引,col1为主键
最大特点是将索引page和数据page分离,也就是叶子节点没有数据,只有对应的数据的地址,叫做非聚簇索引,而innode
索引,是将索引和数据放在一起的,叫做聚簇索引。
MySQL除了默认会建立主键索引外,我们用户也有可能建立按照其他列信息建立的索引,一般这种索引叫做普通索引。
对于 MyISAM ,建立辅助(普通)索引和主键索引没有差别,无非就是主键不能重复,而非主键可重复
InnoDB 除了主键索引,用户也会建立辅助(普通)索引,我们以上表中的 Col3 建立对应的辅助索引如下图
InnoDB 的非主键索引中叶子节点并没有数据,而只有对应记录的key值
所以,通过普通索引,找到目标记录,需要两遍索引:首先检索索引获得主键,然后哟个主键到主索引中检索获得记录。这种过程叫做回表查询。
为何 InnoDB 针对这种辅助(普通)索引的场景,不给叶子节点也附上数据呢?原因就是太浪费空间了。
// 方式一:在创建表的时候,直接在字段名后指定primary key
create teble user1(id int primary key, name varchar(30));
// 方式二:在创建表的最后,指定某列或某几列为主键索引
vreate table user2(id int, name varchar(30),primary key(id));
// 方式三:创建表后再添加主键
create table uese3(id int,name varchar(30));
alter table user3 add primary key(id);
主键索引的特点:
// 方式一:在表定义时,在某列后直接指定unique唯一属性
create table uese4(id int primary key,name varchar(30) unique);
// 方式二:创建表时,在表的后面指定某列或某几列为unique
create table user5(id int primary key,name varchar(30),unique(name));
// 方式三: 创建后再添加
create table user6(id int primary key,name varchar(30));
alter table user6 add unique(name);
唯一索引的特点:
// 方式一:在表的定义最后,指定某列为索引
create teble user8(id int primary key,name varchar(20),email varchar(30),index(name));
// 方式二:创建完表以后指定某列为普通索引
create table user9(id int primary key, name varchar(20), email varchar(30));
alter table user9 add index(name);
// 方式三:创建一个索引名为idx_name的索引
create table user10(id int primary key, name varchar(20), email varchar(30));
create index idx_name on user10(name);
普通索引的特点:
当对文章字段或有大量文字的字段进行检索时,会使用到全文索引。MySQL提供全文索引机制,但是有要求,要求表的存储引擎必须是MyISAM,而且默认的全文索引支持英文,不支持中文。如果对中文进行全文检索,可以使用sphinx的中文版(coreseek)
create table articles (
id int unsigned auto_increment not null primary key,
title varchar(200),
body text,
fulltext (title,body)
)engine=MyISAM;
insert into articles (title,body) values
('MySQL Tutorial','DBMS stands for DataBase ...'),
('How To Use MySQL Well','After you went through a ...'),
('Optimizing MySQL','In this tutorial we will show ...'),
('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
('MySQL vs. YourSQL','In the following database comparison ...'),
('MySQL Security','When configured properly, MySQL ...');
查询database数据
如果使用如下方式,虽然查询出数据,但是没有用到全文索引
查看是否使用到索引
使用全文索引
select * from articles where match (title,body) against ('database');
show keys from 表名;
show index from 表名;
desc 表名;
alter table 表名 drop primary key;
alter table 表名 drop index 索引名;
索引名就是show keys from 表名
中的 Key_name 字段alter table user10 drop index idx_name;
drop index 索引名 on 表名
drop index name on user8