注意:范式只是早期大佬们提出的规范,现在很多情况下,为了性能基本都不遵守基本规范,了解即可。具体原因,以前的提出范式的时候,磁盘的存储是相当贵的,当时是为了节省空间,从而牺牲时间,而如今,很多公司都基本为了追求性能,为了时间而牺牲空间,比如:为了查询更加迅速,会去进行单表冗余,此时就违反了第二范式
第一范式(1NF): 关系 R 属于第一范式,当且仅当 R 中的每一个属性 A 的值域只包含原子项,
意思: 每个列不能进一步被拆分,例如 某列:经济系王强 不满足,可拆分经济系,王强
第二范式(2NF):在满足 1NF 的基础上,消除非主属性对码的部分函数依赖
意思: 每个表都有主键,且非主键列要与主键相关
第三范式(3NF):在满足 2NF 的基础上,消除非主属性对码的传递函数依赖
意思: 消除传递依赖,即,列要与主键依赖关系
BC 范式(BCNF):在满足 3NF 的基础上,消除主属性对码的部分和传递函数依赖
第四范式(4NF):消除非平凡的多值依赖
第五范式(5NF):消除一些不合适的连接依赖
开源:MySQL、PostgreSQL
商业:Oracle,DB2,SQL Server内存数据库:Redis?,VoltDB
图数据库:Neo4j,Nebula
时序数据库:InfluxDB、openTSDB
其他关系数据库:Access、Sqlite、H2、Derby、Sybase、Infomix 等
NoSQL 数据库:MongoDB、Hbase、Cassandra、CouchDB
NewSQL/分布式数据库:TiDB、CockroachDB、NuoDB、OpenGauss、OB、TDSQ
- 5.6/5.7的差异 :
- 5.7/8.0的差异:
注意:存储计划,现在很少用了,因为存储计划不适用于项目的迁移,比如:公司维护了一套几年的业务系统用的mysql数据库,并写了大量的存储计划。但是,现在系统做升级,换库,则mysql的存储计划将不能迁移,产生大量的迁移工作。
-- 创建存储过程
CREATE PROCEDURE userData(
IN a VARCHAR(256)
)
BEGIN
SELECT * from tbl_area WHERE id = a;
END;
-- 销毁存储过程
drop procedure userData;
-- 调用存储过程
call userData(310101000000)
-- 查询当前配置
show variables like '%last%'
-- 查询全局配置
show global variables like '%innodb%';
-- 查询某个变量属性
select @@last_insert_id;
-- 设置属性
set last_insert_id = 1;
-- 设置全局属性,注意5.6/5.7的mysql 重启后全局设置不生效
set global last_insert_id = 1;
1)连接请求的变量
1、max_connections 最大连接数
2、back_log 半连接状态最大数量
3、wait_timeout和interative_timeout 等待超时时间和交互超时时间
2)缓冲区变量
4、key_buffer_size
5、query_cache_size(查询缓存简称 QC) 8.0以后没有这个参数
6、max_connect_errors 最大错误数
7、sort_buffer_size 1M
&emsp**;8、max_allowed_packet=32M 给mysql的最大数据包:如,sql语句超过32M,则拒收**
9、join_buffer_size=2M
10、thread_cache_size=30
3)配置 Innodb 的几个变量
11、innodb_buffer_pool_size=128M 缓存区域大小
12、innodb_flush_log_at_trx_commit
13、innodb_thread_concurrency=0
14、innodb_log_buffer_size
15、innodb_log_file_size=50M
16、innodb_log_files_in_group=3
17、read_buffer_size=1M 读取数据时Buffer大小
18、read_rnd_buffer_size=16M 随机读Buffer大小
19、bulk_insert_buffer_size=64M 插入的时候buffer的大小
20、binary log
如何恰当选择引擎?
不要强事务,数据量比较大,比如论坛这种,可以用mysISAM,
做电商,金融,这种强事务的情况下,可以用Innodb。
数据小,不需要持久化,可以用memory
数据要归档,可以使用 toku,压缩效率高,库表如何命名?
用前缀表示模块如何合理拆分宽表?
如何选择恰当数据类型:明确、尽量小
char、varchar 的选择
char是定长,varchar是变长的(text/blob/clob)的使用问题?
数据量比较大,存储的一条数据的时候会操作两次,第一次插入其他列,第二次打开updload上传流,效率低文件、图片是否要存入到数据库?
不建议存在数据库中,建议文件图片或者大的数据类型blob这种文本很长的的,可以放在分布式文件系统上,或者应用服务器磁盘上,数据库里放url时间日期的存储问题?
数值的精度问题?
是否使用外键、触发器
-唯一约束和索引的关系?
唯一约束自动上索引是否可以冗余字段?
提高查询效率是否使用游标、变量、视图、自定义函数、存储过程?
不建议使用,不容易移植自增主键的使用问题?
数据量大的情况,分布式的情况 不建议使用能够在线修改表结构(DDL 操作)?
在线修改,导出的时候,会进行锁表逻辑删除还是物理删除?
建议逻辑删除要不要加 create_time,update_time 时间戳?
建议加数据库碎片问题?
进行操作会进行锁表,空闲时间做如何快速导入导出、备份数据?
弄个主从数据库,备份的时候直接摘下来从库,进行备份从库,
导出的,时候,先导数据,后建立索引
•Atomicity: 原子性,一次事务中的操作要么全部成功,要么全部失败。
•Consistency: 一致性,跨表、跨行、跨事务,数据库始终保持一致状态。
•Isolation: 隔离性,可见性,保护事务不会互相干扰,包含4种隔离级别。
•Durability: 持久性,事务提交成功后,不会丢数据。如电源故障,系统崩溃
for update 上 排他锁(X锁),lock in share model 上共享锁(S锁)
行级锁(InnoDB)
•记录锁(Record): 始终锁定索引记录,注意隐藏的聚簇索引
•间隙锁(Gap): 锁住一个范围
•临键锁(Next-Key): 记录锁+间隙锁的组合; 可“锁定”表中不存在记录
•谓词锁(Predicat): 空间索引死锁: -阻塞与互相等待 -增删改、锁定读 -死锁检测与自动回滚 -锁粒度与程序设计
\
• 读未提交: READ UNCOMMITTED 很少使用
• 读已提交(RC): READ COMMITTED :oracle,sql server,db2默认的
• 可重复读(RR): REPEATABLE READ :mysql默认的
• 可串行化: SERIALIZABLE 事务隔离是数据库的基础特征。
MySQL:
• 可以设置全局的默认隔离级别
• 可以单独设置会话的隔离级别
• InnoDB 实现与标准之间的差异 隔离级别 并发性 可靠性 一致性
•脏读(dirty read) : 使用到从未被确认的数据(例如: 早期版本、回滚),其他线程还没提交的数据,被查询到了
•不可重复读(unrepeated read): 不加锁的情况下,其他事务 update 会对结果集有影响 ,查询到的结果集被其他线程修改
•幻读(phantom read): 相同的查询语句,在不同的时间点执行时,产生不同的结果集不同,两次查询结果不一致
--解决:加锁,提高隔离级别
undo log: 撤消日志
•保证事务的原子性
•用处: 事务回滚, 一致性读、崩溃恢复。
•记录事务回滚时所需的撤消操作
•一条 INSERT 语句,对应一条 DELETE 的 undo log
•每个 UPDATE 语句,对应一条相反 UPDATE 的 undo log 保存位置:
•system tablespace(MySQL 5.7 默认)
•undo tablespaces(MySQL 8.0 默认)
redo log: 重做日志
•确保事务的持久性,防止事务提交后数据未刷新到磁盘就掉电或崩溃。
•事务执行过程中写入 redo log,记录事务对数据页做了哪些修改。
•提升性能: WAL(Write-Ahead Logging) 技术,先写日志,再写磁盘。
•日志文件: ib_logfile0, ib_logfile1
•日志缓冲: innodb_log_buffer_size
•强刷: fsync()
–mvcc机制,事务控制的隐藏列配合undo log 进行回滚,可查询
系统经过一个月的运行,用户表增长约100万,DBA 接到告警, CPU 升高,查询越来越慢,请定位问题并给出解决方案:
-慢查询日志
Slowlog文件,-看应用和运维的监控
• Hash
计算hash值,kv存储
• B-Tree/ B+Tree
B树:按块存储,每块有指针和数据,指针指向其他块
B+树:分级别,最多存储三级,做三次io转换,与B树不同的是,所有数据都在最底层的叶子节点中,上层父节点只有键值和指针。所有叶子节点的块都会用双向指针串起来,第二次调用时,不用回溯树结构
因为数据库b+树存储数据规则时,是主键直接对应着数据,聚合索引, 而非主键索引,称二级索引是单独创建的索引文件,不包含实际数据,需要找到主键去再回表拿记录
– 会锁表, 占用表
– 会重建索引
– 主从模式会延迟主从同步
– 抢占资源
– 采用 Multiple Values/Add Batch的方式在后面追加
– load data 命令导入csv文件
– PreparedStatement 减少 SQL 解析
– 索引和约束问题 最后数据导入之后在重建
数据范围的更新设计到 锁
注意 GAP Lock 的问题,能不用范围更新就不用,要精确,否则会导致锁区域
导致锁的范围变大
–精确
like 参数尽量 (百分号在后面)l% 前置查询会调用索引, %l 百分号在前面则不会走索引
使用like的数据比较多,组合模糊查询,倒排索引 建议使用 solr、es
NULL, not , not in ,函数等;
or也会使索引失效,减少使用or ,可以用 union(去重) 和union all(union all 不去重),替换
- 什么时候使用索引?
- 字段有唯一限制时,如商品编码
- 经常用来条件查询的如WHERE后的查询
- 经常用于group by 和order by 的字段
- 什么时候不要创建索引?
- 字段中大量重复字段,字段数据太大
- 经常更新的字段,避免为何索引成本太高
高效分页 还能不能继续改进?
- 分页:count/pageSize/pageNum, 带条件的查询语句
- 常见实现-分页插件:使用查询 SQL,嵌套一个 count,性能的坑?
- 改进一下1,重写 count - 大数量级分页的问题,limit 100000,20
- 改进一下2,反序
- 继续改进3,技术向:带 id
例如:select * from city where id>20 limit 20
- 继续改进4,需求向:非精确分页
- 所有条件组合? 索引
随着数据量的增大,读写并发的增加,系统可用性要求的提升,
单机 MySQL 面临:
1、容量有限,难以扩容
2、读写压力,QPS 过大,特别是分析类需求会影响到业务事务
3、可用性不足,宕机问题
– MySQL 高可用0:
主从手动切换 如果主节点挂掉,将某个从改成主;
重新配置其他从节点。
修改应用数据源配置。>有什么问题?
- 可能数据不一致。
- 需要人工干预。
- 代码和配置的侵入性
– MySQL 高可用1:
主从手动切换 用 LVS+Keepalived 实现多个节点的探活+请求路由。
配置 VIP 或 DNS 实现配置不变更。
> 有什么问题?
- 手工处理主从切换
- 大量的配置和脚本定义
– MySQL 高可用2:MHA
MHA(Master High Availability)目前在 MySQL 高可用方面是一个相对成熟的解决方案,它由 日本 DeNA 公司的 youshimaton(现就职于 Facebook 公司)开发,是一套优秀的作为 MySQL 高可用性环境下故障切换和主从提升的高可用软件。
基于 Perl 语言开发,一般能在30s内实现主从切换。 切换时,直接通过 SSH 复制主节点的日志。
> 有什么问题?
- 需要配置 SSH 信息
- 至少3台
– MySQL 高可用3:MGR
如果主节点挂掉,将自动选择某个从改成主; 无需人工干预,基于组复制,保证数据一致性。
> 有什么问题?
- 外部获得状态变更需要读取数据库。
- 外部需要使用 LVS/VIP 配置。
– MySQL 高可用4:MySQL Cluster
– MySQL 高可用5:Orchestrator
如果主节点挂掉,将某个从改成主;
Orchestrator 一款 MySQL 高可用和复制拓扑管理工具,支持复制拓扑结构的调整,自动故障转移和手动主从切换等。 后段数据库 MySQL 或 SQLite 存储元数据,并提供 Web 界面展示 MySQL 复制的拓扑关系及状态, 通过 Web 可更改 MySQL 实例的复制关系和部分配置信息,同时也提供命令行和 API 接口,方便运维 管理。
特点:
- 自动发现 MySQL 的复制拓扑,并且在 Web 上展示;
- 重构复制关系,可以在 Web 进行拖图来进行复制关系变更;
- 检测主异常,并可以自动或手动恢复,通过 Hooks 进行自定义脚本;
- 支持命令行和 Web 界面管理复