关系型数据库MySQL及其优化

写在前面

本文看下MySQL的基础内容以及常见的优化方式。

1:MySQL基础内容

1.1:什么是关系型数据库

以二维的数据格式来存储数据的数据库叫做关系型数据库,其中关系包括一对一,一对多,多对多,都通过二位数据中的行与行关联来表达关系。

1.2:E-R图

e的意思是entity,r的意思是relation,E-R图,即实体关系图,表达的是关系型数据库中的表之间的关系,一对一,一对多,多对多,如下图是一个电商系统中可能的关系图:

在这里插入图片描述

1.3:数据库范式

在这里插入图片描述

先来看一些重要的概念:

1.3.1:重要的概念

1.3.1.1:主键、候选键、超键

  • 主键
    能够唯一标识一行的键就叫做主键,比如如下的表:
    在这里插入图片描述

其中(学号)(身份证号),二者中的任何一个都能唯一的标识一行,因此二者中任何一个我们都叫做主键,但注意主键只能有一个。

  • 候选键
    能够作为主键的键和集合,我们叫做候选键,即候选键中的任何一个都可以作为主键,如下的表:

在这里插入图片描述
其中[(学号),(身份证号)]的集合就是这个表的候选键。

  • 超键
    在候选键中任意添加其他的列,构成的键就叫做超建,即包含了主键的键,如下表:
    在这里插入图片描述

候选集为[(学号),(身份证号)],我们可以添加性别到学号,添加姓名到身份证号,变为如下:[(学号,性别),(身份证号,姓名)]。即超键肯定能作为主键(但不一定符合某些范式)

1.3.1.2:函数依赖,部分依赖,传递依赖

  • 函数依赖
    一个或者是一组属性的值可以确定(推导出)其他属性的值,就叫做函数依赖,比如下表:
    在这里插入图片描述

通过(学号)可以推导出姓名,就可以说姓名函数依赖于学号。

  • 部分依赖
    即通过主键中的部分属性就能推导出非主键属性,就叫做部分依赖,如下表:
    在这里插入图片描述

如果使用(学号,姓名)作为主键,通过学号可以推导出姓名,就可以说姓名函数依赖于(学号,姓名),问题的本质是把超键当做主键来用了。

  • 传递依赖
    主属性A可以推导出非主属性B,而非主属性B又可以推到出非主属性C,则主属性A推导非主属性C的过程就叫做传递依赖,如下表:
    在这里插入图片描述

比如我们使用(学号)作为主键,则存在学号->班级编号->院系,这里学号对院系就是传递依赖。

1.3.2:五种数据库范式

范式类似于设计模式 ,都是一种经验,可以直到我们更好的设计数据库,范式的英文是Normal Form,简称NF,范式有如下的6种:

1:1NF第一范式
2:2NF第二范式
3:3NF第三范式
4:BCNFBC范式,因为介于3NF和4NF之间,所以有时也叫做3.5NF
5:4NF第四范式
6:5NF第五范式

1.3.2.1:1NF

数据库第一范式,定义为,对于关系R,当且仅当关系R的每个属性的值域只包含原子项,接下来用人话翻译一遍,就是,对于一张表R,表R的每个列的值都不可再分,如下表:
在这里插入图片描述
其中name_age列就是可以在分为name和age的,因此并不是原子项,不符合第一范式,如果修改为如下,则符合第一范式:
在这里插入图片描述

1.3.2.2:2NF

在满足第一范式的基础上,不存在部分函数依赖,即消除非主属性对主属性的部分函数依赖,如下表:
在这里插入图片描述

主键为(学生编号,课程编号),但是存在通过学生编号就可以推导出学生姓名的情况,即存在部分函数依赖,所以不满足第二范式,因此将该表拆分为如下的两个表就可以满足第二范式了:
在这里插入图片描述

在这里插入图片描述

1.3.2.3:3NF

在满足第二范式的基础上,消除传递函数依赖,如下表:
在这里插入图片描述

主键是(学生编号),虽然其能够决定院系,但并非直接决定,而是通过学生编号->班级编号->院系,即是通过传递函数依赖确定的,因此此时是不符合第三范式的,可修改为如下表结构:
在这里插入图片描述

