MySql学习笔记

 

目录

1、常见的MySql引擎

1.1、什么是MySql引擎?

1.2、存储引擎的作用是什么?

1.3、为什么要合理选择数据库存储引擎?

1.4、InnoDB引擎(Version5.1以后的默认存储引擎)

1.5、MyIsam引擎(Version5.1以前的默认存储引擎)

1.6、InnoDB引擎和MyIsam引擎的对比

2、事务

2.1、什么是MySql事务?

2.2、事务的四大特征ACID

2.3、事务的并发问题

2.4、MySql数据库提供的四种隔离级别

3、MVCC(Multi-Version Concurrency Control)

3.1、什么是MVCC?它能解决什么问题?

3.2、InnoDB中MVCC的具体实现分析

3、索引

3.1、什么是索引?索引有什么用?

3.2、索引的类型

3.2.1、单列索引 之 普通索引

3.2.2、单列索引 之 唯一索引

3.2.3、单列索引 之 主键索引

3.2.4、组合索引

3.2.5、全文索引

3.2.6、聚簇索引和非聚簇索引

3.3、索引的使用原则总结


1、常见的MySql引擎

1.1、什么是MySql引擎?

数据库引擎是用于存储、处理和保护数据的核心服务。利用数据库引擎可控制访问权限并快速处理事务,从而满足企业内大多数需要处理大量数据的应用程序的要求。使用存储引擎创建用于联机事务或联机分析处理数据的关系数据库。这包括创建用于存储数据的表和用于查看、管理和保护数据安全的数据库对象(如索引、视图和存储过程)

1.2、存储引擎的作用是什么?

  1. 设计并创建数据库以保存系统所需的关系或XML文档。
  2. 实现系统以访问和更改数据库中存储的数据。包括实现网站或使用数据的应用程序,还包括生成使用SQL-Server工具和实用工具以使用数据的过程。
  3. 为单位或客户部署实现的系统。
  4. 提供日常管理支持以优化数据库的性能。

1.3、为什么要合理选择数据库存储引擎?

MySql中的数据用各种不同的技术存储在文件(或者内存)中,这些技术中的每一种技术都使用不同的存储机制、索引技巧、锁定水平并且最终提供广泛的不同的功能和能力。通过选择不同的技术(存储引擎),你能够获得额外的速度或者功能,从而改善你的应用的整体功能。

这些不同的技术以及配套的相关功能在MySQL中被称作存储引擎(也称作表类型)。MySQL默认配置了许多不同的存储引擎,可以预先设置或者在MySQL服务器中启用。你可以选择适用于服务器、数据库和表格的存储引擎,以便在选择如何存储你的信息、如何检索这些信息以及你需要你的数据结合什么性能和功能的时候为你提供最大的灵活性

下图是我的mysql引擎配置情况:

1.4、InnoDB引擎(Version5.1以后的默认存储引擎)

InnoDB是一个事务型的存储引擎,它给MySql提供了具有提交、回滚、崩溃恢复能力的事务安全(ACID兼容)存储引擎,有行级锁定和外键约束。

InnoDB是为处理巨大数据量时的最大性能设计,它的CPU效率可能是其他基于磁盘关系数据库引擎所不能匹敌的。

InnoDB引擎提供了对数据库ACID事务的支持,并且实现了SQL标准的四种隔离级别。该引擎还提供行级锁和外键约束,它的设计目的是处理大容量数据库系统,它本身其实就是基于MySql后台的完整数据库系统。MySql运行时Innodb会在内存中建立缓冲池,用于缓冲数据和索引。当需要使用数据库事务时,该引擎是首选

适用场景

  1. 经常更新的表,适合处理多重并发的更新请求(因为InnoDB有并发版本控制功能)。
  2. 需要支持数据库事务时。
  3. 需要外键约束时。
  4. 支持自动增加列属性auto_increment。
  5. 数据库崩溃后快速恢复。相对而言,MyIsam崩溃后发生损坏的几率要大于InnoDB,且恢复速度也比InnoDB慢。
  6. insert和update操作比较多时,InnoDB更合适。

