MySQL浓缩笔记(1)-基础篇

文章笔记主要引用:

阿秀的学习笔记 (interviewguide.cn)

小林coding (xiaolincoding.com)

关系型和非关系型数据库的区别你了解多少?

  • 关系型数据库的优点
    • 容易理解。因为它采用了关系模型来组织数据。
    • 可以保持数据的一致性。
    • 数据更新的开销比较小。
    • 支持复杂查询(带where子句的查询)
  • 非关系型数据库的优点
    • 不需要经过SQL层的解析,读写效率高。
    • 基于键值对,数据的扩展性很好。
    • 可以支持多种类型数据的存储,如图片,文档等等。

什么是非关系型数据库?

非关系型数据库也叫NOSQL,采用键值对的形式进行存储。

它的读写性能很高,易于扩展,可分为内存性数据库以及文档型数据库,比如 Redis,Mongodb,HBase等等。

适合使用非关系型数据库的场景:

  • 日志系统
  • 地理位置存储
  • 数据量巨大
  • 高可用

说一下MySQL是如何执行一条SQL的?具体步骤有哪些?

Server层按顺序执行sql的步骤为:

  1. 客户端请求->
  2. 连接器(验证用户身份,给予权限) ->
  3. 查询缓存(存在缓存则直接返回,不存在则执行后续操作)->
  4. 分析器(对SQL进行词法分析(构建语法树)和语法分析操作) ->
  5. 预处理器(检查 SQL 查询语句中的表或者字段是否存在;将 select * 中的 * 符号,扩展为表上的所有列;)->
  6. 优化器(主要对执行的sql优化选择最优的执行方案方法) ->
  7. 执行器(执行时会先看用户是否有执行权限,有才去使用这个引擎提供的接口)->
  8. 去引擎层获取数据返回(如果开启查询缓存则会缓存查询结果)

你了解MySQL的内部构造吗?一般可以分为哪两个部分?

可以分为server层和存储引擎层两部分,其中:

server层包括连接器、查询缓存、解析器、预处理器、优化器、执行器等,涵盖MySQL的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。

存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持InnoDB、MyISAM、Memory等多个存储引擎。现在最常用的存储引擎是InnoDB,它从MySQL 5.5.5版本开始成为了默认的存储引擎。

MySQL优化了解吗?说一下从哪些方面可以做到性能优化?

  • 为搜索字段创建索引
  • 避免使用 Select *,列出需要查询的字段
  • 垂直分割分表
  • 选择正确的存储引擎

听说过视图吗?那游标呢?

视图是基于 SQL 语句的结果集的可视化的表。

游标是系统为用户开设的一个数据缓冲区,存放SQL语句的执行结果。每个游标区都有一个名字,用户可以用SQL语句逐一从游标中获取记录,并赋给主变量,交由主语言进一步处理。

视图的作用是什么?可以更改吗?

视图是虚拟的表,与包含数据的表不一样,视图只包含使用时动态检索数据的查询;不包含任何列或数据。使用视图可以简化复杂的 sql 操作,隐藏具体的细节,保护数据;视图创建后,可以使用与表相同的方式利用它们。

视图不能被索引,也不能有关联的触发器或默认值,如果视图本身内有order by 则对视图再次order by将被覆盖。

创建视图:create view xxx as xxxx

对于某些视图比如未使用联结子查询分组聚集函数Distinct Union等,是可以对其更新的,对视图的更新将对基表进行更新;但是视图主要用于简化检索,保护数据,并不用于更新,而且大部分视图都不可以更新。

MySQL常见的存储引擎InnoDB、MyISAM的区别?适用场景分别是?

1)事务:MyISAM不支持,InnoDB支持 2)锁级别: MyISAM 表级锁,InnoDB 行级锁及外键约束 3)MyISAM存储表的总行数;InnoDB不存储总行数; 4)MyISAM采用非聚集索引,B+树叶子存储指向数据文件的指针。InnoDB主键索引采用聚集索引,B+树叶子存储数据;5)备份: InnoDB 支持在线热备份,要获取一致性视图不需要停止对所有表的写入。而MyISAM不支持。

适用场景: MyISAM适合: 插入不频繁,查询非常频繁,如果执行大量的SELECT,MyISAM是更好的选择, 没有事务。 InnoDB适合: 可靠性要求比较高,或者要求事务; 表更新和查询都相当的频繁, 大量的INSERT或UPDATE

你知道哪些数据库结构优化的手段?

  • 范式优化: 比如消除冗余(节省空间。。)
  • 反范式优化:比如适当加冗余等(减少join)
  • 限定数据的范围: 务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内。
  • 读/写分离: 经典的数据库拆分方案,主库负责写,从库负责读;
  • 拆分表:分区将数据在物理上分隔开,不同分区的数据可以制定保存在处于不同磁盘上的数据文件里。这样,当对这个表进行查询时,只需要在表分区中进行扫描,而不必进行全表扫描,明显缩短了查询时间,另外处于不同磁盘的分区也将对这个表的数据传输分散在不同的磁盘I/O,一个精心设置的分区可以将数据传输对磁盘I/O竞争均匀地分散开。对数据量大的时时表可采取此方法。可按月自动建表分区。