在这里插入图片描述

1.3.2.4:BCNF

只有存在联合主键的时候才可能存在不满足BCNF的情况。

在满足第三范式的基础上,消除主属性对于码的传递函数依赖和部分函数依赖。来看个例子,假定某物流公司有很多仓库,每个仓库都有一个仓库管理员,每个仓库都可以存放多种物品,每种物品都有数量,设计出来后如下表:

在这里插入图片描述
此时码(即联合主键)(仓库名,管理员,物品名),存在如下的问题:

在这里插入图片描述
此时会出现的问题是,如果我们有新的仓库,比如火星仓,则必须在配备了管理员,准备了物品后,才能创建该仓库,这明显是不能满足业务的使用的,删除也是同样的道理,现在某个管理员离职,更换其他管理员,更新的成本也很高,可以修改为如下的表,使其符合BCNF:
在这里插入图片描述

1.3.2.5:4NF

在满足3NF的基础上,消除表内的多对多关系,如下表:

在这里插入图片描述

课程->学生和课程->先修课,都是1:n的关系,因此表的数据冗余度将会非常高,可修改为如下:

在这里插入图片描述

1.3.2.6:5NF

TODO

1.4:SQL语言

1.4.1:简介

全称是structure query language,即结构化查询语言,是一种用来操作关系型数据库的语言,在1970年由boyce和chanberlin提出(也就是BCNF中的BC),sql根据执行的操作不同可以分为如下的几种:

DQL:data query language,数据查询语言,或“数据检索语句”,即select ...。用来查询数据。
DML:data monipulation[məˌnɪpjʊˈleɪʃ(ə)n] language,数据操纵语言,如insert,update,delete。用来增删改查数据。
DDL:data definition language,数据定义语言,如create table,drop table,alter table等。用来创建表和修改表结构。
TCL:transaction control language,事务控制语言,如start transaction,begin,commit,savepoint,rollback等。用来通过事务控制数据的增删改成功。
DCL:data control language,数据控制语言,如grant,revoke等。用来控制用户对库表,以及各种增删改查等操作的权限。

前两种使用的最多的,因为我们的程序就是在查询和修改数据,第三种也会用到,但没那么多了。

1.4.2:历史

在1986年有了第一个版本,SQL-86,最后一个版本是在2011年,SQL:2011,具体如下图:

在这里插入图片描述

其中目前使用最多的还是1992年的SQL2和1999年的SQL3。

1.5:MySQL数据库历史

monty是MySQL的开发,第一行代码就由其编写(据说第一行代码,其实是一行注释,可见注释还是重要啊!!!),之后monty和朋友合伙创建了MySQL AB公司,接着在2008年sun公司以10亿美元收购了MySQL AB公司,但monty并未随之进入sun公司,而是单起炉灶成立了另外一家公司,之后在2009年Oracle以74亿美元收购了sun公司(有没有一种大鱼吃小鱼,小鱼吃虾米的感觉)。MySQL创世人monty担心Oracle公司将MySQL商业化,闭源,就有基于MySQL拉了另一个分支,开发了mariaDB,如下图:

在这里插入图片描述

MySQL的my是monty和首任妻子所生大闺女的名字,mariaDB是monty和二婚妻子所生二闺女的名字,看来不管是中国人还是老外,还真都是女儿奴啊!!!

接着我们来看下MySQL本身的发展历史。

4.0在该版本中通过innodb支持了事务
5.0(2003年)
5.6
5.7
8.0 

8.0版本相对于5.7版本发生了非常大的变化,所以直接叫做8.0版本了,按照官方的计划,是大力发展该版本,并使该版本成为时长的主流,但事与愿违,因为8.0版本的变化是在是太大,迁移的成本太高,所以用户量一直也没有太大的升高,反而,用户不断的将版本升级为5.7版本,因此当前5.7版本是最主流的MySQL版本,如果有一个新业务,也可以考虑使用该版本,那么每个版本都有哪些更新呢,也来看下:

