首页 > 数据库 >数据库基础

数据库基础

时间:2022-10-08 10:35:29浏览次数:91  
标签:存储 范式 字节 数据库 基础 char 类型 varchar

1 范式化设计

1.1 第一范式(1NF)无重复的列

定义

所谓第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。如果出现重复的属性,就可能需要定义一个新的实体,新的实体由重复的属性构成,新实体与原实体之间为一对多关系。在第一范式(1NF)中表的每一行只包含一个实例的信息。简而言之,第一范式就是无重复的列。

image-20220919091324610

上面这张表就不符合第一范式,有重复的列,应该将 name-age 拆分成 name 和 age 两个列

1.2 第二范式(2NF)属性完全依赖于主键

定义

第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。第二范式(2NF)要求数据库表中的每个实例或行必须可以被惟一地区分。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。这个惟一属性列被称为主关键字或主键、主码。

image-20220919100708607

上面这张订单表,我们看到订单 id 为 1 的订单包含了两个产品,没有一个唯一的列被称为关键字,所以需要加上一个关键字主键

这张表需要优化成

订单表主表:

image-20220919100957960

订单表明细

image-20220919101125045

这样订单明细表中就依赖关键字 id,id 是唯一的主键,符合第二范式

1.3 第三范式(3NF)属性不依赖于其它非主属性

满足第三范式(3NF)必须先满足第二范式(2NF)。第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。

image-20220919091946856

上面这个订单表的设计,它依赖的商品信息过多,应该将商品信息拆分出来一张表单独存放

image-20220919092221757

商品表中存储商品相关信息,订单表中只存放商品 id,不存储名称等信息

总结

在日常工作中,我们在数据库设计方面基本上满足以上三个范式就可以了,至于BCNF范式第四范式(4NF) 作为了解即可

2 数据库常用类型

设计表时类型选择应该遵循以下几个规则

1、更小的字段,CPU 处理周期更少

2、简单就好

3、尽量避免 NULL

2.1 整数类型

类型 字节数 说明
tinyint 1 字节 对应 Java 中的 boolean 类型
smallint 2 字节
mediumint 3 字节
int 4 字节
bigint 8 字节 对应 Java 中的 Long 类型

无符号

在数据库管理工具中我们进程见到无符号这个选项

image-20220919102426328

勾选了无符号,说明这个字段只能存储正数,有符号则存储范围是负数~正数

2.2 实数类型

MySQL 实数有三种类型,floatdoubledecimal

类型 说明 字节数
float 单精度浮点数 4 个字节
double 双精度浮点数 8 个字节
decimal(M, D) 压缩的“严格”定点数 M + 2 个字节

实数类型通常用于存储有小数的场景下,比如金额,重量等

博主在使用 MySQL 中这几个类型使用较少,这里给大家提供一些金额类字段存储的设计思路

我们存储金额一般会精确到分,比如 12.54 元,那么在存储的时候我们可以用整型,将 12.54 * 100 存储数据库中,取出的时候再进行相应的转化。有的同学可能会有疑问,这样做不是很麻烦。为什么这么做,这里就涉及到计算的精度问题了,如果计算时发现需要四舍五入,那么就可以考虑将数值乘以相应的倍数,100、1000 倍

2.3 字符串类型

类型 长度范围 字节数
char(M) 0 <= M <=255 M 个字节
varchar(M) 0 <= M <= 65535 M + 1 个字节
enum 1 <= M <= 65535 1或者2 个字节
tinytext 0 <= M <=255 M + 2 个字节
text 0 <= M <= 65535 M + 2 个字节
mediumtext 0 <= M <= 16777215 M + 3 个字节
longtext 0 <= M <= 4294967295 M + 4 个字节

工作中常用的就是 char、varchar 和 text 类型

char

  • char(M) 类型一般需要预先定义字符串长度。如果不指定(M),则表示长度默认是1个字符。
  • char 是定长字符串,保存数据时,数据的实际长度比 char 类型声明的长度小,则会在右侧填充空格以达到指定的长度。当MySQL检索 char 类型的数据时,char 类型的字段会去除尾部的空格。
  • 定义 char 类型字段时,声明的字段长度即为 char 类型字段所占的存储空间的字节数。