数据库为什么要进行分库和分表呢?都放在一个库或者一张表中不可以吗?

分库与分表的目的在于,减小数据库的单库单表负担,提高查询性能,缩短查询时间

通过分表,可以减少数据库的单表负担,同时因为不同的表上的数据量少了,提高了查询性能。此外,可以很大的缓解表锁的问题。 分表策略可以归纳为垂直拆分和水平拆分: 水平分表:取模分表就属于随机分表,而时间维度分表则属于连续分表。 如何设计好垂直拆分,我的建议:将不常用的字段单独拆分到另外一张扩展表. 将大文本的字段单独拆分到另外一张扩展表, 将不经常修改的字段放在同一张表中,将经常改变的字段放在另一张表中。 对于海量用户场景,可以考虑取模分表,数据相对比较均匀,不容易出现热点和并发访问的瓶颈。

库内分表,仅仅是解决了单表数据过大的问题,但并没有把单表的数据分散到不同的物理机上,因此并不能减轻 MySQL 服务器的压力,仍然存在同一个物理机上的资源竞争和瓶颈,包括 CPU、内存、磁盘 IO、网络带宽等。

分库与分表带来的分布式困境与应对之策 数据迁移与扩容问题----一般做法是通过程序先读出数据,然后按照指定的分表策略再将数据写入到各个分表中。 分页与排序问题----需要在不同的分表中将数据进行排序并返回,并将不同分表返回的结果集进行汇总和再次排序,最后再返回给用户。

数据库优化中有一个比较常用的手段就是把数据表进行拆分,关于拆分数据表你了解哪些?

拆分其实又分垂直拆分水平拆分

案例: 简单购物系统暂设涉及如下表:

1.产品表(数据量10w,稳定)

2.订单表(数据量200w,且有增长趋势)

3.用户表 (数据量100w,且有增长趋势)

以 MySQL 为例讲述下水平拆分和垂直拆分,MySQL能容忍的数量级在百万静态数据可以到千万

垂直拆分

解决问题:表与表之间的io竞争

不解决问题:单表中数据量增长出现的压力

方案: 把产品表和用户表放到一个server上 订单表单独放到一个server上

水平拆分

解决问题:单表中数据量增长出现的压力

不解决问题:表与表之间的io争夺

方案:用户表 通过性别拆分为男用户表和女用户表,订单表 通过已完成和完成中拆分为已完成订单和未完成订单,产品表 未完成订单放一个server上,已完成订单表盒男用户表放一个server上,女用户表放一个server上(女的爱购物 哈哈)。

一道场景题:假如你所在的公司选择MySQL数据库作数据存储,一天五万条以上的增量,预计运维三年,你有哪些优化手段?

  • 设计良好的数据库结构,允许部分数据冗余,尽量避免join查询,提高效率。
  • 选择合适的表字段数据类型和存储引擎,适当的添加索引。
  • MySQL库主从读写分离
  • 规律分表,减少单表中的数据量提高查询速度。
  • 添加缓存机制,比如Memcached,Apc等。
  • 不经常改动的页面,生成静态页面
  • 书写高效率的SQL。比如 SELECT * FROM TABEL 改为 SELECT field_1, field_2, field_3 FROM TABLE。

数据库中的主键、超键、候选键、外键是什么?(很棒)

  • 超键:在关系中能唯一标识元组的属性集称为关系模式的超键

  • 候选键:不含有多余属性的超键称为候选键。也就是在候选键中,若再删除属性,就不是键了!

  • 主键用户选作元组标识的一个候选键称为主键

  • 外键:如果关系模式R中属性K是其它模式的主键,那么k在模式R中称为外键

举例

学号 姓名 性别 年龄 系别 专业
20020612 李辉 20 计算机 软件开发
20060613 张明 18 计算机 软件开发
20060614 王小玉 19 物理 力学
20060615 李淑华 17 生物 动物学
20060616 赵静 21 化学 食品化学
20060617 赵静 20 生物 植物学
  1. 超键:于是我们从例子中可以发现 学号是标识学生实体的唯一标识。那么该元组的超键就为学号。除此之外我们还可以把它跟其他属性组合起来,比如:(学号性别),(学号年龄)
  2. 候选键:根据例子可知,学号是一个可以唯一标识元组的唯一标识,因此学号是一个候选键,实际上,候选键是超键的子集,比如 (学号,年龄)是超键,但是它不是候选键。因为它还有了额外的属性。
  3. 主键:简单的说,例子中的元组的候选键为学号,但是我们选定他作为该元组的唯一标识,那么学号就为主键。
  4. 外键是相对于主键的,比如在学生记录里,主键为学号,在成绩单表中也有学号字段,因此学号为成绩单表的外键,为学生表的主键。

