第8章 数据库考察点

Mysql基础常考题

  • 事务的原理,特性,事务并发控制

  • 常用的字段, 含义和区别

  • 常用的数据库引擎之间区别

什么是事务?

Transaction:

  • 事务是数据库并发控制的基本单位

  • 事务可以看作是一系列SQL语句的集合

  • 事务必须要么全部执行成功,要么全部执行失败(回滚)

  • 转账操作是事务使用的一个常见场景

#Transaction 示例
    session.begin()
    try:
        item1 = session.query(Item).get(1)
        item2 = session.query(Item).get(2)
        item1.foo = 'bar'
        item2.bar = 'foo'
        session.commit()
    except:
        session.rollback()
        raise

事务的ACID特性

ACID是事务的四个基本特性

  • 原子性(Atomicity): 一个事务中所有操作全部完成或失败

  • 一致性(Consistency): 事务开始和结束之后数据完整性没有被破坏

  • 隔离性(Isolation): 允许多个事务同时对数据库修改和读写

  • 持久性(Durability): 事务结束之后,修改是永久的不会丢失

事务的并发控制可能产生哪些问题

如果不对事务进行并发控制,可能会产生四种异常情况

  • 幻读(phantom read): 一个事务第二次查出现第一次没有出现的结果

  • 非重复读(nonrepeatable read): 一个事务重复读两次得到不同的结果

  • 脏读(dirty read): 一个事务读取到另一个事务没有提交的修改

  • 丢失修改(lost update): 并发写入造成其中一些修改丢失

四种事务隔离级别

为了解决并发控制异常,定义了4种事务隔离级别

  • 读未提交(read uncommitted) 别的事务可以读取到未提交改变

  • 读已提交(read committed): 只能读取已经提交的数据

  • 可重复读(repeatable read): 同一个事务先后查询结果一样

​ Mysql InnoDB 默认实现可重复读级别

  • 串行化(Serializable): 事务完全串行化的执行,隔离级别最高,执行效率最低

如何解决高并发场景下的插入重复

高并发场景下, 写入数据库会有数据重复问题

  • 使用数据库的唯一索引

  • 使用队列异步写入

  • 使用redis等实现分布式锁

乐观锁和悲观锁

什么是乐观锁,什么是悲观锁

  • 悲观锁是先获取锁再进行操作,一锁二查三更新 select for update

  • 乐观锁先修改,更新的时候发现数据已经变了就回滚(check and set)

  • 乐观锁一般通过版本号或者时间戳实现

  • 需要根据响应速度,冲突频率,重试代价来判断使用那一种

Mysql常用数据类型-字符串(文本)

CHAR(Length) length bytes A fixed-length field from 0 to 255 characters long
VARCHAR(Length) String length + 1 or 2 bytes A variable-length field from 0 to 65535 characters long
tinytext String length + 1 bytes A string with a maximum length of 255 characters
TEXT String length + 2 bytes A string with a maximum length of 65535 characters

Mysql常用数据类型-数值

TINYINT(Length) 1 byte Range of -128 to 127 or 0 to 255 unsigned
SMALLINT(Length) 2 bytes Range of -32768 to 32767 or 0 to 65535 unsiged
MEDIUMINT(Length) 3 bytes Range of -8388608 to 8388607 or 0 to 16777215 unsigned
INT(Length) 4 bytes Range of -2147483648 to 2147483647 or 0 to 4294967295
BIGINT(Length) 8 bytes Range of -9223372036854775808 to 9223372036854775807 or 0 to 18446744073709551615 unsigned
FLOAT(Length, Decimals) 4 bytes A small number with a floating decimal point
DOUBLE(Length, Decimals) 8 bytes A large number with a floating decimal point

Mysql常用数据类型-日期和时间

DATE 3 bytes ln the format of YYYY-MM-DD
DATETIME 8 bytes ln the format of YYYY-MM-DD HH:MM:SS
TIMESTAMP 4 bytes In the format of YYYYMMDDHHMMSS; acceptable range starts in 1970 and ends in the year 2018

InnoDB vs MyISAM

两种引擎常见的区别

  • InnoDB支持事务

  • InnoDB支持外键

  • InnoDB支持行锁和表锁 MyISAM只支持表锁

Mysql索引原理及优化常见考题

Mysql索引

  • 索引的原理,类型,结构

  • 创建索引的注意事项,使用原则

  • 如何排查和消除慢查询

什么是索引?

为什么需要索引?

  • 索引是数据表中一个或者多个列进行排序的数据结构

  • 索引能够大幅提升检索速度

  • 创建,更新索引本身也会耗费空间和时间

什么是B-Tree?