1.5、MyIsam引擎(Version5.1以前的默认存储引擎)

MyIsam是MySql V5.1之前的默认存储引擎,在此版本之后默认引擎改为了InnoDB。

MyIsam没有提供对数据库事务的支持,也不支持行级锁和外键约束,因此当INSERT(插入)或UPDATE(更新)数据时即写操作需要锁定整个表,效率会更低一些

MyIsam引擎独立于操作系统,也就是可以在Windows上使用,也可以比较简单的将数据转移到Linux操作系统上去。MyIsam引擎在创建表的时候,会创建三个文件,

  1. 一个是.frm文件用于存储表的定义;

  2. 一个是.MYD文件用于存储表的数据;

  3. 另一个是.MYI文件用于存储索引。

操作系统操作大文件的速度是比较慢的,这样将表分为3个文件,那么.MYD这个文件单独来存放数据自然可以优化数据库的查询等操作。有索引管理和字段管理。MyIsam还是用一种表格锁定的机制,用来优化并发的读写操作,其代价是你需要经常运行OPTIMIZE TABLE命令来恢复被更新机制锁浪费的空间。

适用场景

  1. 不支持事务的设计,但是不代表有着事务操作的项目就不能用Mylsam引擎,可以在service层根据自己业务需求进行相应的控制。
  2. 不支持外键的表设计。
  3. 查询速度快,如果大量执行select操作,MyIsam是更好的选择。
  4. 如果读操作的需求远远超过写操作,并且不需要数据库事务的支持,那么MyIsam引擎是比较好的选择

1.6、InnoDB引擎和MyIsam引擎的对比

存储引擎MyIsamInnodb
事务不支持事务处理等高级处理支持
外键不支持外键支持
锁的粒度锁的粒度是表级锁的粒度是行级
全文类型索引支持mysql5.6以后支持

 

MyIsam相对简单,所以在效率上要优于InnoDB,小型应用可以考虑使用MyIsam。

当你的数据库有大量的写入、更新操作,而查询比较少或者数据完整性要求比较高的时候就选择InnoDB。

当你的数据库以查询为主,而更新和写入操作较少,并且业务方面完整性要求不是那么严格,就选择使用MyIsam。

1.7、乐观锁的实现示例

锁的粒度主要有以下几种:

  • 行锁:粒度最小,并发性最高。
  • 页锁:一次锁定一页。25个行锁可以升级为一个页锁。
  • 表锁:粒度大,并发性低。
  • 数据库锁:控制整个数据库操作。

乐观锁、悲观锁:

乐观锁:相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所在在数据进行提交更新时,才会正式对数据的冲突与否进行检测,如果发生了冲突,则返回用户错误信息,让用户决定如何去改,一般乐观锁的实现方式就是记录数据版本。

举个例子:客户端A和客户端B正在同一个系统中借阅同一本书《老人与海》,但是这本书只有最后一本了,所以势必有一个人会借书失败(如果不进行处理的话,并发情况下可能两人都会借书成功,这于系统业务逻辑不符),当前此条数据行的状态如下:

bookidbooknameamount
00011老人与海1

 

那么怎么保证系统能正确处理这个情况呢?下面使用乐观锁来解决这个问题,在表中再加一列属性version,用于表示该行数据的版本号,假设当前version为1,每更新一次数据,version+1:

bookidbooknameamountversion
00011老人与海11

 

既然要借《老人与海》这本书,那么一开始A和B肯定都要查询bookname='老人与海'的这本书目前情况:

select amount,version from booktable where bookname='老人与海';

查询过后,A和B都知道《老人与海》这本书目前amount=1,version=1。我们假设A先对数据行进行更新:

update booktable set amount=amount-1,version=version+1 where bookname='老人与海' and version=1;

