Skip to content

《面渣逆袭》MySQL 篇 · 第 1/10 章。原版 PDF(下载 / 打印)

配图

作为 SQLBoy ,基础部分不会有人不会吧?面试也不怎么问,基础掌握不错的小伙伴可以跳过这一部分。当然,可能会现场写一些 SQL 语句,SQ语句可以通过牛客、LeetCode 、LintCode 之类的网站来练习。

1. 什么是内连接、外连接、交叉连接、笛卡尔积呢?

内连接(innerjoin ):取得两张表中满足存在连接匹配关系的记录。

外连接(outerjoin ):不只取得两张表中满足存在连接匹配关系的记录,还包括某张表(或两张表)中不满足匹配关系的记录。

交叉连接(crossjoin ):显示两张表所有记录一一对应,没有匹配关系进行筛选,它是笛卡尔积在 SQL 中的实现,如果 A 表有 m 行,B 表有 n 行,那么 A 和 B 交叉连接的结果就有 m*n行。

笛卡尔积:是数学中的一个概念,例如集合 A={a,b} ,集合 B={1,2,3} ,那么 A

配图

B={<a,o>,

<a,1>,<a,2>,<b,0>,<b,1>,<b,2>,}

2. 那 MySQL 的内连接、左连接、右连接有有什么区别?

MySQL 的连接主要分为内连接和外连接,外连接常用的有左连接、右连接。

配图

MySQL-joins- 来源菜鸟教程

innerjoin 内连接,在两张表进行连接查询时,只保留两张表中完全匹配的结果集

leftjoin 在两张表进行连接查询时,会返回左表所有的行,即使在右表中没有匹配的记录。

rightjoin 在两张表进行连接查询时,会返回右表所有的行,即使在左表中没有匹配的记录。

3.说一下数据库的三大范式?

配图

第一范式:数据表中的每一列(每个字段)都不可以再拆分。例如用户表,用户地址还可以拆分成国家、省份、市,这样才是符合第一范式的。

第二范式:在第一范式的基础上,非主键列完全依赖于主键,而不能是依赖于主键的一部分。例如订单表里,存储了商品信息(商品价格、商品类型),那就需要把商品 ID 和订单 ID 作为联合主键,才满足第二范式。

第三范式:在满足第二范式的基础上,表中的非主键只依赖于主键,而不依赖于其他非主键。例如订单表,就不能存储用户信息(姓名、地址)。

配图

三大范式的作用是为了控制数据库的冗余,是对空间的节省,实际上,一般互联网公司的设计都是反范式的,通过冗余一些数据,避免跨表跨库,利用空间换时间,提高性能。

4.varchar 与 char 的区别?

配图

char

char 表示定长字符串,长度是固定的;

如果插入数据的长度小于 char 的固定长度时,则用空格填充;

因为长度固定,所以存取速度要比 varchar 快很多,甚至能快 50% ,但正因为其长度固定,所以会占据多余的空间,是空间换时间的做法;

对于 char 来说,最多能存放的字符个数为 255 ,和编码无关

varchar

varchar 表示可变长字符串,长度是可变的;

插入的数据是多长,就按照多长来存储;

varchar 在存取方面与 char 相反,它存取慢,因为长度不固定,但正因如此,不占据多余的空间,是时间换空间的做法;

对于 varchar 来说,最多能存放的字符个数为 65532日常的设计,对于长度相对固定的字符串,可以使用 char ,对于长度不确定的,使用 varchar 更合适一些。

5.blob 和 text 有什么区别?

blob 用于存储二进制数据,而 text 用于存储大字符串。

blob 没有字符集,text 有一个字符集,并且根据字符集的校对规则对值进行排序和比较

6.DATETIME 和 TIMESTAMP 的异同?

相同点

  1. 两个数据类型存储时间的表现格式一致。均为YYYY-MM-DDHH:MM:SS

  2. 两个数据类型都包含「日期」和「时间」部分。

  3. 两个数据类型都可以存储微秒的小数秒(秒后 6 位小数秒)

区别

配图

DATETIME 和 TIMESTAMP 的区别

  1. 日期范围:DATETIME 的日期范围是1000-01-0100:00:00.0000009999-12-31

23:59:59.999999;TIMESTAMP 的时间范围是1970-01-0100:00:01.000000UTC 2038-

01-0903:14:07.999999UTC

  1. 存储空间:DATETIME 的存储空间为 8 字节;TIMESTAMP 的存储空间为 4 字节

  2. 时区相关:DATETIME 存储时间与时区无关;TIMESTAMP 存储时间与时区有关,显示的值也

依赖于时区

4.默认值:DATETIME 的默认值为 null;TIMESTAMP 的字段默认不为空(not null),默认值为
当前时间(CURRENT_TIMESTAMP)

7.MySQL 中 in 和 exists 的区别?