查找结构进化史

  • 1> 线性查找: 实现简单,太慢

  • 2> 二分查找: 有序,简单,要求是有序的,插入特别慢

  • 3> HASH: 查询快,占用空间,不太适合存储大规模数据

  • 4> 二叉查找树: 插入和查询快(log(n)), 无法存大规模数据,复杂度退化

  • 5> 平衡树: 解决bst退化的问题,树是平衡的,节点非常多的时候,依然树高很高

  • 6> 多路查找树: 一个父亲多个孩子节点(度) 节点过多 树高不会特别深

  • 7> 多路平衡查找树: B-Tree

什么是B-Tree,为什么要使用B-Tree

  • 多路平衡查找树(每个节点最多m(m >= 2))个孩子,称为m阶或者度)

  • 叶节点具有相同的深度

  • 节点中的数据key从左到右是递增的

B+Tree
B+树是B-Tree的变形

  • Mysql实际使用的B+Tree作为索引的数据结构

  • 只在叶子节点带有指向记录的指针(为什么? 可以增加树的度)

  • 叶子节点通过指针相连,为什么?实现范围查询

是不是树的度越多越好?

Mysql索引的B+Tree类型

Mysql创建索引类型

  • 普通索引(CREATE INDEX)

  • 唯一索引,索引列的值必须唯一(CREATE UNIQUE INDEX)

  • 多列索引

  • 主键索引(PRIMARY KEY) 一个表只能有一个

  • 全文索引(FULLTEXT INDEX), InnoDB不支持

什么时候创建索引?

建表的时候需要根据查询需求来创建索引

  • 经常用作查询条件的字段(WHERE条件)

  • 经常用作表连接的字段

  • 经常出现在order by, group by之后的字段

创建索引有哪些需要注意的?

最佳实践

  • 非空字段 NOT NULL, Mysql很难对空值作查询优化

  • 建表规范要求索引字段有默认值

  • 区分度高, 离散度大,作为索引的字段尽量不要有大量相同值

  • 索引的长度不要太长(比较耗费时间)

索引什么时候失效?

记忆口诀:模糊匹配,类型隐转,最左匹配

  • 以 % 开头的LIKE语句,模糊搜索

  • 出现隐式类型转换(在py这种动态语言查询中需要注意)

  • 没有满足最左前缀原则(为什么是左配)

什么是聚集索引和非聚集索引?

聚集索引和辅助索引

聚焦索引

非聚集和聚集索引的文件存储方式

  • 聚集还是非聚集指的是B+Tree叶节点存的是指针还是数据记录

  • MyISAM索引和数据分离,使用的是非聚集索引

  • InnoDB数据文件就是索引文件, 主键索引就是聚集索引

  • 辅助索引先找到主键以后再根据主键找到数据

如何排查慢查询

通常缺少索引,索引不合理或者业务代码实现导致

  • slow_query_log_file 开启并且查询慢查询日志

  • 通过explain排查索引问题

  • 调整数据修改索引,业务代码层限制不合理访问

总结

  • 索引的原理

  • B + Tree的结构

  • 不同索引的区别

SQL语句编写常考题

考点聚焦

SQL语句以考察各种常用连接为重点

  • 内连接(INNER JOIN): 两个表都存在匹配时,才会返回匹配行

  • 外连接(LEFT/RIGHT JOIN): 返回一个表的行,即使另一个没有匹配

  • 全连接(FULL JOIN): 只要某一表存在匹配就返回

内连接

INNER JOIN

  • 将左表和右表能够关联起来的数据连接后返回

  • 类似于求两个表的"交集"
    • select * from A inner join B on a.id = b.id

示例表

id value
1 ab
2 a
id value
1 ab
3 b

外连接

外连接包含左连接和右连接

  • 左连接返回左表中所有记录,即使右表中没有匹配的记录

  • 右连接返回右表中所有记录,即使左表中没有匹配的记录

  • 没有匹配的字段会设置成NULL

缓存及Redis常考面试题

缓存的使用场景,Redis的使用,缓存使用的坑

为什么使用缓存?使用场景?

Redis的常用数据类型, 使用方式

缓存使用问题,数据一致性问题,缓存穿透,击穿,雪崩问题

主要讨论内存缓存(Redis/Memchached)

  • 解关系数据库(常见的是Mysql)并发访问的压力,热点数据

  • 减少响应时间:内存IO速度比磁盘快

  • 提升吞吐量:Redis等内存数据库单机就可以支撑很大并发

操作时间对比

操作 响应时间
打开一个网站 几秒
在数据库中查询一条记录(有索引) 十几毫秒
机械磁盘一次寻址定位 4毫秒
从机械磁盘顺序读取1MB数据 2毫秒
从SSD磁盘顺序读取1MB数据 0.3毫秒
从远程分布式缓存Redis读取一个数据 0.5毫秒
从内存中读取1MB数据 十几微秒
Java程序本地方法调用 几微秒
网络传输2KB数据 1微秒