从上面的SQL语句可知,更新后amount=0,version=2,表示最后一本《老人与海》已经借出且数据版本号更新为2。这时B也对数据行进行update操作,更新语句与A相同,那么B能更新成功吗?答案很明显是不能,因为这时version已经不等于1,而是等于2了,所以B更新操作失败,操作请求被驳回,系统会抛出异常,并告知B这本书已经被借完了。

悲观锁:顾名思义,就是很悲观,每次取拿数据的时候都认为别人会修改,所以每次拿数据时都要上锁,这样别人来拿数据时就会block(受阻)知道它拿掉锁。传统的关系型数据库中就有很多这种锁机制,比如行锁、表锁、读锁、写锁等,都是在操作之前先上锁。

2、事务

2.1、什么是MySql事务?

MySql事务主要用于处理操作量大,复杂度高的数据。比如说,在学生管理系统中,你要删除一名学生,你既需要删除这个学生的基本资料,也要删除和该学生有关的的信息,比如成绩、文章等,这些数据库操作语句就构成一个事务。

事务主要是用来维持数据库的完整性,一个事务中的一批数据库操作语句要么都执行,要么全都不执行!且事务是用来管理update、insert、delete语句的。

2.2、事务的四大特征ACID

  • 事务的原子性(Atomicity):指一个事务要么全部执行,要么全部不执行。
  • 事务的一致性(Consistency):指事务的运行并不能改变数据库中数据的一致性。例如,A向B转账,A的钱扣了,而B却没有收到,这是不允许发生的。
  • 事务的独立性(Isolation):事务的独立性也称为隔离性,一个事务的执行不能干扰其他事务,即一个事务内部的操作和使用的数据对于其他并发事务来说是隔离的,并发执行的各个事务之间不能相互干扰。例如:A正在一张银行卡中取钱,在A取钱没有完成时,B不可能向A的这张卡转账成功。
  • 事务的持久性(Durability):事务的持久性是指事务执行成功之后,该事务对数据库所做的更改是持久保存在数据库中的,不会无缘无故的回滚到之前的状态。

2.3、事务的并发问题

  • 脏读:指在一个事务处理过程中读取了另一个未提交的事务中的数据。比如说事务A读取了事务B更新的数据,然后B回滚操作,那么A读到的就是脏数据。
  • 不可重复读:指在一个事务处理过程中读取了另一个已经提交的事务中的数据。不可重复读的重点在于update和delete。事务A多次读取同一数据X,事务B在A读取的过程中对数据X进行了更新并提交,导致A多次读取同一数据时,结果不一致。
  • 幻读:指在一个事务处理过程中读取了另一个已经提交的事务中的数据。幻读的重点在于insert。管理员A将数据库中所有学生成绩从具体分数改成了ABCD四个等级,但是这时候另一个管理员B突然在其中插入了一条具体的分数,当管理员A全部改完以后,突然发生还有一条数据是具体分数而非等级,就好像发生了幻觉一样。

解决不可重复读的问题只需锁住满足条件的行,而解决幻读则需要锁表(InnoDB引擎在快照读的模式下通过MVCC来解决幻读的问题,在当前读的模式下通过next-key来解决幻读问题)。

2.4、MySql数据库提供的四种隔离级别

事务隔离级别出现脏读可能性出现不可重复读可能性出现幻读可能性
读未提交(read-uncommitted)
不可重复读(read-committed)X

可重复读(repeatable-read)

(MySql默认事务隔离级别)

XX
串行化(Serializable)XXX

可能有人会问:既然串行化能解决所有的问题,那么为什么不把数据库的事务隔离级别都提升到Serializable呢?安全是一定会付出性能代价的,串行化顾名思义,所有操作任务排队等候处理,每一个操作任务在处理过程中都会加锁,它不释放锁的话,那后面的任务就只能乖乖的等,这样会导致大量的超时问题,会大大降低操作处理效率,浪费资源。

注:安全级别由上往下逐渐升高。√代表会发生,X代表不会发生。