MySQL 中的 in 语句是把外表和内表作 hash 连接,而 exists 语句是对外表作 loop 循环,每次 loop循环再对内表进行查询。我们可能认为 exists 比 in 语句的效率要高,这种说法其实是不准确的,要区分情景:

  1. 如果查询的两个表大小相当,那么用 in 和 exists 差别不大。

  2. 如果两个表中一个较小,一个是大表,则子查询表大的用 exists ,子查询表小的用 in 。

  3. notin 和 notexists :如果查询语句使用了 notin ,那么内外表都进行全表扫描,没有用到索

引;而 notextsts 的子查询依然能用到表上的索引。所以无论那个表大,用 notexists 都比 not

in 要快。

8.MySQL 里记录货币用什么字段类型比较好?

货币在数据库中 MySQL 常用 Decimal 和 Numric 类型表示,这两种类型被 MySQL 实现为同样的类型。他们被用于保存与货币有关的数据。

例如 salary DECIMAL(9,2),9(precision)代表将被用于存储值的总的小数位数,而 2(scale)代表将

被用于存储小数点后的位数。存储在 salary 列中的值的范围是从- 9999999.99 到 9999999.99 。

DECIMAL 和 NUMERIC 值作为字符串存储,而不是作为二进制浮点数,以便保存那些值的小数精度。

之所以不使用 float 或者 double 的原因:因为 float 和 double 是以二进制存储的,所以有一定的误差。

9.MySQL 怎么存储 emoji

配图

?

MySQL 可以直接使用字符串存储 emoji 。

但是需要注意的,u tf8 编码是不行的,MySQL 中的 utf8 是阉割版的 utf8 ,它最多只用 3 个字节存储字符,所以存储不了表情。那该怎么办?

需要使用 utf8mb4 编码。

altertableblogsmodifycontenttextCHARACTERSETutf8mb4COLLATE

utf8mb4_unicode_ci not null;

10.drop、delete 与 truncate 的区别?

三者都表示删除,但是三者有一些差别:

deletetruncatedrop
类型属于 DML属于 DDL
回滚可回滚不可回滚
删除内容表结构还在,删除表的全部或者一部分数据行表结构还在,删除表中的所有数据
删除速度删除速度慢,需要逐行删除删除速度快

因此,在不再需要一张表的时候,用 drop ;在想删除部分数据行时候,用 delete ;在保留表而删除所有数据的时候用 truncate 。

11.UNION 与 UNION ALL 的区别?

如果使用 UNIONALL ,不会合并重复的记录行效率 UNION 高于 UNIONALL

12.count(1)、count() 与 count(列名) 的区别?

配图

执行效果

count(*) 包括了所有的列,相当于行数,在统计结果的时候,不会忽略列值为 NULL

count(1) 包括了忽略所有列,用 1 代表代码行,在统计结果的时候,不会忽略列值为 NULL

count( 列名) 只包括列名那一列,在统计结果的时候,会忽略列值为空(这里的空不是只空字符串或者 0 ,而是表示 null )的计数,即某个字段值为 NULL 时,不统计。

执行速度

列名为主键,count(列名)会比 count(1)快
列名不为主键,count(1)会比 count(列名)快

如果表多个列并且没有主键,则 count (1 ) 的执行效率优于 count (* )

如果有主键,则 selectcount (主键)的执行效率是最优的如果表只有一个字段,则 selectcount (* )最优。

13.一条 SQL 查询语句的执行顺序?

配图

  1. FROM:对 FROM 子句中的左表< left_table> 和右表< right_table> 执行笛卡儿积

(Cartesianproduct ),产生虚拟表 VT1

  1. ON:对虚拟表 VT1 应用 ON 筛选,只有那些符合< join_condition> 的行才被插入虚拟表 VT2

  1. JOIN:如果指定了 OUTERJOIN (如 LEFTOUTERJOIN 、RIGHTOUTERJOIN ),那么

保留表中未匹配的行作为外部行添加到虚拟表 VT2 中,产生虚拟表 VT3 。如果 FROM 子句包含两个以上表,则对上一个连接生成的结果表 VT3 和下一个表重复执行步骤 1 )~步骤 3 ),直到处理完所有的表为止

  1. WHERE:对虚拟表 VT3 应用 WHERE 过滤条件,只有符合< where_condition> 的记录才被插

入虚拟表 VT4 中

  1. GROUPBY:根据 GROUPBY 子句中的列,对 VT4 中的记录进行分组操作,产生 VT5

  2. CUBE|ROLLUP:对表 VT5 进行 CUBE 或 ROLLUP 操作,产生表 VT6

  3. HAVING:对虚拟表 VT6 应用 HAVING 过滤器,只有符合< having_condition> 的记录才被插

入虚拟表 VT7 中。

  1. SELECT:第二次执行 SELECT 操作,选择指定的列,插入到虚拟表 VT8 中

  2. DISTINCT:去除重复数据,产生虚拟表 VT9

  3. ORDERBY:将虚拟表 VT9 中的记录按照< order_by_list> 进行排序操作,产生虚拟表

VT10 。11 )

  1. LIMIT:取出指定行的记录,产生虚拟表 VT11 ,并返回给查询用户
本文整理自三分恶《面渣逆袭》系列的公开内容,仅供个人学习使用

本站仅供个人学习使用,请勿外传