🎉欢迎您来到我的MySQL基础复习专栏
☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克🍹
✨博客主页:小小恶斯法克的博客
🎈该系列文章专栏:重拾MySQL-进阶篇
🍹文章作者技术和水平很有限,如果文中出现错误,希望大家能指正🙏
📜 感谢大家的关注! ❤️
目录
🚀索引分类
🚀聚集索引&二级索引
🚀索引语法
🚀索引分类
在MySQL数据库,将索引的具体类型主要分为以下几类:主键索引、唯一索引、常规索引、全文索引。
分类 | 含义 | 特点 | 关键字 |
主键 索引 | 针对于表中主键创建的索引,唯一标识表中的每一行数据 | 默认自动创建 , 只能有一个 不允许NULL值 | PRIMARY KEY |
唯一 索引 | 避免同一个表中某数据列中的值重复,确保列中的值唯一 | 可以有多个NULL值 | UNIQUE |
常规 索引 | 快速定位特定数据,提高查询性能 | - 允许重复值和NULL值 | INDEX |
全文 索引 | 全文索引查找的是文本中的关键词,而不是比较索引中的值 | 只能在MyISAM存储引擎上使用 | FULLTEXT |
🚀聚集索引&二级索引
在InnoDB存储引擎中,根据索引的存储形式,又可以分为以下两种:
分类 | 含义 | 特点 |
聚集索引 (Clustered
Index) | 将数据存储与索引放到了一块,索引结构的叶子 节点保存了行数据 | 必须有 ,而且只 有一个 |
二级索引 (Secondary Index) | 将数据与索引分开存储,索引结构的叶子节点关 联的是对应的主键 | 可以存在多个 |
聚集索引选取规则 :
✨表中只能有一个聚集索引:每个表只能有一个聚集索引,该索引决定了数据在磁盘上的物理排序顺序。
✨主键作为默认的聚集索引:如果没有显式地指定聚集索引,MySQL将使用主键作为默认的聚集索引。主键是唯一标识表中每一行数据的列。(即如果存在主键,主键索引就是聚集索引。)
✨如果表没有主键,或没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索 引。
✨唯一非空索引可以作为聚集索引:如果表中没有主键或者不想使用主键作为聚集索引,可以选择一个唯一非空索引作为聚集索引,这样可以提高查询性能并减少磁盘IO操作。
聚集索引的选择应考虑查询频率和范围:选择适合查询频率高且范围较小的列作为聚集索引,这样可以减少磁盘IO操作,并提高查询效率。
✨聚集索引的列顺序很重要:聚集索引的列顺序对查询性能有影响,通常情况下,将经常用于过滤和排序的列放在前面,以便优化查询性能。
✨避免频繁更新聚集索引列:由于聚集索引决定了数据在磁盘上的物理排序顺序,频繁更新聚集索引列可能导致数据重组和性能下降,因此,如果有大量更新操作,应该谨慎选择聚集索引。
✨请注意,聚集索引只适用于使用InnoDB存储引擎的表。对于使用MyISAM存储引擎的表,可以通过显示指定
ALTER TABLE
语句来创建聚集索引。
聚集索引和二级索引的具体结构如下:(以下分析以及图片来自于黑马的视频)
聚集索引的叶子节点下挂的是这一列的数据 。
二级索引的叶子节点下挂的是该字段值对应的主键值。
接下来,我们来分析一下,当我们执行如下的SQL语句时,具体的查找过程是什么样子的。
具体过程如下 :
① . 由于是根据name字段进行查询,所以先根据name='Arm'到name字段的二级索引中进行匹配查找,但是在二级索引中只能查找到Arm对应的主键值10。
② . 由于查询返回的数据是*,所以此时,还需要根据主键值10,到聚集索引中查找10对应的记录,最终找到10对应的行row。
③ . 最终拿到这一行的数据,直接返回即可。
回表查询: 这种先到二级索引中查找数据,找到主键值,然后再到聚集索引中根据主键值,获取数据的方式,就称之为回表查询。
✨以下两条SQL语句,那个执行效率高? 为什么?
A. select * from user where id = 5 ;
B. select * from user where name = 'bob' ;
备注 : id为主键, name字段创建的有索引;
解答
✨在这种情况下,执行效率高的SQL语句是A.
select * from user where id = 5;
。原因如下:✨主键索引的查找效率高:由于id是主键,主键索引是一种特殊的索引,具有唯一性和快速查找的特点。通过主键索引可以直接定位到指定id的行,因此查询效率高。
✨因为A语句直接走聚集索引,直接返回数据。
✨而B语句需要先查询name字段的二级索引,然后再查询聚集索引,也就是需要进行回表查询。
思考
InnoDB主键索引的B+tree高度为多高呢 ?
InnoDB主键索引的B+树的高度取决于数据表中的行数和索引的大小
B+树是一种常用的索引结构,用于在数据库中实现索引。对于InnoDB存储引擎而言,主键索引是基于B+树实现的。
B+树的高度是指从根节点到叶子节点的层数。在InnoDB中,B+树的高度通常较低,这是因为InnoDB采用了多级索引的技术。
假设 :
一行数据大小为1k,一页中可以存储16行这样的数据。 InnoDB的指针占用6个字节的空 间,主键即使为bigint,占用字节数为8。
高度为2:
n * 8 + (n + 1) * 6 = 16*1024 , 算出n约为 1170
1171* 16 = 18736
也就是说,如果树的高度为2,则可以存储 18000 多条记录。
高度为3:
1171 * 1171 * 16 = 21939856
也就是说,如果树的高度为3,则可以存储 2200w 左右的记录。
🚀索引语法
创建索引
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 tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES ( 'a ', '15377777770 ', 'lvbu666@163.com', '软件工程 ', 23, '1 ', '6 ', '2001-02-02 00:00:00 ');
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES ( 'b ', '15377777771 ', 'caocao666@qq.com', '电气工程 ', 33, '1 ', '0 ', '2001-03-05 00:00:00 ');
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES ( 'c ', '15377777772 ', '17799990@139.com', '计科 ', 34, '1 ', '2 ', '2002-03-02 00:00:00 ');
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES ( 'd ', '15377777773 ', '17799990@sina.com', '工程造价 ', 54, '1 ', '0 ', '2001-07-02 00:00:00 ');
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES ( 'e ', '15377777774 ', '19980729@sina.com', '软件工程 ', 23, '2 ', '1 ', '2001-04-22 00:00:00 ');
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES ( 'f ', '15377777775 ', 'daqiao666@sina.com', '药学 ', 22, '2 ', '0 ', '2001-02-07 00:00:00 ');
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES ( 'g ', '15377777776 ', 'luna_love@sina.com', '应用数学 ', 24, '2 ', '0 ', '2001-02-08 00:00:00 ');
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES ( 'h ', '17799990007 ', 'chengyaojin@163.com', '化工 ', 38, '1 ', '5 ', '2001-05-23 00:00:00 ');
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES ( 'i ', '17799990008 ', 'xiaoyu666@qq.com', '金属材料 ', 43, '1 ', '0 ', '2001-09-18 00:00:00 ');
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES ( 'j ', '17799990009 ', 'baiqi666@sina.com', '机械工程及其自动 化 ', 27, '1 ', '2 ', '2001-08-16 00:00:00 ');
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES ( 'k ', '17799990010 ', 'hanxin520@163.com', '无机非金属材料工 程 ', 27, '1 ', '0 ', '2001-06-12 00:00:00 ');
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES ( 'l ', '17799990011 ', 'jingke123@163.com', '会计 ', 29, '1 ', '0 ', '2001-05-11 00:00:00 ');
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES ( 'n ', '17799990012 ', 'lanlinwang666@126.com', '工程造价 ', 44, '1 ', '1 ', '2001-04-09 00:00:00 ');
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES ( 'm ', '17799990013 ', 'kuangtie@sina.com', '应用数学 ', 43, '1 ', '2 ', '2001-04-10 00:00:00 ');
数据如下:
完成下列需求:
name字段为姓名字段,该字段的值可能会重复,为该字段创建索引。
CREATE INDEX idx_user_name ON tb_user (name);
如果name字段的值可能会重复,可以使用普通索引来提高查询效率。可以使用以下SQL语句为name字段创建普通索引:
ALTER TABLE tb_user ADD INDEX idx_name (name);
这条语句使用了ALTER TABLE命令,用于修改表结构。ADD INDEX表示要添加一个普通索引,idx_name是索引的名称,name是要创建索引的字段名。
执行这条语句后,MySQL会为name字段创建一个普通索引,可以提高对该字段的查询效率。当查询条件中包含name字段时,MySQL可以使用该索引进行快速查询。需要注意的是,如果name字段的值经常被更新,那么维护索引的代价可能会比较高,因此需要根据实际情况来选择是否创建索引。
phone手机号字段的值,是非空,且唯一的,为该字段创建唯一索引。
create index idx_user_phone on tb_user (phone);
ALTER TABLE tb_user ADD UNIQUE INDEX idx_phone (phone);
这条语句使用了ALTER TABLE命令,用于修改表结构。ADD UNIQUE INDEX表示要添加一个唯一索引,idx_phone是索引的名称,phone是要创建唯一索引的字段名。
执行这条语句后,MySQL会为phone字段创建一个唯一索引,确保该字段的值非空且唯一。如果插入重复的phone值,MySQL会抛出错误提示。
为profession、 age、 status创建联合索引。
CREATE INDEX idx_profession_age_status ON tb_user (profession, age, status);
ALTER TABLE tb_user ADD INDEX idx_profession_age_status (profession, age, status);
这条语句使用了ALTER TABLE命令,用于修改表结构。ADD INDEX表示要添加一个普通索引,idx_profession_age_status是索引的名称,profession、age、status是要创建联合索引的字段名。
执行这条语句后,MySQL会为profession、age、status字段创建一个联合索引,可以提高这三个字段的查询效率。当查询条件中包含这三个字段中的任意一个或多个时,MySQL可以使用该联合索引进行快速查询。
为email建立合适的索引来提升查询效率。
CREATE INDEX idx_email ON tb_user (email);
为了提高email字段的查询效率,可以根据实际情况选择创建普通索引或全文索引。
如果查询条件中只包含email字段,可以使用普通索引。可以使用以下SQL语句为email字段创建普通索引:
ALTER TABLE tb_user ADD INDEX idx_email (email);
这条语句使用了ALTER TABLE命令,用于修改表结构。ADD INDEX表示要添加一个普通索引,idx_email是索引的名称,email是要创建索引的字段名。
如果查询条件中包含email字段的全文搜索,可以使用全文索引。可以使用以下SQL语句为email字段创建全文索引:
ALTER TABLE tb_user ADD FULLTEXT INDEX idx_email (email);
这条语句使用了ALTER TABLE命令,用于修改表结构。ADD FULLTEXT INDEX表示要添加一个全文索引,idx_email是索引的名称,email是要创建索引的字段名。
需要注意的是,全文索引只能用于全文搜索,不能用于普通的等值查询。因此,如果查询条件中只包含email字段的等值查询,应该使用普通索引。
完成上述的需求之后,我们再查看tb_user表的所有的索引数据。
show index from tb_user;
执行:
今天的学习就到这里,希望对你有帮助!