拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SQL语言课内索引

SQL语言课内索引

1. 索引是什么

  • 索引是加速数据查询的辅助数据结构。能加速的原因是"先查目录再取数据"
  • 键:索引列上的取值,比如name = '张三'。
  • 值:能定位到那一行的东西,存什么取决于哪一种索引——
    • 聚簇索引(主键索引)的叶子节点存的是整行数据,"值"就是那一行本身;
    • 非聚簇索引(辅助索引)的叶子节点存的是主键值(整行只有一份,不放在这里),所以拿到主键值后还得回聚簇索引再查一次,这就是回表;
    • B+ 树的非叶节点只存键和指向子节点的页号(逐层缩小范围),叶子节点之间再用链指针串成一串。
  • 怎样的值能定位:不是"某种特殊的值",而是——① 查询条件要用得上这个索引(等值,或满足最左前缀;用不上索引时,值再规整也只能全表扫描);② 这个值的区分度要够(重复值太多,树里定位到的是一大段,还要顺着叶子链一条条比对)。
  • 注意:索引是内模式(存储)层面的东西,所以它的效果和存储引擎绑在一起(见[[1 数据定义]]§2 那张层次表)。

2. 建索引与索引的分类

-- 语法格式(课件 36 页)CREATE[UNIQUE][CLUSTER]INDEX<索引名>ON<表名>(<列名>[ASC|DESC][,…]);-- 课件 36 页的例子CREATEINDEXidx_nameONs(sname);-- [例7](课件 38 页)为学生-课程库的三个表建索引CREATEUNIQUEINDEXIdx_StusnoONStudent(Sno);-- Student 按学号升序建唯一索引CREATEUNIQUEINDEXIdx_CoucnoONCourse(Cno);-- Course 按课程号升序建唯一索引CREATEUNIQUEINDEXIdx_SCnoONSC(SnoASC,CnoDESC);-- SC 按学号升序、课程号降序建唯一索引-- 课件注:也可以在创建表的时候直接指定CREATETABLEperson(idINTNOTNULLAUTO_INCREMENTPRIMARYKEY,nameVARCHAR(8),INDEXix_person_name(name)-- 建表时带上索引);
分类角度种类说明
功能逻辑主键索引唯一且非空,每张表 1 个,聚簇索引
普通索引—
唯一索引—
全文索引—
物理实现方式聚簇索引叶子节点直接放整行数据
非聚簇索引(二级索引 / 辅助索引)需要回表
字段个数单一索引—
联合索引最左原则:index(a,b,c)支持a;a,b;a,b,c三类查询

两种索引的层次关系(CREATE INDEX建出来的一律是非聚簇的二级索引,聚簇索引由主键决定):

定主键就定了聚簇索引

InnoDB 的表本身就是

其余索引一律是

拿主键值回聚簇索引取整行

表 Student

聚簇索引

主键

二级索引

叶子节点:整行数据

叶子节点:索引列的值 + 主键值

按主键查:一次查找就取到整行

按索引列查:取到主键值后再回表

  • 建索引就一个动词CREATE INDEX,可带UNIQUE(唯一)和CLUSTER(聚簇)。

3. 回表

-- 表 t(id 主键, name 建了索引, gender, flag),四条数据SELECT*FROMtWHEREname='lisi';-- (1)先通过普通索引(辅助索引)定位到主键值 id = 5-- (2)再通过聚簇索引定位到行记录 ← 这一步就叫回表-- 课件提的两个问题:-- 如何减少回表?-- 如果查询结果是多行记录,是每条记录都回表还是若干次后回表 1 次?
  • 回表的含义就是B表name查id,那id到A表再查。
  • 要点:课件原话"MySQL 不支持单独的聚簇索引,主键索引即聚簇索引",所以例8 的CREATE CLUSTER INDEX Stusname ON Student(Sname);(课件 39 页)在 MySQL 上会报错,聚簇索引只能通过主键定下来。

4. 删索引(课件 41 页)

-- 语法格式(课件 41 页)DROPINDEX<索引名>ON<表名>;-- [例9] 删除 Student 表的 Stusname 索引DROPINDEXStusnameONStudent;ALTERTABLEstudentDROPINDEXStusname;-- 等价的第二种写法(课件给的)
  • 总体:一个索引两种删法,效果相同。
  • 大思路:课件原话——SQL 标准中没有定义对索引的修改功能,而采用删除 + 重新定义索引的方式实现。所以[[1 数据定义]]§2 那张"四类对象 × 三个动词"表里,索引的"修改"一栏是空的。
  • 要点:删主码索引要写ALTER TABLE t DROP PRIMARY KEY,删外码要写DROP FOREIGN KEY 名,都不是DROP INDEX。

