数据库学习:MySQL总结

MySQL学习总结

B+ Tree 原理

B Tree — Balance Tree。B树是一棵平衡树

  • B+ Tree。这个"+",加的是叶子结点之间的指针。通过B树去划分区间,在叶子结点可以通过指针进行范围遍历。
  • 结点的key按升序进行排列

image-20200724142917226

  • 查找:先从根节点开始进行二分查找,再在指针的位置上递归进行查找。直到找出key所对应的data

  • 与红黑树对比:

    • (数据结构)B+树的高度更低:有效的减少了指针向下递归的层树。红黑树出度为2,而B+树的出度会很多
    • (硬件优化)磁盘读写快:磁盘寻道的次数与树高成正比,在同一个磁盘块上访问只需要很短的磁盘旋转时间
      • 可以借助磁盘的预读特性,将相邻的节点也预先载入(通过底层的连接指针)

MySQL索引

  1. B+ 树索引:
    • 不需要全表扫描,只需要进行树的搜索
    • 基于B+Tree的有序特性,除了查找以外,还可以进行排序和分组(通过范围查找)
    • InnoDB索引分类:
      • 主索引(聚簇索引):叶子结的data域包含了完整的数据记录。即存储的行数据
        • 一个表只能有一个聚簇索引。因为不能把数据存储在两个不同的地方(区别MyISAM)
        • 如果没有定义主键,InnoDB引擎会隐式的定义一个主键来作为聚簇索引
          • 聚簇索引性能最好而且具有唯一性。如果没有特别的需要,请永远使用一个与业务无关的自增字段作为主键。
          • 顺序添加可以有效利用每个页的存储空间,对页进行顺序填满。不然会导致页出现空位,占用额外的存储空间
          • 数据页通过双向链表进行连接
        • 缺点:聚簇索引新值的插入会比较慢 – 树的平衡操作较为复杂。
          • 插入速度依赖于插入顺序 – 按主键顺序插入最快,否则将会出现页分裂(自增ID)
        • image-20200724143723245
        • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VNyn1aba-1595730754095)(https://blog.codinglabs.org/uploads/pictures/theory-of-mysql-index/10.png)]
      • 辅助索引(非聚簇索引):叶子结点的data域包含主索引的主键值。需要先查找到主键值,然后再在主索引中进行查找
        • 索引结构的叶子节点指向了数据的对应行。
        • 辅助索引只保存主键值,占用空间小。当表需要建立多级索引的时候,比聚簇索引好(建立聚簇索引相当于又建立一个新表)
      • image-20200724143902801

MyISAM引擎采用的是非聚簇索引,两棵B+树没有不同,结点的结构完全一致。

  • 表数据存储在独立的地方,这两颗B+树的叶子节点都使用一个地址指向真正的表数据,对于表数据来说,这两个键没有任何差别。
  • 主索引要求key唯一,辅助索引的key可以重复
  • 由于索引树是独立的,通过辅助键检索无需访问主键的索引树
  • 由于MyISAM采用非聚簇索引,数据的物理地址是离散的,存储的是数据的指针,导致硬盘IO需要花费大量的寻道时间进行查找。而InnoDB的只需一次IO,因为其数据都是顺序分布在磁盘上的。
  • 以下是MyISAM的索引实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O6uNxBqu-1595730754100)(https://blog.codinglabs.org/uploads/pictures/theory-of-mysql-index/8.png)]

不建议大量使用索引的原因:

  • 索引会消耗存储空间,同时会加重CRUD的负担,MYSQL在运行时要消耗资源维护索引
    • 当记录较少(<=2000),不需要建立索引,可以直接做全表扫描。超过2000条需要酌情考虑
    • 选择需要经常查询的列建立索引

百万索引测试:

CREATE TABLE `app_user` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT '',
`email` varchar(50) NOT NULL,
`phone` varchar(20) DEFAULT '',
`gender` tinyint(4) unsigned DEFAULT '0',
`password` varchar(100) NOT NULL DEFAULT '',
`age` tinyint(4) DEFAULT NULL,
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

-- 插入100万数据.
DELIMITER $$
-- 写函数之前必须要写,标志
CREATE FUNCTION mock_data ()
RETURNS INT
BEGIN
DECLARE num INT DEFAULT 1000000;
DECLARE i INT DEFAULT 0;
WHILE i<num DO
INSERT INTO `app_user`(`name`,`eamil`,`phone`,`gender`)VALUES(CONCAT('用户',i),'19224305@qq.com','123456789',FLOOR(RAND()*2));
SET i=i+1;
END WHILE;
RETURN i;
END;

SELECT mock_data() -- 执行此函数 生成一百万条数据
explain select * from app_user where name='用户9999'
  • 不加索引之前(我这里是因为之前不小心创建了两次函数):
  • 无索引的查找会从头到尾扫描一遍,效果很差

image-20200724160837225

时间:2 rows retrieved starting from 1 in 1 s 119 ms (execution: 1 s 93 ms, fetching: 26 ms)

大概花了1s左右。

建立索引:

create index id_app_user_name on app_user(`name`)
 -- 格式 create index index_name on  table_name(`column_name`)

再次执行查询:

时间:2 rows retrieved starting from 1 in 42 ms (execution: 5 ms, fetching: 37 ms)

只查找了两行。正常应该是只有一行,我之前瞎搞了一下。

image-20200724161132490

总结分析:

回到上文。建立索引,相当于是在内存再次建立了一个数据结构,为这一列单独建立了一棵B+树,从而减少了在聚簇索引中遍历查找的行数。先通过name建立的辅助索引B+树中去找到主键,再根据主键去寻找聚簇索引中的具体值。

哈希索引

可以将查找的时间复杂度降低到o(1),但是不利于顺序查找。

  • 不能进行排序与分组。只支持精确查找,无法用于模糊搜索和范围查找

InnoDB支持**“自适应哈希索引”**,每当某个索引值被频繁引用,会在B+树上创建一个哈希索引

全文索引

MyISAM支持全文索引。MYSQL在5.6过后也支持全文索引

select * from app_user where MATCH(name) AGAINST ('用户9999')

索引顺序性要求

让选择性最强的索引列放在前面:不重复的索引值和记录总数的比值越大,选择性越强。

前缀索引

对于BLOB,TEXT,VARCHAR等,必须使用前缀索引,只索引开始的部分字符。

覆盖索引

可以理解为叶子结点包含了该索引列的值。InnoDB可以通过直接访问索引来获取数据,而不需要再在聚集索引中查找

查询性能优化

  1. 使用Explain找到被拖慢的原因

  2. 优化数据访问

    • 减少数据量 :
      • 尽量不要使用 select *
      • 使用limit来截断数据
      • 合理利用缓存,避免在数据库中进行查询
    • 减少服务端扫描行数:通过索引来覆盖查询
  3. 重构查询方式:

    • 切分大查询:一次大查询一次性执行会锁住很多数据,占满整个事务日志,拖慢性能

    •  -- 切分成多次查询
      rows_affected = 0
      do {
          rows_affected = do_query(
          "DELETE FROM messages WHERE create  < DATE_SUB(NOW(), INTERVAL 3 MONTH) LIMIT 10000")
      } while rows_affected > 0
      
    • 将联表查询在应用程序中转换成单表查询:

      • 有效利用缓存,如果联表中有一个表数据被修改,那么缓存不可用
      • 减少锁竞争
      • 应用层可以实现更灵活的数据拆分

存储引擎

InnoDB
  1. 事务性引擎
  2. 默认级别是Repeatable Read:通过MVCC + Next-Key Lock来实现
  3. 聚簇索引+辅助索引
  4. 内部优化:磁盘预读,自适应哈希索引,插入缓冲区
  5. 在线热备份
  6. 支持行锁
MyISAM
  1. 提供压缩表,空间数据索引等特性
  2. 不支持事务
  3. 只能对整个表加锁
  4. 容易发生数据的崩溃

数据库切分

  1. **水平切分:将一个表中的记录拆分到多个结构相同的表中

image-20200726102856470

  1. 垂直切分:将一张表按列切分成多个表,通常是按照列的关系密集程度进行切分

image-20200726102926541

主从复制+读写分离,这个和Redis差不多

image-20200726103021193

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值