5.7:增加json处理功能mgr(mysql group replication) 一种基于paxos协议的分布式解决方案分区表修复XA问题
8.0json增强,优化json处理的性能自增列持久化utf8mb4为默认编码

8以前的版本,默认编码是utf-8,但其utf-8是假u8很多,因为很多编码都不支持,而真正的u8编码是utf8mb4,所以8默认的编码是真正的u8编码了。

2:优化

2.1:参数优化

2.1.1:连接请求变量

  • max_connections

尽量不让达到最大连接。

最大连接数,最大值16384,可适当调大该值,最优值为达到85%的使用量,即max_used_connection/max_connnects约等于85%最好。

当连接数达到max_connections时,用来等待可用连接时存放的临时区域,一般设置为3000左右。

  • wait_timeout/interactive_timeout
    设置客户端超时,分别用户非交互式(jdbc)和交互式(mysql cli)连接超时时长。超过会断开连接,默认是8个小时,一般不需要修改。

2.1.2:缓冲区变量

  • key_buffer_size
    设置myisam存储引擎存储索引的缓存大小。虽然当前一般都是使用的innodb存储引擎,但还存在临时磁盘表的情况,但需要的内存不多,一般设置为32M左右即可。
  • sort_buffer_size
    执行排序的内存大小,需要设置合理大小,避免发生基于磁盘文件排序,发生IO,降低效率,一般设置为2M左右即可,如下rds配置:
    在这里插入图片描述
  • query_cache_size
    查询缓存大小,如果是读多写少的场景可以考虑设置,但是一般都是关闭的,因为维护缓存的成本比较高,单个表改变,将会导致相关的所有的缓存全部失效,如下rds配置:
    在这里插入图片描述
  • max_allowed_packet
    允许的最大包大小,一般给个较大个值即可,避免出现比较大的sql时无法执行,如500M,1G这种,如下rds配置:
    在这里插入图片描述
  • join_buffer_size
    执行表连接的缓存大小,设置一个合理的值,可以加快表连接的效率,一般设置为1M左右即可,如下rds而配置:
    在这里插入图片描述
  • thread_cache_size
    线程缓存大小,提高线程的复用率,减少线程的重复创建,提高效率。

2.1.3:innodb相关变量

因为innodb比较重要,目前用的最多,所以单独看下其相关的变量。

  • innodb_buffer_pool_size
    设置索引内存缓存的大小,因为innodb数据就是存储在索引上的,所以一般该值可以设置的较大,总内存的80%左右即可。
  • innodb_flush_log_at_trx_commit
    该参数用来控制修改写入到redo log的策略,修改最终写入到磁盘需要经过redo log buffer->page cache->redo log磁盘文件,如下图:
    在这里插入图片描述

该参数可能的取值有如下三个:

0:每次只写到redo log buffer中,此时如果数据库异常重启将会导致数据丢失,因为后台线程刷盘每一秒钟执行一次,所以最多会有一秒钟的数据丢失,不建议设置该值。
1:每次都会将数据写到redo log磁盘文件中,这种方式可以保证数据不丢失,但是每次事务提交都要发生磁盘IO,所以性能不会很好,如果你的系统压力不是特别大,建议设置该值,否则不建议设置。
2:每次都会将数据写到page cache中,此时数据已经写到操作系统的缓存中,所以MySQL服务器本身的异常重启,不会丢失数据,但是如果是机器掉电,还是会丢失数据,但掉电概率相对较低,如果是对性能要求较高,可以考虑该值

总结如图:
在这里插入图片描述

一般情况下,数据安全才是第一位的,所以该值一般设置为1,如下是我司线上环境rds配置:
在这里插入图片描述

当然如果经过业务的分析,允许少量数据丢失的话,并且对性能要求比较高可以考虑将该值设置为2,但是不建议设置为0,因为丢失数据的风险太高了,且0在性能表现上并不比2好太多。

  • innodb_thread_concurrent
    限制并发执行查询的线程的数据量,当事务处于空闲时,以及处于锁等待时,对应的线程是不占用innodb_thread_concurrent的,比如某一时刻执行了一个事务,当该事务执行查询是innodb_thread_concurrent=1,当该事务空闲,或者是因为被其他事务的行锁阻塞时,innodb_thread_concurrent会减1,变为0,即innodb_thread_concurrent只有正在消耗CPU资源的线程才做基数,如下:
时刻1:事务A开始并执行一个查询,开始消耗CPU资源,innodb_thread_concurrent变为1
时刻2:在事务A的查询结束前事务B开始,并执行一个查询,开始消耗CPU资源,innodb_thread_concurrent+1变为2
时刻3:事务A查询依然没有结束,事务B被事务A的间隙锁阻塞等待,因为此时事务B不在消耗CPU资源,所以innodb_thread_concurrent-1,变为1
时刻4:事务A结束,innodb_thread_concurrent-1变为0
时刻5:事务B结束锁等待,开始执行查询,开始消耗CPU资源,innodb_thread_concurrent+1变为1
时刻6:事务B结束,innodb_thread_concurrent-1变为0

最后再看一个设置innodb_thread_concurrent为3,阻塞主第四个事务查询的例子,如下图:
在这里插入图片描述

实践上,不建议将该值设置为0,此时不限制线程数,可能会导致过多的线程,而导致严重上下文切换,引起性能问题,一般建议设置在64~128之间,具体的值可以根据具体压测的情况来确定。

注意的就是:如果一个线程某个时刻不占用CPU资源,则不占用innodb_thread_concurrent的计数。

  • innodb_log_buffer_size
    设置innodb日志缓冲区的大小,合理的设置该值可以有效的减少写redo带来的磁盘IO开销,一般建议设置不要超过64M(MySQL本身的限制),如下是我司设置的为8M:
    在这里插入图片描述

如下是极客时间AI给出的答案,很全面,也截图放在这里:
在这里插入图片描述

  • innodb_log_file_size
    设置日志文件大小,即redo log单个文件的大小,可以根据情况设置为一个较大的值,官方建议为总内存的1/2到1/4,同时需要注意,不要随意修改该值,因为修改该值需要删除老的logfile,并且需要重启服务器,还存在数据丢失的风险,如下是极客时间给出的答案:
    在这里插入图片描述
  • innodb_log_files_in_group
    设置redo log文件的个数,默认值为2,innodb_log_files_in_group*inndb_log_file_size的值就是redo log文件的总大小。一般建议设置1到4个,正常使用默认值即可。设置为2的好处是可以分离插入数据的操作和更新删除数据的操作,提高并发性能。如下是极客时间AI给出的答案:
    在这里插入图片描述
  • read_buffer_size
    查询操作从磁盘读取数据发送给客户端的缓冲区大小,如果是查询数据量较大可以考虑设置512k,1M这类比较大的值,如果是查询数据量不大可设置较小值,注意该值不可设置过大,避免内存占用过大影响其他的操作,以及增大响应客户端的延迟。
  • read_rnd_buffer_size
    read_rnd_buffer_size,用于设置read rdn buffer的大小,read rnd buffer是MRR 优化用到的缓冲区,该缓冲区用于对将要访问索引的一组数据进行排序,进而能够尽量的顺序读盘,提升性能,该值一般给1M即可,也可以根据具体情况调整该值,但不可设置过大,影响其他操作。
  • bulk_insert_buffer_size
    临时存储大量插入数据的内存区域,该值默认是16M,如果是有大量的输入插入可适当的调大该值,如64M。

2.1.4:表设计相关优化

  • 存储引擎选择
    常用的存储引擎有innodb。myisam,memory,archive,比如如下:
    在这里插入图片描述
  • 字段类型
    使用尽量小的字段类型,减少存储,内存成本,提高网络传输效率,进而提高数据查询的速度。云厂商数据库1G每年的存储成本大概是10元人民币,所以,不必要的过大数据类型也会带来不必要的成本支出。