5. 索引的实现

二叉树 / 平衡二叉树:一个节点一个键 → 树高约 log2(N),每层一次磁盘 IO,太高 B 树: 非叶节点和叶节点都存数据 → 一页里能装的键变少、树变高;范围查询要在树里来回走 B+ 树: 只有叶节点存数据,叶节点之间用链指针连成一串;非叶节点只存键 → 一页装的键多、树矮(IO 少);范围查询顺着叶节点链走 Hash: 按 hash 值直接定位 → 等值查询快,但范围、排序用不了
  • 总体:索引的物理实现就是这张图里的四种结构,MySQL 的索引用 B+ 树。
  • 比较它们的标准是磁盘 IO 次数——数据在磁盘上,一次 IO 读一页;树越矮、一页装的键越多,需要读的页越少。
  • 要点(课件 46 页两道课后讨论题的答案):① 不用平衡二叉树,是因为树高太大、IO 次数多;不用 B 树,是因为非叶节点也存数据导致一页装的键变少、树变高,且范围查询效率差。② Hash 索引适合等值查询;B+ 树索引等值和范围都行,还能用于排序。

6. 最左匹配原则,索引命中与速度

CREATEINDEXidx_objONuser(ageASC,heightASC,weightASC);-- ASC 是 Ascending 的缩写,意思是升序,从小到大 是默认值,不写也是升序。-- 联合索引的排序规则:先比 age,age 相同再比 height,height 也相同才比 weightSELECT*FROMuserWHEREage=1ANDheight=2ANDweight=7;-- 走索引:三列全用上SELECT*FROMuserWHEREage=1;-- 走索引:只用第一列SELECT*FROMuserWHEREheight=2ANDweight=7;-- 不走索引:缺最左的 ageSELECT*FROMuserWHEREage>1;-- 范围查询:age 可用,它右边的列不能再定位
  • 总体:联合索引index(a,b,c)能被用上的只有a、a,b、a,b,c这三种"最左前缀"。
  • 查询速度快慢,一般而言命中索引的快,命中越多越快。
  • 注意,SELECT * FROM user WHERE height=2 AND weight=7;-- 不走索引:缺最左的 age,是完全不命中索引(本质查询树,开头不能断)

7. EXPLAIN 看执行计划

EXPLAINSELECT*FROMSCWHERESno='2024001';-- 课件:查看查询的执行计划(性能分析之必备)SELECTsno,snameFROMuserinfoUSEINDEX(index_list)WHEREuser_id>100;-- 课件:强制指定用某个索引

EXPLAN的查询结果如下表:

列名描述列名描述
idselect 查询的序列号,表示查询中执行 select 子句或表的顺序key_len实际使用的索引长度
select_type查询类型ref使用索引等值查询时,与索引列进行等值匹配的对象信息
table表名rows预估的需要读取的记录数
partitions匹配的分区信息filtered预估记录经过搜索条件过滤后剩余记录条数的百分比
type针对单表的访问方法

type(按执行速度):system > const > eq_ref > ref > range > index > all
all = 全表扫描
Extra一些额外的信息
possible_keys可能用到的索引
key实际使用的索引,NULL则没用
  • 总体:EXPLAIN把一个查询的执行计划摊开:用了哪个索引、扫多少行、用什么访问方法。
  • 大思路:调优就看三处——key是不是 NULL(没用索引)、type是不是all(全表扫描)、rows是不是很大。
  • 要点:课件给的type快慢序要背下来,all是最慢的一档。

8. 其他题目

主观题:索引一定可以提高查询效率吗?如何使用索引才能提高效率?(课件 39 页)
→ 不一定。索引占空间,而且增删改时都要维护索引;数据量小、或列上重复值很多(如性别)时,走索引并不比全表扫描快;查询条件不满足最左前缀、或查询列被函数包住时,索引也用不上。要用得对:建在经常出现在查询条件里的列上、建在区分度高的列上、联合索引按最左前缀的顺序写条件、建完用EXPLAIN验证。

判断题:聚集索引决定了索引所在表的物理存储结构,一张表中只能有一个聚集索引,但是一个聚集索引可以包含很多列。(课件 42 页)
→对。聚簇索引的叶子里放的就是整行数据,行的物理存放顺序由它决定;一张表只能有一个(数据只有一份物理顺序),但可以是多列组成的联合索引。

主观题:唯一键和主键的区别是什么?(课件 43 页)
→ ① 主键非空且唯一,唯一键允许空值(且可以有多个空值);② 一张表只能有一个主键,唯一键可以有多个;③ 主键对应实体完整性、可作外码的参照目标,唯一键属于用户定义完整性;④ 两者都会自动建索引。

返回列表