SQL 学习(二)性能优化

数据表中的键

数据表中的键 由一个或者多个属性组成

  1. 超键 能唯一标示元组的属性集 叫做超键 能唯一标示这一条记录的属性(一个或者多个)或者和其他属性的任意组合
  2. 候选键 不包含其他属性的超键
  3. 主键 从候选键中选一个。一张表 只能有一个主键
  4. 外键
  5. 主属性 包含在任一 候选键中的属性叫候选键
  6. 非主属性 与主属性相对
三范式
  1. 1NF 数据表中任何属性都是原子的 不可拆分
  2. 2NF 非主属性完全依赖于候选键 也就是 确定候选键就能唯一确定这些非主属性
  3. 3NF 任何非主属性都不传递依赖于候选键
BCNF

巴斯-科德范式 消除主属性对候选键的部分依赖或者传递依赖

反范式设计
  1. 满足范式设计 会出现表的层级越来越多 如果数据量大 需要多表关联 那么会影响查询效率
  2. 带来的问题 会对维护成本有所增加
  3. 适用场景 比如历史数据 或者 增删改的操作不多 的情况
索引
  1. 什么是索引 是一个数据结构 帮助数据库管理系统高效获取数据的数据结构 索引就像是一本书的目录 帮助我们快速查找数据库中的数据
  2. 当数据量少的时候 使用索引和不使用索引区别不大 当要建索引的属性重复率在10%以上是就不需要建索引 比如 性别列 如果加上索引 反而会使查询变慢
  3. 使用索引的同时也要注意数据的分布情况 当需要查询的数据量少的情况 使用索引 查询效率会大大增加
索引的种类

功能逻辑上分

  1. 普通索引
  2. 唯一索引
  3. 主键索引
  4. 全文索引 (Mysql 只支持英文的全文索引 一般使用专门的全文索引引擎 ElasticSearch)

物理实现方式分

  1. 聚集索引 叶子节点存储的直接就是数据 一张表只能有一个聚集索引
  2. 非聚集索引 叶子节点存储的是数据的位置 需要先找到位置 在找到真实的数据。

联合索引的最左侧原则
比如说 对userid 和 userName 做一个联合索引 如果用select userName from where userid=10 and userName=“abc” 和 select userName from where userid=10都是可以用上索引的 但是使用 select userName from where use rName=“abc” 就用不上索引了

索引的实现原理
  1. 什么是 B 树
    平衡多路搜索树
    每个节点都有M个子节点 每个子节点保存了关键字和子节点的指针 磁盘IO的次数比二叉树低 但总体上效率也不是很高
  2. 什么是B+树
    非叶子节点的关键字同时也会存在在子节点中
    非叶子节点仅用于索引 不保存数据记录 跟数据记录有关的都保存在叶子节点中 所有关键字都在叶子节点出现 叶子节点构成一个有序链表 叶子节点本身按照从小到大顺序链接
  3. B树和B+树的比较
    B+树比B树更稳定 因为数据都存在叶子节点中 每次都只有访问到叶子节点才能拿到数据
    B+树由于 叶子节点之间是采用链表的形式 所以范围查找的情况下效率也更高
    通常情况下B+比B树更矮胖 磁盘的I/O 会更少
Hash 索引
  1. Hash 索引是 键值通过Hash 映射到一个桶(bucket) 桶是一个能存储一条或者多条数据的存储单位 一个桶包含一个内存指针数组 桶中的每一行都会指向下一行形成链表结构

  2. Hash 索引 和 B+ 索引区别
    Hash 索引 不能进行范围查找 B+ 索引可以
    Hash 索引 不支持联合索引的最左侧原则
    Hash 索引 无序 B+ 有序
    Hash 索引 不支持order_by
    Hash 索引 不能进行模糊查询

  3. 对于等值查询来说 Hash 索引比 B+ 要快 但是当重复数据多的情况下 就会出现大量的Hash 冲突 也会降低效率

索引创建规律
  1. 需要创建索引的情况

    • 字段是唯一的 可以创建唯一索引 或者主键索引
    • 频繁使用的 where 条件
    • Group By 或者 Order By 的字段
    • 多表链接的时候 一定要有where 条件并且对where条件做索引 同时还需要对链接的字段做索引 并且链接的字段的类型必须相同
  2. 什么时候不需要创建索引

    • where 条件里用不到的数据
    • 表记录少
    • 字段大量重复
    • 频繁更新的字段不一定创建索引
  3. 什么时候索引会失效

    • 如果对索引字段进行了表达式计算 比如 where user_id + 1 > 1000
    • 对索引使用函数也会失效 比如WHERE SUBSTRING(comment_text, 1,3)=‘abc’
    • where 条件中 如果 or 前边的使用了索引 后边的没有索引 索引会失效
    • 联合索引最左侧原则
    • 索引字段最好加上not null 约束
数据库的存储结构
  1. 页 数据库存储的基本单位是 页 一个页可以存储 一个数据页中存储一条或者多条记录 不管数据库读取一行还是多行记录最终都需要加载整页到内存中
  2. 区 Innodb中 一个区分配64个连续的页 一个页16kb 一个区是64*16=1M
  3. 段 由一个区或者多个区组成
  4. 表空间 存储一个或者多个段 一个段只能属于一个表空间
  5. 数据库由一个或者多个表空间组成 在innodb 中 分为独立表空间和共享表空间 共享表空间 就是多张表共用一个表空间 独立表空间就是一个表对应一个表空间

