mysql笔记

mysql笔记

  • 内容摘自
  • 存储引擎是什么
  • InnoDB存储引擎
    • 行格式
      • InnoDB页是什么
      • 页目录(重点)
      • 页的总结构(除了记录和页目录外的部分了解即可)
    • 索引(原理:B+树)
      • 回顾
      • 页之间的关系
      • 索引实现
      • 聚簇索引
    • 二级索引
      • 用处
      • 查找方式
    • MySQL中创建和删除索引的语句
      • 建立索引与删除索引
  • MySQL 重点语法
    • 内容摘自
    • 分组
      • GROUP BY(数据分组)
      • HAVING(过滤分组)
      • ORDER BY(分组与排序)
    • 子查询
      • 利用子查询进行过滤

内容摘自

《mysql是怎样运行的:从根儿上理解mysql》

存储引擎是什么

mysql服务器把数据的存储和提取操作都封装到了一个叫存储引擎的模块里。我们知道表是由一行行记录组成的,但这只是一个逻辑的概念。物理上如何表示记录,怎么从表中读取数据,怎么把数据写入具体的物理存储器上,这些都是存储引擎负责的。为了实现不同的功能,mysql提供了各式各样的存储引擎。

InnoDB存储引擎

行格式

mysql笔记_第1张图片

  • 变长字段列表:mysql支持一些变长的数据类型(变长字段),比如varchar(M)、varbinary(M)、TEXT类型、BLOB类型。这些变长字段占用的存储空间分为两部分:
    • 1.真正的数据内容
    • 2.占用的字节数
  • NULL值列表:我们知道表中的这些列可能存储NULL值,如果把这些NULL值存放到记录的真实数据中存储会很占地方,所以用字节的位来表示这些NULL值。
  • 记录头信息:由5个字节,也就是40个二进制位,不同的位代表不同的意思。
    mysql笔记_第2张图片
    • delete_mask: 标记该记录是否被删除。
    • min_rec_mask: B+树的每层非叶子结点中的最小记录都会添加该标记。
    • record_type: 表示当前记录的类型,0表示普通,1表示B+树非叶子节点记录2表示最小记录3表示最大记录
    • next_record: 表示下一条记录的相对位置

InnoDB页是什么

  • 页是InnoDB管理存储空间的基本单位,一个页的大小一般是16KB。我们现在聚集的是存放我们表中记录的那种类型的页,官方称这种存放记录的页为索引(INDEX)页,这些表中的记录就是我们日常口中所称的数据,目前还是叫这种存放记录的页为数据页
  • 数据页中的记录按照主键从小到大的顺序形成了一个单链表
    mysql笔记_第3张图片

页目录(重点)

  • 前面我们提到:页中的记录按照主键从小到大的顺序形成了一个单链表。如果要找到一个主键对应的记录,依次遍历非常慢( O(n) )。
  • 设计师这样子设计了一个页的目录:
    • 将所有正常的记录(包括最大和最小记录,不包括标记为已删除的记录)划分为几个组
    • 每个组的最后一条记录(组内最大的那条记录)的头信息中的n_owned属性表示该组内拥有多少条记录
    • 将每个组的最后一条记录的地址偏移量next_record单独提取出来,按顺序存储到靠近页的尾部的地方,这就是页目录(Page Directory)。页面目录中的这些地址偏移量称为槽(Slot),所以这个页目录由槽组成
      mysql笔记_第4张图片
  • 记录数多的时候是这样子:
    mysql笔记_第5张图片
  • 查找算法(二分查找如下)O(logn):假如说我们要找主键值为6的记录
    • height = 槽4,low = 槽0。
    • mid =(槽0+槽4)/2 = 槽2,而槽2对应的记录的主键值为8,主键8>主键6,所以设置 height = mid = 2。
    • mid = (槽0 + 槽2) /2 = 槽1,而槽1对应的记录的主键值为4,主键4< 主键6,所以设置low = mid = 1。
    • 因为 height - low = 1 (主键6肯定不在槽low,那只能在槽height了),所以主键在槽2。
    • 遍历槽2,找到了主键6对应的记录。