Redis/Memcached主要区别?

对比参数 Redis Memcached
类型 1.支持内存 2.非关系型数据库 1.支持内存 2.key-value键值对形式 3.缓存系统
数据存储类型 1.String 2.List 3. Set 4.Hash 5.Sort Set(ZSet) 1.文本型 2. 二进制类型[新版增加]
查询[操作]类型 1.批量操作 2. 事务支持[假的事务] 3.每个类型不同的CRUD 1.CRUD 2.少量的其它命令
附加功能 1. 发布/订阅模式 2. 主从分区 3. 序列化支持 4.脚本支持[Lua脚本] 1. 多线程服务支持
网路IO模型 1. 单进程模式 1. 多线程,非阻塞IO模式
事件库 自封装简易事件库AeEvent 贵族血统的LibEvent事件库
持久化支持 1. RDB 2. AOF 不支持

Mysql + Redis就能抗很多业务

请简述Redis常用数据类型和使用场景?

考察对Redis使用的掌握程度

  • String(字符串):用来实现简单的KV键值对存储,eg:计数器

  • List(链表): 实现双向链表,eg:用户的关注,粉丝列表

  • Hash(哈希表): 用来存储彼此相关的信息的键值对
    • HSET key field value
  • Set(集合): 存储不重复元素,比如用户的关注者

  • Sorted Set(有序集合): 实时信息排行榜

延伸考点:Redis内置实现

需要了解Redis各种类型的C底层实现方式

  • String: 整数或者sds(Simple Dynamic String)

  • List: ziplist or double linked list

  • ziplist: 通过一个连续的内存块实现list结构,

    ​ 其中的每个entry节点头部保存前后节点长度信息,实现双向链表功能

  • Hash: ziplist or hashtable

  • set: inset or hashtable

  • SortedSet: skiplist 跳跃表

reference book

​ Redis 设计与实现

这些数据结构操作的时间和空间复杂度?

Redis实现的跳跃表示什么结构?

  • Sorted Set为了简化实现,使用skiplist而不是平衡树实现?

Redis有哪些持久化方式?

Redis支持两种方式实现持久化

  • 快照方式:把数据快照放在磁盘二进制文件中,dump.rdb

    ​ 快照的实现方式是指定时间间隔把Redis数据库状态保存到一个压缩的二进制文件中

    • AOF(Append Only File): 每一个写命令追加到appendonly.aof中 可以通过修改redis配置实现

什么是Redis事务?

和mysql的事务有什么不同?

  • 将多个请求打包,一次性,按序执行多个命令的机制

  • Redis通过MULTI, EXEC, WATCH等命令实现事务功能

  • Python redis-py pipeline=conn.pipeline(transaction=True)

Redis如何实现分布式锁?

  • 使用setnx实现加锁,可以同时通过expire添加超时时间

  • 锁的value值可以使用一个随机的uuid或者特定的命名

  • 释放锁的时候,通过uuid判断是否是该锁,是则执行delete释放锁

使用缓存的模式?

  • Cache Aside:同时更新缓存和数据库

  • Read/Write Through: 先更新缓存,缓存负责同步更新数据库

  • Write Behind Caching:先更新缓存,缓存定期异步更新数据库一致性问题

如何解决缓存穿透问题?

​ 大量查询不到的数据的请求落到后端数据库,数据库压力增大

​ 由于大量缓存查不到就去数据库取,数据库也没有要查的数据

  • 解决:对于没查到返回为None的数据也缓存, 插入数据的时候删除相应缓存,或者设置较短的超时时间

如何解决缓存击穿问题?

​ 某些非常热点的数据key过期,大量请求打到后端数据库

​ 热点数据key 失效导致大量请求打到数据库增加数据库压力

  • 分布式锁:获取锁的线程从数据库拉数据更新缓存,其它线程等待

  • 异步后台更新:后台任务对过期的key自动刷新

如何解决缓存雪崩问题?

缓存不可用或者大量缓存key同时失效,大量请求直接打到数据库

  • 多级缓存:不同级别的key设置不同的超时时间

  • 随机超时:key的超时时间随机设置,防止同时超时

  • 架构层: 提升系统可用性,监控,报警完善

Mysql与Redis思考题?

索引的理解

为什么Mysql数据库的主键使用自增的整数比较好?

使用uuid可以吗?为什么?

如果是分布式系统下怎么生成数据库的自增id呢?

Redis应用-分布式锁

redis的应用之一:实现分布式锁

思考题:

​ 请基于redis编写代码实现一个简单的分布式锁

​ 要求:支持超时时间参数

​ 扩展:如果redis单个节点宕机,如何处理?还有其它方案实现分布式锁?

猜你喜欢

转载自www.cnblogs.com/xuzhaoping/p/11619245.html