在RR安全级别下,如何解决幻读问题应该要在“快照读”和“当前读”两种情况下分开讨论,快照读模式下可以通过MVCC来解决,但是当前读模式下,要通过next-key来解决。


3、MVCC(Multi-Version Concurrency Control)

3.1、什么是MVCC?它能解决什么问题?

MVCC是一种多版本并发控制机制。大多数的MySql事务型存储引擎,如InnoDB、Falcon等都不只是简单地使用行锁机制,它们都和MVCC-多版本并发控制机制一起使用。并且大家都知道可以通过锁来控制并发操作,但是对于系统来说开销较大,而MVCC在大部分情况下可以代替行级锁,使用MVCC可以有效降低系统开销。并且MVCC可以解决可重复读级别下的幻读问题。

3.2、InnoDB中MVCC的具体实现分析

下面通过InnoDB来简单分析MVCC是如何进行并发控制的:

InnoDB的MVCC是通过在每行记录后面保存两个隐藏的列来实现的这两个列,分别保存了这个行的创建时间和这个行的删除时间。这个时间并不是实际的时间值,而是系统的版本号(可以理解为事务的ID),每开始一个新的事务,系统版本号就自增,事务开始时刻的系统版本号会作为事务的ID。下面的例子是在Repeatable read隔离级别下,MVCC的具体实现过程。

创建一张test表,主键id自增,另有一个属性字段name:

插入数据,InnoDB为新插入的每一行保存当前系统版本号作为版本号,

第一个事务,ID为1

//开启事务
start transaction;
insert into test values(NULL,'zhangsan');
insert into test values(NULL,'lisi');
insert into test values(NULL,'wangwu');
commit;

对应的数据如下表所示(我没有使用Mysql中查出来的表,因为后面两列是看不到的):

idname创建时间(事务ID)删除时间(事务ID)
1zhangsan1undefined
2lisi1undefined
3wangwu1undefined

SELECT