你设计的数据不仅仅存储在你的业务数据库,还有有多个slave,数据还可能同步到大数据部门进行,所以这个数据影响的范围会进一步增大。

  • 外键
    不要使用外键,而由业务控制表关系。
  • 触发器
    不要使用触发器,降低不必要的性能开销。
  • 文件,图片存储
    不要直接存储文件,图片数据本身,因为数据较大,存储成本高,而是将文件,图片存储到文件服务器,数据库只存储文件服务器的标识即可。
  • 索引创建
    不能滥用索引,例如某联合索引包含某单个索引,则可删除单个索引,降低磁盘占用,以及数据变更对索引的维护成本。

写在后面

参考文章列表

让人敬佩的白发程序员——MySQL/MariaDB之父Monty阿里交流会 。

范式通俗理解:1NF、2NF、3NF和BNCF 。

数据库范式详细介绍(1NF,2NF,3NF,BCNF,4NF) 。

MySQL历史,名称由来及版本 。

23 | MySQL是怎么保证数据不丢的? 。

29 | 如何判断一个数据库是不是出问题了? 。

35 | join语句怎么优化? 。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/33674.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

商业智能BI,如何区别联机事务处理(OLTP)和联机分析处理(OLAP)

商业智能(Business Intelligence,简称:BI),又称商业智慧或商务智能,指用现代数据仓库技术、线上分析处理技术、数据挖掘和数据展现技术进行数据分析以实现商业价值。 商业智能BI - 派可数据数据可视化分析平台 定义为下列软件工具…

CAD随机粗糙度表面插件

插件介绍 CAD随机粗糙度表面插件可用于在AutoCAD软件内生成随机高度分布的表面三维实体模型,适用于科研论文绘图、有限元建模、随机地形模拟等方面的应用。 插件可指定的参数有三维模型的长、宽、高;随机粗糙度表面信息中网格尺寸控制模型生成的精细程…

解决idea编辑application.yml文件或properties文件没有提示问题

注意:这里说的没有提示,是针对application.properties和application.yml文件 解决办法:在idea的插件面板中,禁用或卸载 wl Spring Assistant插件即可解决问题。

做BI领域的ChatGPT,思迈特升级一站式ABI平台

8月8日,以「指标驱动 智能决策」为主题,2023 Smartbi V11系列新品发布会在广州丽思卡尔顿酒店开幕。 ​ 后疫情时代,BI发展趋势的观察与应对 在发布会上,思迈特CEO吴华夫在开场致辞中表示,当前大环境背景下&#xf…

K8S系列文章之 离线安装自动化工具Ansible

参考 文档 离线安装 Ansible - DevOps - dbaselife 一、Ansible简介 Ansible是一款开源的IT配置管理工具,常被IT界的小伙伴们用于自动化的场景,多用在服务部署、配置管理方面。配置文件采用最常见的yaml格式,学习起来也是比较容易&#xff…

【分布式系统】聊聊高性能设计

每个程序员都应该知道的数字 高性能 对于以上的数字,其实每个程序员都应该了解,因为只有了解这些基本的数字,才能知道对于CPU、内存、磁盘、网络之间数据读写的时间。1000ms 1S。毫秒->微秒->纳秒-秒->分钟 为什么高性能如此重要的…

数据结构刷题训练:用栈实现队列(力扣OJ)

目录 前言 1. 题目:用栈实现队列 2. 思路 3. 分析 3.1 定义 “ 队列 ” 3.2 创建队列 3.3 入队 3.4 队头数据 3.5 出队 3.6 判空和销毁 4.题解 总结 前言 栈和队列是数据结构中的两个重要概念,它们在算法和程序设计中都有着广泛的应用。本文将带你深入了…

kube-prometheus 使用 blackbox-exporter 进行icmp 监控