页的总结构(除了记录和页目录外的部分了解即可)

  • File Header,表示页的一些通用信息,占固定的38个字节。
  • Page Header,表示数据页专有的一些信息,占固定的56个字节。
  • Infimum + Supremum,两个虚拟的伪记录,分别表示页中的最小和最大记录,占固定的26个字节。
  • User Records,真实存储我们插入的记录的部分,大小不固定。
  • Free Space,页中尚未使用的部分,大小不确定。
  • Page Directory,页中的某些记录相对位置,用于快速找到主键对应的记录,插入的记录越多,槽越多,页目录占的空间越多。
  • File Trailer,用于检验页是否完整的部分,占用固定的8个字节。

索引(原理:B+树)

回顾

mysql笔记_第6张图片

  • 前面我们提到了InnoDB页的七个组成部分,现在概括一下页的重要点:
    • 各个数据页之间可以组成一个双向链表,页a、页b、页c…页n这些页可以不在物理结构上相连,只要通过双向链表相关联即可。
    • 数据页中的记录会按照主键值从小到大的顺序组成一个单向链表
    • 每个数据页都会为存储在它里边儿的记录生成一个页目录在通过主键查找某条记录的时候,可以在页目录中使用二分法快速定位到对应的槽,然后再遍历该槽对应分组中的记录,即可快速找到主键对应的记录。

页之间的关系

  • 对页中的记录进行增删改查的过程中,我们通过一些诸如记录移动的操作来始终保持了这个状态一直成立:下一个数据页中用户记录的主键值必须大于上一个页中的用户记录的主键值。这个过程我们可以称为页分裂
    mysql笔记_第7张图片

索引实现

  • 我们把每个页中的两个元素提取出来,分别形成一个目录项:
    • 页的用户记录的主键的最小值。(页10是1,页28是5,页9是12,页20是209)
    • 页号,page_no(10,28,9,20)
      mysql笔记_第8张图片
    • 假如说我们要找主键值为20的记录:
      1.找到该记录所在的
      2.在该页中根据页目录找到该条记录(前面学过)
    • 我们可以用二分法来找到这条记录所在的页
      • low = 目录项1,height = 目录项4
      • mid = (low+height)/2 = 目录项2,而目录项2的key = 5 < 20,所以low = 目录项2。
      • mid = (low+height)/2 = 目录项3,而目录项3的key =12 < 20,所以low = 目录项3。
      • height - low = 1,所以主键值为20的记录肯定在目录项3中,而目录项3的页号是9,我们就找到了记录所在的页。
    • 这些目录项我们会另外放到另一层的页中。
      mysql笔记_第9张图片
    • 目录项记录的record_type为1。
    • 目录项记录很多的时候,我们会新生成页来存放目录项,如果我们表中的数据非常多的话,则会产生很多存储目录项记录的页,那么我们怎么快速定位一个存储目录项的页呢。答案是生成一个更高层级的目录,就像是一个多级目录一样,从1级目录到2级目录,再到3级目录,最后一级存放的才是我们的数据。
      mysql笔记_第10张图片
  • 简化成下面这张图,这就是我们所说的B+树
    mysql笔记_第11张图片

聚簇索引

  • 我们上面所说的目录项页+数据页形成的B+树就是我们经常听到的聚簇索引,这种索引有以下两个特点:
  1. 使用记录的主键值的大小,进行记录和页的排序,这包括了三部分的含义。
    • 页内的记录是按照主键的大小顺序排成一个单向链表
    • 各个存放记录的页(数据页)也是,根据页中记录的主键大小顺序,排成一个双向链表
    • 存放目录项记录的页——目录项页分为不同的层次,在同一层次的页也是根据页中目录项记录的主键大小顺序,排成一个双向链表
  2. B+树的叶子节点存储的是完整的用户记录。
  • InnoDB存储引擎会自动地为我们创建聚簇索引(强迫表需要有主键),也就是说,在InnoDB存储引擎中,聚簇索引就是数据的存储方式了(所有记录都在B+树的叶子节点),这也就是所谓的索引即数据,数据即索引。
  1. 聚簇索引的目的是通过主键来快速寻找主键所在的记录

二级索引

