欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

MySQL索引与锁的机制 三 MYSQL 索引机制

程序员文章站 2024-03-23 12:23:10
...

                                                          MYSQL 索引机制


数据库的检索过程:

  • Mysql 的 基本存储 结构是 ,  各个数据页 组成一个双向的 链表,单个数据页中的记录 又组成一个 单向的 链表
  • 每个数据 页 都会为 存储的记录 生成一个页目录, 在通过 主键(索引) 查找 某条记录时, 可在 页目录中 使用 二分法 快速定位 对应的 槽,  让后再 遍历 该槽对应 分组中的 记录 即可 快速 找到 指定的 记录数据。 以 非主键 作为 搜索条件 只能从最小 记录开始 依次 遍历 单链表中的每条记录 即:

1. 遍历双向链表,找到所在的页

2. 从所在的页中 查找相应的 记录,  由于不根据 主键查询, 只能遍历所在页的 单链表当数据量过大时(比如上亿条) 结果会很慢         

  • select * from users where id              = 10010      主键(索引)

  • select * from users where username = 'tom'        非主键(无索引)

MySQL索引与锁的机制 三 MYSQL 索引机制 

 


 

 

索引与创建索引:

什么是索引:

  • 索引 是对数据库 表中的一列或多列的值 进行排序的 一种 存储结构(B+树), 可以加快数据库的检索速度

  • 索引 的作用相当于数 的 目录,可以根据目录中的 页码快速 找到 所需的内容

  • 没有使用 索引 需要遍历 双向链表来 定位 对应的页,  现在通过索引 就可以很快定位 到对应的页上, 索引 底层结构就是 B+ 树(也有 hash 表), B+ 树作为 树的 一种实现, 能够让我们 很快底查找出对应的记录

索引的创建:

CREATE TABLE users(
    userid INT NOT NULL auto_increment  PRIMARY KEY,
    username VARCHAR(20)  NOT NULL,
    pwd VARCHAR(16),
    INDEX idx_username(username)                 #创建索引

    #INDEX idx_username(username(10))         #前 10个字符作为索引 
)


ALTER TABLE users ADD INDEX idx_username(username)                #可重复的索引
ALTER TABLE users ADD UNIQUE idx_username(username)             #不可重复的索引
ALTER TABLE users ADD PRIMARY KEY idx_username(username)   #不可重复的索引, 表中数据的 唯一标识


DROP INDEX  idx_username ON users                                           #删除索引

ALTER TABLE users DROP INDEX idx_username                          #删除索引
ALTER TABLE users DROP PRIMARY KEY                                    #删除索引

SHOW INDEX FROM users
SHOW KEY FROM users

联合索引:

CREATE * FROM users(
    userid INT NOT NULL,
    username VARCHAR(20) NOT NULL,
    pwd VARCHAR(20) NOT NULL,
    phone VARCHAR(20),
    INDEX idx_username_pwd(username, pwd, phone)                        #指定 联合索引
)

SELECT * FROM users WHERE username = 'tom' AND pwd = 'malocfree'

 

  • 相当于创建了 (username, pwd, phone),(username, pwd),(username) 三个索引
  • 最左匹配:遇到范围查询(>, <, between, like, 左匹配等)就不能进行 一步匹配, 后续退化为 线性查找; 如为 一个表 创建 联合索引 (a,b,c,d), 查询 select * from mytable where a = 1 and b = 2 and c > 3 and d = 4,  则会 一次 命中   a, b,c  却无法命中 d
  • 联合索引 (a,b,c,d)   查询条件 c > 7 and b = 5 and a = 1 and d < 3 与 a = 1 and c > 7 and b =5 and d <3 等顺序都是可以的。 Mysql 会 自动优化 为  a = 1 and b =5 and c > 7 and d < 3,  依次命中 a b c

 

 

 


索引注意事项:

适合建立索引的情况:

  1. 表的主 关键字,自动建立唯一索引

  2. 表的字段唯一约束

  3. 直接条件查询 的字段

  4. 查询中与 其他表关联的字段

  5. 查询中排序的字段

  6. 查询中 统计 或者 分组的 字段(max 和 group by 的字段)

不适合建立索引的情况:

  1. 表记录太少(一般索引表 与 数据表 不在同一个数据库, 需要先访问索引表 在通过 索引表访问 数据表)

  2. 经常插入, 删除, 修改的 表 字段(B+树 平衡调整)

  3. 数 经常 重复 且 分布均匀 的表 字段(b比如 性别, 星期几 等等)

 

索引并不总是 最好用的工具, 总的来说  只有当  索引帮助 存储引擎 快速 查找到记录 带来的好处 大于 其带来的 额外工作时。 索引才是 有效的对于非常小的表, 大部分情况下 全表扫描 更加高效。 对于 中到大型的表, 索引就非常有效了。 但对于 特大型的表, 建立 和 使用索引的 代价 将随之增加。 这种情况下 则需要一种技术 可以 直接区分出查询 需要的 一组数据, 而不是 一条记录 一条记录的 匹配, 例如: 可以使用分区技术

  根据 每天 把数据表 分区

CREATE TABLE IF NOT EXISTS mytable(
	id INT NULL auto_increment PRIMARY KEY,
	mname VARCHAR(20),
  pwd VARCHAR(20)	
) PARTITIONED BY (ymd date)

 

 

 


 

 

聚簇索引 与 非聚簇索引:

● 聚簇索引

以主键 创建的索引, 在叶子结点处  储存的记录 包含了表中所有的列(key- value)

●  二级索引(非聚簇索引)

非主键 创建 的索引,在叶子结点 处 储存的记录内容是 主键,使用非 聚簇 索引 查询数据时,拿到叶子结点的 主键, 再去 聚簇索引的 B+树 上查询 想要的数据(这个过程叫做 回表)

每增加 一种索引, 就会新建一颗 对应的 B+ 树, 彼此独立的树

●MyISAM  单独为表的 主键常见一个  B+ 树的索引, 在 B+ 树 的叶子 结点中 存储的不是 完整的用户记录, 而是主键值 + 行号的 组合。 也就是 先通过 索引 找到 对应的 行号, 在通过行号 去找 对应的记录。 两次

● InnoDB 存储引擎 只需要 根据 主键值 对应 聚簇 索引 进行 一次查找 即可 找到对应的记录数据, MyISAM  中需要进行 一次回表操作, 意味着MyISQL  中建立的 索引 全部是二级的

 

 


 

 

Hash 索引:

● 哈希索引就是 采用 哈希算法, 把键值换算 成行的哈希值, 检索时 不需要 类似 B+ 那样 从根节点到 叶子结点 逐级查询, 只需要 一次哈希 算法 即可立刻 定位到 相应的位置,速度快

● 局限性

  1. 无法利用 索引 完成排序

  2. 不支持 最左匹配原则

  3. 在有大量重复键值的情况下, 存在 hash 冲突 效率低

  4. 不支持 匹配范围

主流数据库  采用  B+ 树索引  InnoDB 使用的是 自适应 哈希 索引, 即会 根据表的 使用情况 自动为 表生成 哈希索引,不能 人为干预