InnoDB会根据以下两个条件检查每行记录,只有同时满足这两个条件的记录,才能返回作为查询结果:

  • InnoDB只会查找版本早于当前事务版本的数据行(也就是行的系统版本号要小于或等于当前执行事务的系统版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的。
  • 行的删除版本号要么未定义,要么大于当前事务的版本号,这可以确保事务读取到的行,在事务开始之前未被删除。

DELETE

InnoDB会为删除的每一行保存当前系统版本号(事务的ID)作为删除标识。

从下面的例子来分析:

第二个事务,ID为2:

start transaction;
select * from test;   //(1)
select * from test;   //(2)
commit;

假设1

假设在执行这个事务ID为2的过程中,刚执行到(1),这时,有另一个事务ID为3往这个表里插入了一条数据;

第三个事务,ID为3:

start transaction;
insert into test values(NULL,'zhaoliu');
commit;

这时表中数据如下:

idname创建时间(事务ID)删除时间(事务ID)
1zhangsan1undefined
2lisi1undefined
3wangwu1undefined
4zhaoliu3undefined

然后执行事务2中的(2),即select * from test;由于id=4的数据的创建时间(事务ID为3),执行当前事务的ID为2,而InnoDB只会查找事务ID小于或等于当前事务ID的数据行,所以id=4的数据行并不会在执行事务2的(2)中被检索出来,在事务2的(2)中检索出来的数据行只会如下表所示:

idname创建时间(事务ID)删除时间(事务ID)
1zhangsan1undefined
2lisi1undefined
3wangwu1undefined

假设2

假设在执行事务ID为2的过程中,刚执行到(1),假设执行完事务3以后,接着又执行了事务4。

第四个事务,ID为4:

start transaction;
delete from test where id=1;
commit;

此时test表中数据如下:

idname创建时间(事务ID)删除时间(事务ID)
1zhangsan14
2lisi1undefined
3wangwu1undefined
4zhaoliu3undefined

 

接着执行事务ID为2的事务(2),根据SELECT检索条件可以知道,它会检索创建时间(创建事务ID)小于或等于当前事务ID的数据行和删除时间(删除事务ID)大于当前事务的行,而id=4的行上面已经说过了,而id=1的行由于删除时间(删除事务ID)大于当前事务的ID,所以事务2的(2)select * from test也会把id=1的数据检索出来。所以事务2中的两条select语句检索出来的数据如下所示:

idname创建时间(事务ID)删除时间(事务ID)
1zhangsan14
2lisi1undefined
3wangwu1undefined

UPDATE

InnoDB执行UPDATE,实际上是新插入了一行记录,并保存其创建时间为当前事务的ID,同时保存当前事务的ID到要UPDATE的行的删除时间。

假设3

假设在执行完事务2的(1)后,其他用户又执行了事务3和事务4,这时,又有一个用户对这张表执行了UPDATE操作:

第五个事务,ID为5:

start transaction;
update test set name='lisi' where id=2;
commit;

根据UPDATE的更新原则:会生成新的一行,并在原来要修改的列的删除时间列上添加本事务ID,如下表所示:

idname创建时间(事务ID)删除时间(事务ID)
1zhangsan14
2lisi15
3wangwu1undefined
4zhaoliu3undefined
2lisi5undefined

继续执行事务2的(2),根据select检索条件,得到下表:

idname创建时间(事务ID)删除时间(事务ID)
1zhangsan14
2lisi15
3wangwu1undefined

得到的结果还是和事务2中(1)检索出的结果相同。

示例参考自轻松理解MYSQL MVCC 实现机制

3、索引

3.1、什么是索引?索引有什么用?

每一本书都有索引,即目录,我们看书时,想要快速的找到特定的内容就要去翻阅书的索引,找到对应的页码。在MySql中,存储引擎用类似的方法使用索引,其先在索引中找到对应值,然后根据匹配的索引记录找到对应的数据行。

索引大大的减少了需要扫描的数据量。


不管数据表有无索引,首先在SGA的数据缓冲区中查找所需数据,如果数据缓冲区中没有所需数据,服务器进程才去读磁盘。

  • 无索引,首先去读表数据存放的磁盘块,读到数据缓冲区内再去查找数据。
  • 有索引,先读入索引表,通过索引表直接找到所需数据的物理地址,并把数据读入数据缓冲区。

例如,我们现在创建一张如下所示的表,然后我们把10000个不同的名字插入到student表中:

create table student(
    id int primary key auto_increment,
    name varchar(20) not null);

如果我们创建了name列的索引,MySql将在索引中排序name列:对于索引中的每一项,MySql都在内部为它保存一个数据文件中实际记录所在位置的“指针”。因此,如果我们要查找name='张三'的学生id,SQL命令为:

select id from student where name='张三';

MySql能够在name索引中查找'张三'值,然后直接转到数据文件中相应的行,准确的返回该行的id(888)。在这个查找过程中,MySql只需处理一个行就可以返回结果。如果没有name列索引,MySql要扫描数据文件中所有的行,即10000条记录!显然,MySql扫描的行越少,它完成任务的速度就越快。

3.2、索引的类型

下文中使用的案例表如下所示:

CREATE TABLE `award` (
   `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户id',
   `aty_id` varchar(100) NOT NULL DEFAULT '' COMMENT '活动场景id',
   `nickname` varchar(12) NOT NULL DEFAULT '' COMMENT '用户昵称',
   `is_awarded` tinyint(1) NOT NULL DEFAULT 0 COMMENT '用户是否领奖',
   `award_time` int(11) NOT NULL DEFAULT 0 COMMENT '领奖时间',
   `account` varchar(12) NOT NULL DEFAULT '' COMMENT '帐号',
   `password` char(32) NOT NULL DEFAULT '' COMMENT '密码',
   `message` varchar(255) NOT NULL DEFAULT '' COMMENT '获奖信息',
   `created_time` int(11) NOT NULL DEFAULT 0 COMMENT '创建时间',
   `updated_time` int(11) NOT NULL DEFAULT 0 COMMENT '更新时间',
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='获奖信息表';

3.2.1、单列索引 之 普通索引

普通索引是最基本的索引,其Sql命令格式如下:

create index indexname on `tablename`(`字段名`(length));
//或者
alter table tablename add index indexname('字段名'(length));

下面以account字段为例,以两种方式建立索引:

create index account_Index on `award`(`account`);
alter table award add index account_Index('account');

如果是char、varchar类型的字段,索引长度length可以小于字段的实际长度,如果是blob和text类型就必须指定长度。

3.2.2、单列索引 之 唯一索引

唯一索引与普通索引类似,但是不同的是唯一索引要求这一列所有的值都是唯一的,这一点和主键索引一样,但是唯一索引允许有空值。其Sql命令格式如下:

create unique index indexname on `tablename`(`字段名`(length));
//或者
alter table tablename add unique(column_list);

仍然以account字段为例,构建唯一索引:

create unique index account_Index on `award`(`account`);

3.2.3、单列索引 之 主键索引

主键索引不允许有空值(在B+树的InnoDB引擎中,主键索引起到了至关重要的作用)。主键索引建立的规则是int优先于varchar,一般在建表的时候创建,最好是与表的其他字段不相关的列或是业务不相关的列,一般都会设为int,而且是auto_increment自增类型的字段。

以`award`表中的主键id为例,建立主键索引:

alter table award add primary_key(id);

3.2.4、组合索引

一个表中含有多个单列索引不代表是组合索引,通俗一点来说,组合索引是包含多个字段但是只有一个索引名称

其Sql命令格式如下:

create index indexname on `tablename`(`字段名`(length),`字段名`(length),...);

创建一个包含account、nickname、created_time三个字段的组合索引:

create index account_nickname_created_time_Index on `award`(`account`,`nickname`,`created_time`);

组合索引的最左前缀

以上面这个组合索引  account_nickname_created_time为例,当搜索条件是下面的这些组合时,MySql将使用这个组合索引来进行查询:

account,nickname,created_time
account,nickname
account

即如果在(a,b,c)三个字段上建立组合索引的话,那么它能够加快a|(a,b)|(a,b,c)三组的查询速度。

从另一方面来理解,这个组合索引其实相当于为我们创建了(account,nickname,created_time)、(account,nickname)、(account)这三种索引,以下的查询语句都会使用到这个组合索引:

select id from award where account='10001' and nickname='Mike' and created_time='20180110';

select id from award where account='10002' and nickname='tina';

select id from award where account='10003';

下面这些查询语句则不能使用这个组合索引加快查询速度:

select id from award where nickname='lili' and created_time='20180921';

select id from award where nickname='tony';

select id from award where created_time='20170817';

3.2.5、全文索引

全文索引是一种特殊类型的索引,它查找的是文章中的关键词,而不是直接比较索引中的值。全文索引更加类似于搜索引擎做的事情,而不是简单的where条件匹配。

老版本的MySql只有MyIsam引擎支持全文索引,但是自version5.6开始,InnoDB引擎也开始支持全文索引。默认MySql不支持中文全文索引,可以通过扩展MySql,添加中文全文检索或为中文内容表提供一个对应的英文索引表的方式支持中文。

其Sql命令如下:

alter table tablename add fulltext(column1,column2);

利用nickname和message两个字段建立全文索引:

alter table award add fulltext_award(nickname,message);

创建全文索引后我们怎么使用呢?众所周知,我们可以使用like关键字来查询,例如:

select * from award where message like '%查询字符串%';

有了全文索引后,我们应该这样查询:

select * from award where match(nickname,message) against('查询字符串');

注意:

  • 如果可能的话,请尽量先创建表并插入所有数据后再创建全文索引,而不要在创建表的时候就创建全文索引,因为前者比后者的检索效率更高。
  • 使用MySql自带的全文索引时,如果查询字符串长度过短将无法得到预期结果,MySql默认的全文索引能查找到的词最小长度为4个字符。

3.2.6、聚簇索引和非聚簇索引

前面的五种索引是从逻辑结构的角度上来区分的,而聚簇索引和非聚簇索引则是从物理存储角度上来区分的。

聚簇索引

聚簇索引决定数据在磁盘上的物理排序,实际存储的顺序结构与数据存储的物理结构是一致的,所以通常来说物理顺序结构只有一种,那么一个表的聚簇索引也只能有一个。通常默认是主键,设置了主键,系统默认就为你加上了聚簇索引(当然也可以不拿主键做聚簇索引,这就需要你在设置主键之前先自己手动添加上唯一的聚簇索引,再设置主键)。

总而言之,聚簇索引是顺序结构与数据存储的物理结构一致的一种索引,并且一个表只能有唯一的一条。

举个例子形容一下聚簇索引:学校图书馆藏书一般都是很有规律的,一般一个区只放同一类型的书,比如A区放医学书籍,B区放计算机类图书,D区放文学书籍。现在你去学校的图书馆找《老人与海》这本书,你并不知道这本书具体的藏书位置,所以你得先去图书馆电脑上查一下这本书在哪吧,电脑告诉你这本书在D区5柜3排。你直奔D区去,当你走到了C区,你就会想着离D区不远了,到了D区4柜,你就会顺着编号往后找5柜。这实际上就是逻辑顺序(A、B、C、D是按照字母顺序排好的)跟实际存储的物理顺序(图书馆的A区后面连着B区,B区后面连着C区,C区后面连着D区)是相同的,这就雷同于聚簇索引。

非聚簇索引

非聚簇索引记录的物理顺序与逻辑顺序没有必然的联系,与数据存储的物理结构没有关系。非聚簇索引上包含被建立索引的数据,以及一个行定位符row-locator,这个定位符可以理解成一个聚簇索引物理排序的指针,通过这个指针可以找到行数据。一个表对应的非聚簇索引可以有多条,根据不同列的约束可以建立不同要求的非聚簇索引。

还是以找书为例子来形容一下非聚簇索引:现在你还是要找《老人与海》这本书,但是你去的不是学校的图书馆,而是市中心的书城。书城的藏书方式不同于图书馆,有可能A区放了文学书,还放了计算机类图书;同一个书柜可能上一层是古典文学,下一层就是言情小说。这回书城的电脑告诉你要找的书在C区3柜8排,这时你走到了B区,发现B区后面竟然不是C区,而是F区,C区在F区的后面。这里就相当于逻辑顺序(A、B、C、D是按照字母顺序排好的)与实际存储的物理顺序(书城的ABCD区不按照字母表排序相连)不同,它们之间没有必然的联系,这就雷同于非聚簇索引。

创建非聚簇索引

我们为award表中的nickname字段加上非聚簇索引:

create nonclustered index nickname_Index on award(nickname);

创建聚簇索引

我们为award表中的id字段加上聚簇索引:

create clustered index id_Index on award(id);

3.3、索引的使用原则总结

  • 不要索引数据量不大的表,对于小表来说,表扫描的成本可以忽略不计。
  • 不要设置过多的索引,在没有聚簇索引的表中,最大可以设置249个非聚簇索引,过多的索引会占用过多的磁盘空间,尤其是在修改数据时,对索引的维护特别消耗性能。
  • 合理使用组合索引,有些情况下可以考虑创建包含所有输出列的覆盖索引。
  • 对经常使用范围的查询字段,可以考虑使用聚簇索引(聚簇索引是性能最好的,一定要谨慎使用)。
  • 避免对不常用的列、逻辑性列、很少数据的列(例如性别字段,只用0和1来表示男女)、大字段列创建索引。
  • 当表的修改(update、delete、insert)操作远远大于检索(select)操作时,不应该创建索引,这两个操作是互斥关系。
  • 定义为text、image、bit类型的字段不应该设置索引。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值