用处

  • 上边介绍的聚簇索引只能在搜索条件的主键值时才能发挥作用,因为B+树的记录都是按照主键进行排序的。那如果我们想以别的列作为搜索条件该咋办呢?
  • 我们可以多键几棵B+树,不同的B+树采用不同的排序规则
  • 比方说我们用C2列的大小作为数据页、页中记录的排序规则,再建一颗B+树,如下:
    mysql笔记_第12张图片
  • 这棵树的目录项由三个部分构成:
    • 索引列的值(指向的页的索引列的最小值
    • 主键值(指向的页的主键的最小值
    • 页号
  • 这棵树有如下特点:
    • 叶子节点由索引列的值和主键号组成

查找方式

  • 我们还可以和聚簇索引一样找到c2对应的记录,不过因为c2的列不是唯一的,所以查找到的记录也不唯一。
  • 而且我们查找到的是(c2列的值+主键值),还要通过主键的值到聚簇索引中再查找一遍完整的记录(回表操作)。

MySQL中创建和删除索引的语句

建立索引与删除索引

/*创建表的时候指定需要建立索引的单个列或者建立联合索引的多个列*/
CREATE TABLE 表名 (
	各种列的信息 。。。,
	[KEY|INDEX] 索引名(需要被索引的单个列或多个列)
)
/*举例*/
CREATE TABLE index_demo(
	c1 INT,
	c2 INT,
	c3 CHAR(1),
	PRIMARY KEY(c1),
	INDEX idx_c2_c3 (c2,c3)
);
/*这个建表语句中我们创建的索引名是idx_c2_c3, 这个名称可以随便起,不过我们还是建议以idx_为前缀*/

/*ALTER 添加索引*/
ALTER TABLE index_demo ADD INDEX idx_c2_c3 (c2,c3);

/*删除索引*/
ALTER TABLE index_demo DROP INDEX idx_c2_c3;

MySQL 重点语法

内容摘自

《MySQL必知必会》

分组

GROUP BY(数据分组)

  • 下面的例子返回供应商1003提供的产品数目
SELECT COUNT(*) AS num_prods FROM products WHERE vend_id = 1003;

mysql笔记_第13张图片

  • 如果我们要获得每一个供应商提供的产品数目怎么办(group by)?或者返回只提供单项产品的供应商的供应商所提供的产品,或者返回提供10个以上产品的供应商怎么办(having)?
SELECT vend_id, COUNT(*) AS num_prods FROM products GROUP BY vend_id;
  • 上面的SELECT 语句指定了两个列,vend_id指定供应商的ID,num_prods为计算字段。GROUP BY子句指示MySQL按vend_id排序并分组数据。这导致对每个vend_id而不是整个表计算num_prods一次
  • 使用GROUP BY语句还有如下规定:
    mysql笔记_第14张图片

HAVING(过滤分组)

  • 下面的语句返回有两个订单以上的顾客id:
SELECT cust_id, COUNT(*) AS orders FROM orders GROUP BY cust_id HAVING COUNT(*) >= 2;
  • 如何理解HAVING 和 WHERE的区别。
    mysql笔记_第15张图片

  • 为了更好地理解HAVING和GROUP BY的区别,我们来看下面的例子:它列出具有2个(含)以上、价格为10(含)以上的产品的供应商:

SELECT vend_id,COUNT(*) AS num_prods FROM products WHERE prod_price >= 10 GROUP BY vend_id HAVING COUNT(*) >= 2;
  • 这句SQL先用WHERE prod_price >= 10过滤得到价格>=10的行然后对这些行按vend_id,COUNT(*)进行分组,最后通过HAVING 过滤出COUNT(*)>=2的分组
    mysql笔记_第16张图片

ORDER BY(分组与排序)

mysql笔记_第17张图片

  • 为说明GROUP BY 和ORDER BY 的搭配使用方法,请看一个例子。它检索总计订单价格大于等于50的订单号和总计订单价格
SELECT order_num, SUM(quantity*item_price) AS ordertotal FROM orderitems GROUP BY order_num HAVING SUM(quantity*item_price) >= 50;

mysql笔记_第18张图片

  • 为按总计订单价格排序输出,我们只需要在其后面添加ORDER BY 子句即可:
SELECT order_num, SUM(quantity*item_price) AS ordertotal FROM orderitems GROUP BY order_num HAVING SUM(quantity*item_price) >= 50 ORDER BY ordertotal;

子查询

利用子查询进行过滤

  • 介绍一下一些表
    • 订单表(orders表):存储每一个订单的标志性信息,如订单ID、客户ID、订单日期。
    • 订单物品表(orderitems表):存储每一个订单的物品项信息,如订单ID、订单物品号、产品ID、物品数量、物品价格。
    • 客户表(customers表):存储每一个客户的全部信息。

你可能感兴趣的:(数据库,mysql,数据库,java)