数据页的存储结构

  1. 文件头尾 保存两个指针指针指向上一个页和下一个页形成一个双向链表 同时通过hash算法实现数据完整性检验
  2. 记录部分 最大最小记录 用户记录 空闲空间
  3. 索引部分 对数据进行分组 重点是页目录 页目录中提供了二分查找的方式提高检索效率
磁盘I/O

一、缓冲池

  1. DBMS 为了让数据更快的被我们访问到 所以会申请一部分内存来作为数据缓冲池 并且会定时的清理掉不常用的数据 把常用的数据放在缓冲池中 如果修改的数据在缓冲池中 那么其实修改结果不会立刻同步到磁盘中,而是采用一种checkpoint的机制 写入磁盘

二、数据页加载方式

  1. 内存加载
  2. 随机读取 直接查找数据页
  3. 顺序读取 一种批量读取的方式

三、last_query_cost

mysql> SHOW STATUS LIKE 'last_query_cost';

查看查询成本 就是 访问了多少了数据页

索引

一、 窄索引和宽索引

  1. 一般情况下 窄索引就是包含列数小于等于2的
  2. 宽索引就是包含字段大于2的
  3. 每个非聚集索引都会存储主键

二、如果避免回表

  1. 什么是回表 是通过索引找到数据行之后 还要通过主键再去表中找到数据等情况
  2. where条件要加索引 group by order by的字段要加索引 着重考虑需要查找的字段是否要加上联合索引来避免回表 以此来提高查询效率
  3. 小总结: 在某个字段上增加了索引 相当于把这个字段以及主键 放在了B+树的叶子节点上,可以更快的访问到这个字段 以及找到主键 这是要想拿这条数据的完整信息就需要通过主键回表再查找
  4. 索引过多所带来的问题 1. 缓冲池占用过大 磁盘占用过大 2.每更新一条数据就要更新索引造成时间浪费3.造成索引变宽 让一页的存储数据量表少 增加页的访问成本
悲观锁和乐观锁

一、按照粒度进行划分

  1. 行锁
  2. 页锁
  3. 表锁
    Innodb 支持 1 3

二、按照数据库管理的角度划分

  1. 共享锁也叫做读锁 在读取数据的时候会对数据加锁 防止读取数据的时候被修改,加上了共享锁之后这个表就变成了只读的了 要想修改必须释放锁 也可以对数据行加共享锁
  2. 排他锁 也是独占锁 写锁 只有获得锁操作的事务才能对数据进行查询和修改 其他事务不能对数据进行查询和修改
  3. 意向锁 给更大一级的空间示意里面是否已经上过锁 比如对某一行加上了排他锁 数据库回对更大一级的比如数据页加上意向锁 告诉别人已经有人获得了排他锁了
  4. 共享锁 容易产生死锁 比如两个事务都获得了读锁 但是 都没有释放

三、从数据库角度划分

  1. 乐观锁 适用于读多写少的情况下 认为同一时间又读又写的操作不多
  2. 悲观锁 需要利用数据库的锁
事务补充

一、事务带来的三个问题

  1. 脏读 读到了其他事务还没有提交的数据
  2. 不可重复读 第一次读和第二次读不一致
  3. 幻读 第一次读数据5条第二次 6条

二、事务的隔离级别

  1. 读已提交 解决脏读
  2. 可重复读解决不可重复读(mysql中的默认)
  3. 可串行化 解决所有
MVCC多版本并发控制

一、什么是快照读 什么是当前读

  1. 不加锁的select 都是快照读
  2. 加锁的select或者 增加删除修改都是当前读

二、MVCC的实现机制

  1. 事务版本号 没开启一个事务 都会从数据库中获得一个事务ID 也就是事务的版本号 通过ID 的大小就可以判断事务的时间顺序
  2. 行的隐藏列db_row_id 隐藏行ID 默认生成聚集索引 如果创建表的时候没有指定聚集索引 Innodb就会使用这个隐藏字段来作为聚集索引
  3. db_trx_id 操作这个数据的事务ID 也就是最后一个操作该数据的事务ID
  4. db_roll_ptr 回滚指针 指向记录的undo log 信息

三、undolog
保存行记录快照 通过回滚指针形成链表保存

四、Read View 如何工作 下面是重要属性

  1. trx_ids 系统当前增在活跃的事务ID

  2. low_limit_id 活跃事务中最大的事务ID

  3. up_limit_id 活跃事务中最小的事务ID

  4. creator_trx_id 创建这个ReadView的事务ID

    如果现在有一个事务相访问一条数据 假设这条数据的事务ID是 A

  5. 如果A 小于 up_limit_id 说明事务已经提交 对读取操作可见

  6. 如果A大于low_limit_id 说明事务还没有提交对读取操作不可见

  7. 如果在up_limit_id和low_limit_id之间 那么事务可能还没有提交 此时要看A在不在trx_ids中如果在就对读操作不可见 如果不在就对读操作可见

五、InnoDB是如何解决幻读的

  1. 记录锁 对单行数据记录添加锁
  2. 间隙锁 可以锁定一个范围 但是不包含记录本身
  3. Next-Key 锁 可以锁定一个范围 同时包括记录本身
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值