一个典型的互联网产品架构包含接入层、逻辑处理层以及存储层,其中存储层承载着数据落地和持久化的任务,同时给逻辑处理层提供数据查询功能支持。说到存储层就要说到数据库,数据库知识掌握程度也是面试考察的知识点。
典型服务架构
数据库分为关系型数据库和非关系型数据库,也就是我们常说的 SQL 和 NoSQL,这两个方向的数据库代表产品分别是 MySQL 和 Redis ,这次我们主要以面试问答的形式,来学习下关系型数据库 MySQL 基础知识。
面试开始,准备接受面试官灵魂拷问吧!
关系型数据库,是指采用了关系模型来组织数据的数据库,其以行和列的形式存储数据,以便于用户理解,关系型数据库这一系列的行和列被称为表,一组表组成了数据库。用户通过查询来检索数据库中的数据,而查询是一个用于限定数据库中某些区域的执行代码。
简单来说,关系模式就是二维表格模型。
关系型数据库的优势:
结构化查询语言 (Structured Query Language) 简称 SQL,是一种特殊目的的编程语言,是一种数据库查询和程序设计语言程序设计语言,用于存取数据以及查询、更新和管理关系数据库系统。
MySQL 是一个关系型数据库管理系统,MySQL 是最流行的关系型数据库管理系统之一,常见的关系型数据库还有 Oracle 、SQL Server、Access 等等。
MySQL在过去由于性能高、成本低、可靠性好,已经成为最流行的开源数据库,广泛地应用在 Internet 上的中小型网站中。
MySQL 最初由瑞典 MySQL AB 公司开发,MySQL 的创始人是乌尔夫·米卡埃尔·维德纽斯,常用昵称蒙提(Monty)。
在被甲骨文公司收购后,现在属于甲骨文公司(Oracle) 旗下产品。Oracle 大幅调涨 MySQL 商业版的售价,因此导致自由软件社区们对于 Oracle 是否还会持续支持 MySQL 社区版有所隐忧。
MySQL 的创始人就是之前那个叫 Monty 的大佬以 MySQL 为基础成立分支计划 MariaDB。
MariaDB 打算保持与 MySQL 的高度兼容性,确保具有库二进制奇偶校验的直接替换功能,以及与 MySQL API (应用程序接口)和命令的精确匹配,而原先一些使用 MySQL 的开源软件逐渐转向 MariaDB 或其它的数据库。
所以如果看到你公司用的是 MariaDB 不用怀疑,其实它骨子里还是 MySQL,学会了MySQL 也就会了 MariaDB。
MariaDB 是以 Monty 的小女儿 Maria 命名的,就像 MySQL 是以他另一个女儿 My 命名的一样,两款鼎鼎大名的数据库分别用两个女儿的名字命名,老爷子厉害!
在系统命令行下:mysql -V
连接上MySQL命令行输入:
> status;
Server: MySQLServer version: 5.5.45Protocol version: 10
或 select version;
+------------------------+| version |+------------------------+| 5.5.45-xxxxx |+------------------------+
MySQL 数据类型非常丰富,常用类型简单介绍如下:
整数类型:BIT、BOOL、TINY INT、SMALL INT、MEDIUM INT、 INT、 BIG INT。
浮点数类型:FLOAT、DOUBLE、DECIMAL。
字符串类型:CHAR、VARCHAR、TINY TEXT、TEXT、MEDIUM TEXT、LONGTEXT、TINY BLOB、BLOB、MEDIUM BLOB、LONG BLOB。
日期类型:Date、DateTime、TimeStamp、Time、Year。
其他数据类型:BINARY、VARBINARY、ENUM、SET…
CHAR 是固定长度的字符类型,VARCHAR 则是可变长度的字符类型,下面讨论基于在 MySQL5.0 以上版本中。
CHAR(M) 和 VARCHAR(M) 都表示该列能存储 M 个字符,注意不是字节!!
存放的汉字个数与版本相关。
mysql 4.0 以下版本,varchar(50) 指的是 50 字节,如果存放 UTF8 格式编码的汉字时(每个汉字3字节),只能存放16 个。
mysql 5.0 以上版本,varchar(50) 指的是 50 字符,无论存放的是数字、字母还是 UTF8 编码的汉字,都可以存放 50 个。
不一样,具体原因如下:
所以能存储的数据大小不一样,其中的数字 10 代表的只是数据的显示宽度。[^13]
常用的存储引擎有 InnoDB 存储引擎和 MyISAM 存储引擎,InnoDB 是 MySQL 的默认事务引擎。
查看数据库表当前支持的引擎,可以用下面查询语句查看 :
# 查询结果表中的 Engine 字段指示存储引擎类型。show table status from 'your_db_name' where name='your_table_name';
InnoDB 是 MySQL 的默认「事务引擎」,被设置用来处理大量短期(short-lived)事务,短期事务大部分情况是正常提交的,很少会回滚。
采用多版本并发控制(MVCC,MultiVersion Concurrency Control)来支持高并发。并且实现了四个标准的隔离级别,通过间隙锁 next-key locking 策略防止幻读的出现。
引擎的表基于聚簇索引建立,聚簇索引对主键查询有很高的性能。不过它的二级索引 secondary index 非主键索引中必须包含主键列,所以如果主键列很大的话,其他的所有索引都会很大。因此,若表上的索引较多的话,主键应当尽可能的小。另外 InnoDB 的存储格式是平台独立。
InnoDB 做了很多优化,比如:磁盘读取数据方式采用的可预测性预读、自动在内存中创建 hash 索引以加速读操作的自适应哈希索引(adaptive hash index),以及能够加速插入操作的插入缓冲区(insert buffer)等。
InnoDB 通过一些机制和工具支持真正的热备份,MySQL 的其他存储引擎不支持热备份,要获取一致性视图需要停止对所有表的写入,而在读写混合场景中,停止写入可能也意味着停止读取。
Insert Buffer 用于非聚集索引的插入和更新操作。先判断插入的非聚集索引是否在缓存池中,如果在则直接插入,否则插入到 Insert Buffer 对象里。再以一定的频率进行 Insert Buffer 和辅助索引叶子节点的 merge 操作,将多次插入合并到一个操作中,提高对非聚集索引的插入性能。
Double Write 由两部分组成,一部分是内存中的 double write buffer,大小为 2MB,另一部分是物理磁盘上共享表空间连续的 128 个页,大小也为 2MB。在对缓冲池的脏页进行刷新时,并不直接写磁盘,而是通过 memcpy 函数将脏页先复制到内存中的该区域,之后通过 doublewrite buffer 再分两次,每次 1MB 顺序地写入共享表空间的物理磁盘上,然后马上调用 fsync 函数,同步磁盘,避免操作系统缓冲写带来的问题。
InnoDB 会根据访问的频率和模式,为热点页建立哈希索引,来提高查询效率。索引通过缓存池的 B+ 树页构造而来,因此建立速度很快,InnoDB 存储引擎会监控对表上各个索引页的查询,如果观察到建立哈希索引可以带来速度上的提升,则建立哈希索引,所以叫做自适应哈希索引。
为了提高数据库的性能,引入缓存池的概念,通过参数 innodb_buffer_pool_size 可以设置缓存池的大小,参数
innodb_buffer_pool_instances 可以设置缓存池的实例个数。缓存池主要用于存储以下内容:
缓冲池中缓存的数据页类型有:索引页、数据页、undo页、插入缓冲 (insert buffer)、自适应哈希索引(adaptive hash index)、InnoDB存储的锁信息 (lock info)和数据字典信息 (data dictionary)。
MyISAM 是 MySQL 5.1 及之前的版本的默认的存储引擎。MyISAM 提供了大量的特性,包括全文索引、压缩、空间函数(GIS)等,但MyISAM 不「支持事务和行级锁」,对于只读数据,或者表比较小、可以容忍修复操作,依然可以使用它。
MyISAM「不支持行级锁而是对整张表加锁」。读取时会对需要读到的所有表加共享锁,写入时则对表加排它锁。但在表有读取操作的同时,也可以往表中插入新的记录,这被称为并发插入。
MyISAM 表可以手工或者自动执行检查和修复操作。但是和事务恢复以及崩溃恢复不同,可能导致一些「数据丢失」,而且修复操作是非常慢的。
对于 MyISAM 表,即使是 BLOB 和 TEXT 等长字段,也可以基于其前 500 个字符创建索引,MyISAM 也支持「全文索引」,这是一种基于分词创建的索引,可以支持复杂的查询。
如果指定了 DELAY_KEY_WRITE 选项,在每次修改执行完成时,不会立即将修改的索引数据写入磁盘,而是会写到内存中的键缓冲区,只有在清理键缓冲区或者关闭表的时候才会将对应的索引块写入磁盘。这种方式可以极大的提升写入性能,但是在数据库或者主机崩溃时会造成「索引损坏」,需要执行修复操作。
一张表简单罗列两种引擎的主要区别,如下图:
mysql引擎对比
SELECT COUNT(*) 常用于统计表的总行数,在 MyISAM 存储引擎中执行更快,前提是不能加有任何WHERE条件。
这是因为 MyISAM 对于表的行数做了优化,内部用一个变量存储了表的行数,如果查询条件没有 WHERE 条件则是查询表中一共有多少条数据,MyISAM 可以迅速返回结果,如果加 WHERE 条件就不行。
InnoDB 的表也有一个存储了表行数的变量,但这个值是一个估计值,所以并没有太大实际意义。
1范式:1NF 是对属性的原子性约束,要求属性具有原子性,不可再分解;(只要是关系型数据库都满足1NF)
2范式:2NF 是对记录的惟一性约束,要求记录有惟一标识,即实体的惟一性;
3范式:3NF 是对字段冗余性的约束,即任何字段不能由其他字段派生出来,它要求字段没有冗余,没有冗余的数据库设计可以做到。
但是,没有冗余的数据库未必是最好的数据库,有时为了提高运行效率,就必须降低范式标准,适当保留冗余数据,具体做法是:在概念数据模型设计时遵守第三范式,降低范式标准的工作放到物理数据模型设计时考虑,降低范式就是增加字段,允许冗余。
数据库删除操作中的 delete、drop、 truncate 区别在哪?
视图是虚拟表,并不储存数据,只包含定义时的语句的动态数据。
创建视图语法:
CREATE[OR REPLACE][ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}][DEFINER = user][SQL SECURITY { DEFINER | INVOKER }]VIEW view_name [(column_list)]AS select_statement[WITH [CASCADED | LOCAL] CHECK OPTION]
参数说明:
默认端口是 3306
查看端口命令:> show variables like ‘port’;
DISTINCT 用于对选择的数据去重,单列用法容易理解。比如有如下数据表 tamb:
name numberTencent 1Alibaba 2Bytedance 3Meituan 3
查询语句:SELECT DISTINCT name FROM table tamb 结果如下:
name Tencent Alibaba Bytedance Meituan
如果要求按 number 列去重同时显示 name ,你可能会写出查询语句:
SELECT DISTINCT number, name FROM table tamb
多参数 DISTINCT 去重规则是:把 DISTINCT 之后的所有参数当做一个过滤条件,也就是说会对 (number, name)整体去重处理,只有当这个组合不同才会去重,结果如下:
number name1 Tencent2 Alibaba3 Bytedance3 Meituan
从结果来看好像并没有达到我们想要的去重的效果,那要怎么实现「按 number 列去重同时显示 name」呢?可以用 Group By 语句:
SELECT number, name FROM table tamb GROUP BY number 输出如下,正是我们想要的效果:
number name1 Tencent2 Alibaba3 Bytedance
一条或多条 sql 语句集合,有以下一些特点:
delimiter 分隔符create procedure|proc proc_namebeginsql语句end 分隔符delimiter ; --还原分隔符,为了不影响后面的语句的使用--默认的分隔符是;但是为了能在整个存储过程中重用,因此一般需要自定义分隔符(除外)show procedure status like "; --查询存储过程,可以不适用like进行过滤drop procedure if exists;--删除存储过程
存储过程和函数是事先经过编译并存储在数据库中的一段 SQL 语句的集合,调用存储过程和函数可以简化应用开发人员的很多工作,减少数据在数据库和应用服务器之间的传输,对于提高数据处理的效率是有好处的。
相同点
不同点
本文是 MySQL 系列的第二篇,以面试问答形式总结了一系列面试常见的基础知识点,都是非常基础的内容,但越是基础越显得重要,建议收藏作为知识点笔记(据说分享、在看效果更佳),时常拿出来复习温故而知新,MySQL 系列知识点零散庞大,本文是基础篇,更多MySQL系列文章敬请期待。