varchar

  • varchar 使用时,必须指定长度,不指定则会报错
  • varchar 因为是变长字符串,需要额外地在长度列表上存放实际的字符长度:小于255为1个字节,大于255则要2个字节
  • varchar 是变长字符串,比如说 varchar(10),你存储了 "ok",那么 varchar 实际存储就是两个字节,而 char(10) 则是存储了 10 个字节
  • 在不同的字符集下,varchar 的大小是不一样的,很多人可能会试过,varchar 最大可用存储 65535 个字节,为什么我设置 65535 会报错,这是因为我们存储通常用的是 utf8 字符集,在 utf8 字符集下,每个字符占用 3 个字节,所以在 utf8 字符集下 varchar(N) 中的N 最大为 (65535-1-2)/3

char 和 varchar 如何选择

1、存储很短的信息。比如门牌号码101,201……这样很短的信息应该用char,因为varchar还要占个byte用于存储信息长度,本来打算节约存储的,结果得不偿失。

2、固定长度的。比如使用uuid作为主键,那用char应该更合适。因为他固定长度,varchar动态根据长度的特性就消失了,而且还要占个长度信息。

3、十分频繁改变的column。因为varchar每次存储都要有额外的计算,得到长度等工作,如果一个非常频繁改变的,那就要有很多的精力用于计算,而这些对于char来说是不需要的。

扩展

4.0版本以下,varchar(20),指的是20字节,如果存放UTF8汉字时,只能存6个(每个汉字3字节)
5.0版本以上,varchar(20),指的是20字符,无论存放的是数字、字母还是UTF8汉字(每个汉字3字节),都可以存放20个,最大大小是65532字节

gbk:每个字符最多占用2个字节
utf8:每个字符最多占用3个字节

text

text 通常用于存储大文本,比如文章,评论等

3 设计规范

以下设计规范出自阿里巴巴开发手册

  1. 【强制】表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 unsigned tinyint

(1 表示是,0 表示否)。

说明:任何字段如果为非负数,必须是 unsigned。

注意:POJO 类中的任何布尔类型的变量,都不要加 is 前缀,所以,需要在设置

从 is_xxx 到 Xxx 的映射关系。数据库表示是与否的值,使用 tinyint 类型,坚持 is_xxx 的

命名方式是为了明确其取值含义与取值范围。

正例:表达逻辑删除的字段名 is_deleted,1 表示删除,0 表示未删除。

  1. 【强制】表名、字段名必须使用小写字母或数字,禁止出现数字开头,禁止两个下划线中间只

出现数字。数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑。

说明:MySQL 在 Windows 下不区分大小写,但在 Linux 下默认是区分大小写。因此,数据库名、

表名、字段名,都不允许出现任何大写字母,避免节外生枝。

正例:aliyun_admin,rdc_config,level3_name

反例:AliyunAdmin,rdcConfig,level_3_name

  1. 【强制】表名不使用复数名词。

说明:表名应该仅仅表示表里面的实体内容,不应该表示实体数量,对应于 DO 类名也是单数

形式,符合表达习惯。

  1. 【强制】禁用保留字,如 desc、range、match、delayed 等,请参考 MySQL 官方保留字。

  2. 【强制】主键索引名为 pk_字段名;唯一索引名为 uk_字段名;普通索引名则为 idx_字段名。

说明:pk_ 即 primary key;uk_ 即 unique key;idx_ 即 index 的简称。

  1. 【强制】小数类型为 decimal,禁止使用 float 和 double。

说明:float 和 double 在存储的时候,存在精度损失的问题,很可能在值的比较时,得到不

正确的结果。如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数分开存储。

  1. 【强制】如果存储的字符串长度几乎相等,使用 char 定长字符串类型。

  2. 【强制】varchar 是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长

度大于此值,定义字段类型为 text,独立出来一张表,用主键来对应,避免影响其它字段索