安装kube-prometheus 后默认在monitoring namespace中有创建 blackbox-exporter deployment。但默认没有icmp的module配置,无法执行ping探测。因为即使有icmp module,默认配置也是无法执行ping探测的(这篇文章要解决的就是这个问题&#xff0…

中科亿海微FIFO使用

引言 FPGA(现场可编程门阵列)是一种可编程逻辑器件,具有灵活性和可重构性,广泛用于数字电路设计和嵌入式系统开发。在FPGA中,FIFO(First-In, First-Out)是一种常见的存储器结构,用于…

读《Flask Web开发实战》(狼书)笔记 | 第1、2章

前言 2023-8-11 以前对网站开发萌生了想法,又有些急于求成,在B站照着视频敲了一个基于flask的博客系统。但对于程序的代码难免有些囫囵吞枣,存在许多模糊或不太理解的地方,只会照葫芦画瓢。 而当自己想开发一个什么网站的时&…

【云原生】Kubernetes 概述

Kubernetes 概述 1.Kubernetes 简介 Kubernetes 是一个可移植的、可扩展的、用于管理容器化工作负载和服务的开源平台,它简化(促进)了声明式配置和自动化。它有一个庞大的、快速增长的生态系统。Kubernetes 的服务、支持和工具随处可见。 K…

消息队列kafka及zookeeper机制

一、zookeeper1.1 zookeeper简介1.2 zookeeper工作机制1.3 Zookeeper特点1.4 Zookeeper 数据结构1.5 Zookeeper 应用场景1.5.1 统一命名服务1.5.2 统一配置管理1.5.3 统一集群管理1.5.4 服务器动态上下线1.5.5 软负载均衡 1.6 Zookeeper 选举机制1.6.1 第一次启动选举机制1.6.2…

Jenkins 使用

Jenkins 使用 文章目录 Jenkins 使用一、jenkins 任务执行二、 Jenkins 连接gitee三、Jenkins 部署静态网站 一、jenkins 任务执行 jenkins 创建 job job的名字最好是有意义的 restart_web_backend restart_web_mysql[rootjenkins ~]# ls /var/lib/jenkins/ config.xml …

W5500-EVB-PICO作为TCP Client 进行数据回环测试(五)

前言 上一章我们用W5500-EVB-PICO开发板通过DNS解析www.baidu.com(百度域名)成功得到其IP地址,那么本章我们将用我们的开发板作为客户端去连接服务器,并做数据回环测试:收到服务器发送的数据,并回传给服务器…

SAP MM学习笔记16-在库品目评价

在库品目评价是指评估物料。具体比如物料价格,数量,保管场所等发生变化的时候,判断是否发生了变化,要不要生成 FI票,用哪个FI科目来进行管理等内容就叫在库品目评价。 在库品目评价有很多层级,这里先讲3兄弟…

在Linux虚拟机内配置nginx以及docker

目录 1、nginx源码包编译以及安装依赖 1、配置安装所需的编译环境 2、安装函数库(pcre、zlib、openssl) 2、安装nginx 1、获取源码包 2、解压编译 3、启动nginx服务 1、关闭防火墙 2、运行nginx 3、使用本地浏览器进行验证 3、安装docker 1、…

每次执行@Test方法前都执行一次DB初始化(SpringBoot Test + JUnit5环境)

引言 在执行单元测试时,可以使用诸如H2内存数据库替代线上的Mysql数据库等,如此在执行单元测试时就能尽可能模拟真实环境的SQL执行,同时也无需依赖线上数据库,增加了测试用例执行环境的可移植性。而使用H2数据库时,通…

Oracle DB 安全性 : TDE HSM TCPS Wallet Imperva

• 配置口令文件以使用区分大小写的口令 • 对表空间进行加密 • 配置对网络服务的细粒度访问 TCPS 安全口令支持 Oracle Database 11g中的口令: • 区分大小写 • 包含更多的字符 • 使用更安全的散列算法 • 在散列算法中使用salt 用户名仍是Oracle 标识…

【JavaEE】Spring Boot - 日志文件

【JavaEE】Spring Boot 开发要点总结(3) 文章目录 【JavaEE】Spring Boot 开发要点总结(3)1. 日志有什么作用2. 日志格式2.1 日志框架原理 3. 日志的打印3.1 System.out.println3.2 使用日志框架3.3 日志级别3.3.1 设置默认日志显…

深度学习(36)—— 图神经网络GNN(1)

深度学习(36)—— 图神经网络GNN(1) 这个系列的所有代码我都会放在git上,欢迎造访 文章目录 深度学习(36)—— 图神经网络GNN(1)1. 基础知识2.使用场景3. 图卷积神经网…