Bootstrap

MySQL数据库进阶知识(二)《索引》

学习目标:

  • 掌握MySQL数据库的索引知识

学习内容:

一、索引概述

  • 介绍
    索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。

  • 演示
    在这里插入图片描述

  • 优缺点
    在这里插入图片描述

二、索引结构

在这里插入图片描述
MySQL的索引是在存储引擎层实现的,不同的存储引擎具有不同的结构,主要包含以下几种:
在这里插入图片描述
在这里插入图片描述
我们平常所说的索引,如果没有特别指明,都是指B+树结构组织的索引。

  • 二叉树
    在这里插入图片描述
    二叉树缺点:顺序插入时,会形成一个链表,查询性能大大降低。大数据情况下,层级较深,检索速度慢。
    红黑树:大数据情况下,层级较深,检索速度慢。
  • B-Tree(多路平衡查找树)
    以一颗最大度数(max-degree)为5(5阶)的b-tree为例(每个节点最多存储4个key,5个指针):
    在这里插入图片描述
    数的度数指的是一个节点的子节点个数。
    具体动态变化的过程可以参考网站: https://www.cs.usfca.edu/~galles/visualization/BTree.html
  • B+Tree
    在这里插入图片描述
    以一颗最大度数(max-dgree)为5(5阶)的B+tree为例:
    在这里插入图片描述

相对于B-Tree区别:
(1)所有数据都会出现在叶子节点
(2)叶子节点形成一个单向链表

  • Hash
    哈希索引就是采用一定的hash算法,将键值换算成新的hash值,映射到对应的槽位上,然后存储在hash表中。
    如果两个或多个键值,映射到同一相同的槽位上,他们就产生了hash冲突(也称为hash碰撞),可以通过链表来解决。
    (1)hash索引特点
    hash索引只能用于对等比较(=,in),不支持范围查询(between,>,<,……)。
    无法使用索引完成排序操作。
    查询效率高,通常只需要一次检索就可以了,效率通常高于B+Tree索引。
    (2)存储引擎支持
    在mysql中,支持hash索引的是memory引擎,而InnoDB中具有自适应hash功能,hash索引是存储引擎根据B+Tree索引在指定条件下自动构建的。
  • 思考:为什么InnoDB存储引擎选择使用B+Tree索引结构?
    (1)相对于二叉树,层级更少,搜索效率更高;
    (2)对于B-tree,无论是叶子节点还是非叶子节点都会保存数据,这样导致一页中存储的键值减少,指针跟着减少,要同样保存大量数据,只能增加树的高度,导致性能降低;
    (3)相对于hash索引,B-tree支持范围匹配及排序操作。

三、索引分类

在这里插入图片描述
在InnoDB存储引擎中,根据索引的存储形式,又可分为以下2种:
在这里插入图片描述
聚集索引选取规则:
(1)如果存在主键,主键索引就是聚集索引。
(2)如果不存在主键,将使用第一个唯一(UNIQUE)索引作为聚集索引
(3)如果表没有主键,或没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引。
在这里插入图片描述
在这里插入图片描述

  • 思考:
    (1)以下SQL语句,哪个执行效率高?
    在这里插入图片描述
    (2)在这里插入图片描述

四、索引语法

  • 创建索引
create [unique|fulltext] index index_name on table_name(index_col_name,……);
  • 查看索引
show index from table_name;
  • 删除索引
drop index index_name on table_name;

按照以下要求,完成索引的创建
源数据:

create table tb_user(
   id int primary key auto_increment comment '主键',
   name varchar(50) not null comment '用户名',
   phone varchar(11) not null comment '手机号',
   email varchar(100) comment '邮箱',
   profession varchar(11) comment '专业',
   age tinyint unsigned comment '年龄',
   gender char(1) comment '性别 , 1: 男, 2: 女',
   status char(1) comment '状态',
   createtime datetime comment '创建时间'
) comment '系统用户表';


INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('吕布', '17799990000', '[email protected]', '软件工程', 23, '1', '6', '2001-02-02 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('曹操', '17799990001', '[email protected]', '通讯工程', 33, '1', '0', '2001-03-05 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('赵云', '17799990002', '[email protected]', '英语', 34, '1', '2', '2002-03-02 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('孙悟空', '17799990003', '[email protected]', '工程造价', 54, '1', '0', '2001-07-02 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('花木兰', '17799990004', '[email protected]', '软件工程', 23, '2', '1', '2001-04-22 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('大乔', '17799990005', '[email protected]', '舞蹈', 22, '2', '0', '2001-02-07 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('露娜', '17799990006', '[email protected]', '应用数学', 24, '2', '0', '2001-02-08 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('程咬金', '17799990007', '[email protected]', '化工', 38, '1', '5', '2001-05-23 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('项羽', '17799990008', '[email protected]', '金属材料', 43, '1', '0', '2001-09-18 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('白起', '17799990009', '[email protected]', '机械工程及其自动化', 27, '1', '2', '2001-08-16 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('韩信', '17799990010', '[email protected]', '无机非金属材料工程', 27, '1', '0', '2001-06-12 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('荆轲', '17799990011', '[email protected]', '会计', 29, '1', '0', '2001-05-11 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('兰陵王', '17799990012', '[email protected]', '工程造价', 44, '1', '1', '2001-04-09 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('狂铁', '17799990013', '[email protected]', '应用数学', 43, '1', '2', '2001-04-10 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('貂蝉', '17799990014', '[email protected]', '软件工程', 40, '2', '3', '2001-02-12 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('妲己', '17799990015', '[email protected]', '软件工程', 31, '2', '0', '2001-01-30 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('芈月', '17799990016', '[email protected]', '工业经济', 35, '2', '0', '2000-05-03 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('嬴政', '17799990017', '[email protected]', '化工', 38, '1', '1', '2001-08-08 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('狄仁杰', '17799990018', '[email protected]', '国际贸易', 30, '1', '0', '2007-03-12 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('安琪拉', '17799990019', '[email protected]', '城市规划', 51, '2', '0', '2001-08-15 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('典韦', '17799990020', '[email protected]', '城市规划', 52, '1', '2', '2000-04-12 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('廉颇', '17799990021', '[email protected]', '土木工程', 19, '1', '3', '2002-07-18 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('后羿', '17799990022', '[email protected]', '城市园林', 20, '1', '0', '2002-03-10 00:00:00');
INSERT INTO itcast.tb_user (name, phone, email, profession, age, gender, status, createtime) VALUES ('姜子牙', '17799990023', '[email protected]', '工程造价', 29, '1', '4', '2003-05-26 00:00:00');

在这里插入图片描述

1、查看索引

select * from tb_user;
show index from tb_user;-- 查看当前索引

运行结果:
在这里插入图片描述

show index from tb_user\G;

运行结果:
在这里插入图片描述

2、创建索引

create index idx_user_name on tb_user(name);
show index from tb_user;
-- 新增后查看

运行结果:
在这里插入图片描述

create unique index idx_user_phone on tb_user(phone);

运行结果:
在这里插入图片描述

create index idx_prof_age_sta on tb_user(profession,age,status);

运行结果:
在这里插入图片描述

create index idx_email on tb_user(email);

3、删除索引

drop index idx_email on tb_user;

五、SQL性能分析

  • SQL执行频率
    MySQL客户端连接成功后,通过show[session|global] status 命令可以提供服务器状态信息。通过如下指令,可以查看当前数据库的INSERT、UPDATE、DELETE、SELECT的访问频次:
show global status like 'Com_______';

运行结果:
在这里插入图片描述

  • 慢查询日志
    慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认10秒)的所有SQL语句的日志。
    MySQL的慢查询日志默认没有开启,需要在MySQL的配置文件
vi /etc/my.cnf

中配置如下信息:

# 开启慢日志查询开关
slow_query_log=1
# 设置慢日志的时间为2s,SQL执行语句超过2s,就会被视为慢查询,记录慢查询日志
long_query_time=2

配置完毕之后,通过以下指令重新启动MySQL服务器进行测试

systemctl restart mysqld

查看慢日志文件中记录的信息

cd /var/lib/mysql
ll
cat localhost-slow.log

使用以下命令,可实时更新显示慢日志文件内容:

tail -f localhost-slow.log
-- 查询慢日志查询开关状态
show variables like 'slow_query_log';

运行结果:
在这里插入图片描述

  • profile详情
    show profiles能够在做SQL优化时帮助我们了解时间都耗费到哪里。通过have_profiling参数,能够看到当前MySQL是否支持profile操作:
mysql>  select @@have_profiling;

默认profiling是关闭的,可以通过set语句在session/global级别开启profiling:

set @@profiling=1;

查看是否开启profilling:

select @@profiling; -- 为0表示关闭

执行一系列的业务SQL的操作,然后通过如下指令查看指令的执行耗时:

-- 查看每一条SQL的耗时基本情况
show profiles;
-- 查看指定query_id的SQL语句各个阶段的耗时情况
show profile for query query_id;
-- 查看指定query_id的SQL语句CPU的使用情况
show profile cpu for query query_id;
show profiles;

运行结果:
在这里插入图片描述

show profile for query 8;

运行结果:
在这里插入图片描述

show profile cpu for query 8;

运行结果:
在这里插入图片描述

  • explain执行计划
    EXPLAIN或者DESC命令获取MySQL如何执行SELECT语句的信息,包括在SELECT语句执行过程中表如何连接和链接的顺序。
    语法:
-- 直接在select语句之前加上关键字explain/desc
EXPLAIN SELECT 字段列表 FROM 表名 WHERE 条件;
explain select * from tb_user where id=1;

运行结果:
在这里插入图片描述

explain select s.name,c.name from student s,course c,student_course sc where s.id=sc.studentid and c.id=sc.courseid;

运行结果:
在这里插入图片描述
explain执行计划各字段含义(加粗部分为较重要字段):
1.id
select查询的序列号,表示查询中执行select子句或者是操作表的顺序(id相同,执行顺序从上到下;id不同,值越大越先执行)
2.select_type
表示SELECT的类型,常见的取值有simple(简单表,即不使用表连接或者子查询)、primary(主查询,即外层的查询)、union(union中的第二个或者后面的查询语句)、subquery(select/where之后包含了子查询)等。
3.type
表示连接类型,性能由好到差连接类型为NULL、system、const、eq_ref、ref、range、index、all。
在这里插入图片描述
在这里插入图片描述
查询唯一索引性能较好:

explain select * from tb_user where phone='17799990005';

运行结果:
在这里插入图片描述
查询非唯一索引性能差一些:

explain select * from tb_user where name='白起';

在这里插入图片描述
4.possible_key
显示可能应用在这张表上的索引,一个或多个
5.key
实际使用的索引,如果为null,则没有使用索引
6.key_len
表示索引中使用的字节数,该值为索引字段最大可能长度,并非实际使用长度,再不损失精确性的前提下,长度越短越好。
7.rows
MySQL认为必须要执行查询的行数,在innodb引擎的表中,是一个估计值,可能并不总是准确的。
8.filtered
表示返回结果的行数占需读取行数的百分比,filtered的值越大越好。
9.extra
额外的信息

六、索引使用

  • 验证索引效率
    在未建立索引之前,执行如下SQL语句,查看SQL的耗时:
select * from tb_sku where sn='100000003145001'\G;-- 26s

在这里插入图片描述
针对字段创建索引:

create index idx_sku_sn on tb_sku(sn);

查询索引显示已建立:
在这里插入图片描述
重新执行根据sn字段查询数据(执行0.02s,比原来的26s速度快很多):
在这里插入图片描述
在这里插入图片描述
综上可知,索引对于数据库查询表的效率有很大提升。

  • 最左前缀法则
    如果索引了多列(联合索引),要遵循最左前缀法则。最左前缀法则指的是查询从索引的最左列开始,并且不跳过索引中的列。如果跳过某一列,索引将部分失效(后面的字段索引失效)。
    例如:
    在这里插入图片描述
    该表存在一个联合索引,包含3列数据,下面用该联合索引验证法则:
    例1:3个条件进行查询,从索引最左列到第3列,中间没有跳过,此时观察使用了联合索引,并且索引长度54
explain select * from tb_user where profession='软件工程' and age = 31 and status='0';

在这里插入图片描述
例2:2个条件进行查询,从索引最左列到第2列,中间无跳过,此时观察也使用联合索引,索引长度49

explain select * from tb_user where profession='软件工程' and age = 31; 

在这里插入图片描述
例3:1个条件进行查询,从索引最左列,此时观察使用联合索引,索引长度47

explain select * from tb_user where profession='软件工程';

在这里插入图片描述
例4:2个条件进行查询,但未使用索引,使用全表查询,原因是条件查询未对索引最左列进行指定,索引失效(只指定status也是一样的结果)

explain select * from tb_user where age = 31 and status='0';

在这里插入图片描述
例5:2个条件进行查询,但中间跳过一列,依旧使用索引,但是索引长度为47(与只使用最左列进行条件查询长度一致),表明只使用了最左列索引,后面的索引已失效。

explain select * from tb_user where profession='软件工程' and status='0';

在这里插入图片描述

  • 范围查询
    联合索引中,出现范围查询(>,<),范围查询右侧的列索引失效
    例1:联合索引第2列使用 > 范围查询,结果使用的索引长度为49(与只指定1、2列索引条件对应的索引长度一致),表明第2列之后的索引已失效
explain select * from tb_user where profession='软件工程' and age > 30 and status='0';

在这里插入图片描述
例2:联合索引第2列使用 >= 范围查询,结果使用的索引长度为54(与指定全列索引条件对应的索引长度一致),表明所有索引都有效,因此在查询过程中为了提高效率尽量使用>=、<=

explain select * from tb_user where profession='软件工程' and age >= 30 and status='0';

在这里插入图片描述

  • 索引列运算
    不要在索引列上进行运算操作,索引将失效。
    例:
    使用phone(索引列)进行条件查询(未运算),索引使用情况如下:
select * from tb_user where phone='17799990019';

explain select * from tb_user where phone='17799990019';

在这里插入图片描述
使用近似查询对phone进行运算操作,索引使用情况如下(未使用索引,由于索引列条件查询时进行了运算导致索引失效):

explain select * from tb_user where substring(phone,10,2)='15';

select * from tb_user where substring(phone,10,2)='15';

在这里插入图片描述

  • 字符串不加引号
    字符串类型字段使用时,不加引号,索引将失效。
    例1:对于索引列phone进行条件查询,查询时不加引号,可以查询出结果,但是查看索引使用情况,观察到该语句未使用索引,由于未使用引号导致索引失效,降低查询效率。
select * from tb_user where phone=17799990015;

explain select * from tb_user where phone=17799990015;

在这里插入图片描述

2:使用联合索引查询,对于第3列索引,加引号时使用的索引长度为54,未加引号可以查询出结果,但是使用的索引长度为49,表明最后一列索引已失效。
explain select * from tb_user where profession='软件工程' and age >= 30 and status='0';

explain select * from tb_user where profession='软件工程' and age >= 30 and status=0;

select * from tb_user where profession='软件工程' and age >= 30 and status=0;

在这里插入图片描述

  • 头部模糊匹配

例1:使用索引列的模糊查询,仅指定尾部模糊匹配,索引未失效:

select * from tb_user where profession like '软件%';

explain select * from tb_user where profession like '软件%';

在这里插入图片描述
例2:指定头部模糊匹配,索引失效:

explain select * from tb_user where profession like '%工程';

在这里插入图片描述
例3:头部+尾部模糊匹配,索引失效:

explain select * from tb_user where profession like '%工%';

在这里插入图片描述

  • or连接的条件
    用or分隔开的条件,如果or前的条件中列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到。
    例1:id(索引列)与age(无索引列)使用or连接,索引失效,可能使用索引包含索引列对应的索引,但未实际使用该索引:
explain select * from tb_user where id=10 or age=23;

在这里插入图片描述
例2:phone(索引列)与age(无索引列)使用or连接,索引失效,可能使用索引包含索引列对应的索引,但未实际使用该索引:

explain select * from tb_user where phone='17799990000' or age=23;

在这里插入图片描述

以上两例由于age没有索引,所以即使id、phone有索引,索引也会失效。所以需要针对于age也要建立索引。
建立索引后查询用到的索引情况如下:

create index idx_user_age on tb_user(age);

explain select * from tb_user where id=1 or age=31;

在这里插入图片描述

  • 数据分布影响
    如果MySQL评估使用索引比全表更慢,则不使用索引。
    例1:查询带条件的phone数据,第一种为查询大于等于17799990020的数据(部分数据);第二种为查询大于等于17799990000的数据(全部数据)。这两种情况展示索引使用情况后,前者使用索引,而后者未使用
    在这里插入图片描述
    例2:查询带条件的phone数据,第一种为查询大于等于17799990010的数据(大部分数据满足条件);第二种为查询大于等于17799990000的数据(少部分数据满足条件)。这两种情况展示索引使用情况后,前者不使用索引,而后者使用索引。因此可知当条件查询是否使用索引,需要根据满足条件的数据占比确认(大于0.5不走,小于0.5走)。
    在这里插入图片描述

  • SQL提示
    SQL提示,是优化数据库的一个重要手段,简单来说,就是在SQL语句中加入一些人为的提示来达到优化操作的目的。

explain select * from tb_user use index(idx_user_pro) where profession='软件工程';

explain select * from tb_user ignore index(idx_user_pro) where profession='软件工程';

explain select * from tb_user force index(idx_user_pro) where profession='软件工程';

例:当前数据表有一个关于profession+age+status的联合索引,还有一个profession的单列索引,在对profession进行条件查询时,使用索引情况如下:(可能使用索引有两个,实际使用索引为联合索引)

explain select * from tb_user where profession='软件工程';

在这里插入图片描述

1.在进行优化时,可以指定使用index_user_pro索引:

explain select * from tb_user use index(idx_user_pro) where profession='软件工程';

在这里插入图片描述

2.指定不使用某个索引

explain select * from tb_user ignore index(idx_user_pro) where profession='软件工程';

explain select * from tb_user ignore index(idx_prof_age_sta) where profession='软件工程';

在这里插入图片描述

  • 覆盖索引
    尽量使用覆盖索引(查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到),减少select *。
explain select id,profession from tb_user where profession='软件工程' and age=31 and sattus='0';

explain select id,profession,age,status from tb_user where profession='软件工程' and age=31 and sattus='0';

explain select id,profession,age,status,name from tb_user where profession='软件工程' and age=31 and sattus='0';

在这里插入图片描述

using index condition:查找使用了索引,但是需回表查询数据
using where;using index:查找使用了索引,但需要的数据都在索引列能找到,所以不需要回表查询数据。
逻辑图演示:
1.查询的字段包含在索引内:
在这里插入图片描述
2.查询的字段有未包含在索引内的字段:
在这里插入图片描述
思考:一张表,有四个字段(id,username,password,sattus),由于数据量大,需要对一下SQL语句进行优化,该如何进行才是最优方案:

select id,username,password from tb_user where username='itcast';

针对username、password建立联合索引,联合索引下挂的是id,因此可避免回表查询。

  • 前缀索引
    当字段类型为字符串(varchar,text等)时,有时候需要很长的字符串,这会让索引变得很大,查询时,浪费大量的磁盘IO,影响查询效率。此时可以只将字符串的一部分前缀,建立索引,这样可以大大节约索引空间,从而提高索引效率。
    1.语法
create index idx_xxx on table_name(column(n));

2.前缀长度
可以根据索引的选择性来决定,而选择性是指不重复的索引值(基数)和数据表的记录总数的比值,索引选择性越高则查询效率越高,唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。

select count(distinct email)/count(*) from tb_user;

select count(distinct substring(email,1,5))/count(*) from tb_user;

例:根据email字段进行前缀选择性查询
前10个字段查询选择性如下:选择性最高
在这里插入图片描述
5-9、4截取长度下的选择性:
在这里插入图片描述
因此如果追求高选择性索引,可以考虑10个长度的前缀索引,如果需要平衡长度、选择性,则考虑5个长度的前缀索引。
演示:针对email字段建立前5个长度的前缀索引

create index idx_email_5 on tb_user(email(5));

show index from tb_user;-- 查询索引

在这里插入图片描述
建立索引后,查询指定email数据:

select * from tb_user where email='[email protected]';

explain select * from tb_user where email='[email protected]';

查询索引使用情况后,显示确实使用我们创建的前缀索引:
在这里插入图片描述

  • 单列索引与联合索引
    单列索引:一个索引只包含单个列。
    联合索引:一个索引包含多个列。
    例:
    1.单列索引情况:
explain select id,phone,name from tb_user where phone='17799990010' and name='韩信';

在这里插入图片描述
多条件联合查询时,MySQL优化器会评估哪个字段索引效率更高,会选择该索引完成本次查询。
2.对于需要查询id+phone+name的数据,可设置联合索引,防止查询数据时出现回表查询,从而提升效率。

create unique index idx_user_phone_name on tb_user(phone,name);

explain select id,phone,name from tb_user where phone='17799990010' and name='韩信';

explain select id,phone,name from tb_user use index(idx_user_phone_name) where phone='17799990010' and name='韩信';

在这里插入图片描述
在这里插入图片描述

七、索引设计原则

1.针对于数据量比较大(100w以上),且查询比较频繁的表建立索引。
2.针对于常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立索引。
3.尽量选择区分度高(唯一性高)的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高。
4.如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引。
5.尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率。
6.要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改的效率。
7.如果索引列不能存储NULL值,在创建表时使用NOT NULL约束它。当优化器知道每列是否包含null值时,他可以更好地确定哪个索引最有效的用于查询。


学习时间:

  • 周一至周五晚上 7 点—晚上9点
  • 周六上午 9 点-上午 11 点
  • 周日下午 3 点-下午 6 点

学习产出:

  • 技术笔记 2 遍
  • CSDN 技术博客 1 篇
;