引效率。

  1. 【强制】表必备三字段:id, gmt_create, gmt_modified。

说明:其中 id 必为主键,类型为 bigint unsigned、单表时自增、步长为 1。gmt_create,

gmt_modified 的类型均为 datetime 类型,前者现在时表示主动创建,后者过去分词表示被

动更新。

  1. 【推荐】表的命名最好是加上“业务名称_表的作用”。

正例:alipay_task / force_project / trade_config

  1. 【推荐】库名与应用名称尽量一致。

  2. 【推荐】如果修改字段含义或对字段表示的状态追加时,需要及时更新字段注释。

  3. 【推荐】字段允许适当冗余,以提高查询性能,但必须考虑数据一致。冗余字段应遵循:

1)不是频繁修改的字段。

2)不是 varchar 超长字段,更不能是 text 字段。

正例:商品类目名称使用频率高,字段长度短,名称基本一成不变,可在相关联的表中冗余存

储类目名称,避免关联查询。

  1. 【推荐】单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。

说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。

  1. 【参考】合适的字符存储长度,不但节约数据库表空间、节约索引存储,更重要的是提升检

索速度。

4 常用 SQL 语句

常用 SQL 语句可以看我之前写的一篇博客,里面详细记录了常用的查询语句

数据库SQL语句大全

标签:存储,范式,字节,数据库,基础,char,类型,varchar
From: https://www.cnblogs.com/wugongzi/p/16768161.html

相关文章

  • golang各类数据库连接方式
    常用数据库驱动列表//odbc_"github.com/alexbrainman/odbc"//mssql_"github.com/denisenkom/go-mssqldb"//mysql_"github.com/go-sql-d......
  • ruby基础2
    ruby条件运算符c=(a<b)?a:b当a<b时取c=a,否则取c=b使用范围运算符截取字符串txt="cardithea"putstxt[0..3]putstxt[0...3] 转整数to_i转浮点数to_f......
  • python-数据描述与分析2(利用Pandas处理数据 缺失值的处理 数据库的使用)
    2.利用Pandas处理数据2.1汇总计算当我们知道如何加载数据后,接下来就是如何处理数据,虽然之前的赋值计算也是一种计算,但是如果Pandas的作用就停留在此,那我们也许只是看到了......
  • 数据库结构差异比较-SqlServer
    /******Object:StoredProcedure[dbo].[p_comparestructure_2005]ScriptDate:2022/10/810:00:20******/SETANSI_NULLSONGOSETQUOTED_IDENTIFIERONGOALTER......
  • Java基础——封装
    一、什么是封装封装就是对象的属性和操作结合为一个整体,和并尽可能隐藏对象内部的细节。二、为什么要封装1.为了安全,提高程序的复用性,封装就是该漏的,该藏得藏。2.如果......
  • [转]Linux时间同步基础知识
    原文地址:Linux时间同步基础知识|云中君(gitee.io)总结:中国使用CST:ChinaStandardTime,中国标准时间,与原子钟报时的协调世界时(UTC)关系:比UTC早8个小时,记为UTC+8,使......
  • Java基础——方法
    一、定义方法1.除了main方法以外,我们还可以自己定义方法,方法是程序执行的最小单元。2.定义了方法可以直接调用,可以直接拿来用,缩小了代码的冗余。在Student类中定义方法......
  • spring boot集成redis基础入门
    redis支持持久化数据,不仅支持key-value类型的数据,还拥有list,set,zset,hash等数据结构的存储。可以进行master-slave模式的数据备份更多redis相关文档请查看redis官方文......
  • Java基础——类
    一、类1.类是对一类具有相同属性或者行为的事物的描述。类生成对象,在实际开发中通过对象处理我们的业务逻辑。2.定义类:例PublicclassStudent{//属性......
  • Java基础——对象
    区分对象:1.在外部通过引用指向的地址(直接打印引用)。2.在内部,通过this来区分。3.直接打印引用变量会调用toString方法。一、new了两个是指向两个地址Students1=new......