主键为候选键的子集,候选键为超键的子集,而外键的确定是相对于主键的。

数据库三大范式精讲

第一范式

在任何一个关系数据库中,第一范式(1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据库。 所谓第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。

如果出现重复的属性,就可能需要定义一个新的实体,新的实体由重复的属性构成,新实体与原实体之间为一对多关系。在第一范式(1NF)中表的每一行只包含一个实例的信息。

简而言之,第一范式就是无重复的列

第二范式

第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。第二范式(2NF)要求数据库表中的每个实例或行必须可以被惟一地区分

为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。这个惟一属性列被称为主关键字或主键、主码。 第二范式(2NF)要求实体的属性完全依赖于主关键字。

所谓完全依赖是指不能存在仅依赖主关键字一部分的属性,如果存在,那么这个属性和主关键字的这一部分应该分离出来形成一个新的实体,新实体与原实体之间是一对多的关系。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。

简而言之,有主键,非主键字段依赖主键

第三范式

满足第三范式(3NF)必须先满足第二范式(2NF)。简而言之,第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。

例如,存在一个部门信息表,其中每个部门有部门编号(dept_id)、部门名称、部门简介等信息。那么在员工信息表中列出部门编号后就不能再将部门名称、部门简介等与部门有关的信息再加入员工信息表中。如果不存在部门信息表,则根据第三范式(3NF)也应该构建它,否则就会有大量的数据冗余。

简而言之,非主键字段不能相互依赖。

1NF:原子性。 字段不可再分,否则就不是关系数据库; 

2NF:唯一性 。一个表只说明一个事物;   

3NF:每列都与主键有直接关系,不存在传递依赖。

数据库如何保证持久性?

主要是利用Innodb的redo log。重写日志, 正如之前说的,MySQL是先把磁盘上的数据加载到内存中,在内存中对数据进行修改,再写回到磁盘上。如果此时突然宕机,内存中的数据就会丢失。 怎么解决这个问题? 简单啊,事务提交前直接把数据写入磁盘就行啊。 这么做有什么问题?

  • 只修改一个页面里的一个字节,就要将整个页面刷入磁盘,太浪费资源了。毕竟一个页面16kb大小,你只改其中一点点东西,就要将16kb的内容刷入磁盘,听着也不合理。
  • 毕竟一个事务里的SQL可能牵涉到多个数据页的修改,而这些数据页可能不是相邻的,也就是属于随机IO。显然操作随机IO,速度会比较慢。

于是,决定采用redo log解决上面的问题。当做数据修改的时候,不仅在内存中操作,还会在redo log中记录这次操作。当事务提交的时候,会将redo log日志进行刷盘(redo log一部分在内存中,一部分在磁盘上)。当数据库宕机重启的时候,会将redo log中的内容恢复到数据库中,再根据undo logbinlog内容决定回滚数据还是提交数据。

采用redo log的好处?

其实好处就是将redo log进行刷盘比对数据页刷盘效率高,具体表现如下:

  • redo log体积小,毕竟只记录了哪一页修改了啥,因此体积小,刷盘快。
  • redo log是一直往末尾进行追加,属于顺序IO。效率显然比随机IO来的快。

数据库高并发是我们经常会遇到的,你有什么好的解决方案吗?

  • 在web服务框架中加入缓存。在服务器与数据库层之间加入缓存层,将高频访问的数据存入缓存中,减少数据库的读取负担。
  • 增加数据库索引,进而提高查询速度。(不过索引太多会导致速度变慢,并且数据库的写入会导致索引的更新,也会导致速度变慢)
  • 主从读写分离,让主服务器负责写,从服务器负责读。
  • 将数据库进行拆分,使得数据库的表尽可能小,提高查询的速度。
  • 使用分布式架构,分散计算压力。

MySQL分库分表之后怎么确保每个表的id都是唯一的?

可以使用雪花算法来生成分布式 id,它会生成一个 64 bit 的整数,可以保证不同进程主键的不重复性,以及相同进程主键的有序性。

图片

雪花算法

在同一个进程中,它首先是通过时间位保证不重复,如果时间相同则是通过序列位保证。同时由于时间位是单调递增的,且各个服务器如果大体做了时间同步,那么生成的主键在分布式环境可以认为是总体有序的,这就保证了对索引字段的插入的高效性。

但是雪花算法有缺点,雪花算法是强依赖于时间的,而如果机器时间发生回拨,有可能会生成重复的 ID。可以用美团提供的分布式 ID 解决方案 Leaf,他是不依赖时间戳的,

猜你喜欢

转载自blog.csdn.net/shisniend/article/details/131869669