MySQL索引与锁的机制 三 MYSQL 索引机制
MYSQL 索引机制
数据库的检索过程:
- Mysql 的 基本存储 结构是 页, 各个数据页 组成一个双向的 链表,单个数据页中的记录 又组成一个 单向的 链表
- 每个数据 页 都会为 存储的记录 生成一个页目录, 在通过 主键(索引) 查找 某条记录时, 可在 页目录中 使用 二分法 快速定位 对应的 槽, 让后再 遍历 该槽对应 分组中的 记录 即可 快速 找到 指定的 记录数据。 以 非主键 作为 搜索条件, 只能从最小 记录开始 依次 遍历 单链表中的每条记录 即:
1. 遍历双向链表,找到所在的页
2. 从所在的页中 查找相应的 记录, 由于不根据 主键查询, 只能遍历所在页的 单链表, 当数据量过大时(比如上亿条) 结果会很慢
select * from users where id = 10010 主键(索引)
select * from users where username = 'tom' 非主键(无索引)
索引与创建索引:
什么是索引:
索引 是对数据库 表中的一列或多列的值 进行排序的 一种 存储结构(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
索引注意事项:
适合建立索引的情况:
表的主 关键字,自动建立唯一索引
表的字段唯一约束
直接条件查询 的字段
查询中与 其他表关联的字段
查询中排序的字段
查询中 统计 或者 分组的 字段(max 和 group by 的字段)
不适合建立索引的情况:
表记录太少(一般索引表 与 数据表 不在同一个数据库, 需要先访问索引表 在通过 索引表访问 数据表)
经常插入, 删除, 修改的 表 字段(B+树 平衡调整)
数 经常 重复 且 分布均匀 的表 字段(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+ 那样 从根节点到 叶子结点 逐级查询, 只需要 一次哈希 算法 即可立刻 定位到 相应的位置,速度快
● 局限性
无法利用 索引 完成排序
不支持 最左匹配原则
在有大量重复键值的情况下, 存在 hash 冲突 效率低
不支持 匹配范围
● 主流数据库 采用 B+ 树索引 InnoDB 使用的是 自适应 哈希 索引, 即会 根据表的 使用情况 自动为 表生成 哈希索引,不能 人为干预
上一篇: JAVA 攻城狮 第三十二天
下一篇: Python学习(四)——函数