高性能MYSQL(学习笔记)-Schema与数据类型优化1

本文介绍了MySQL中各种数据类型的使用场景及优化策略,包括整数、实数、字符串、日期时间等类型的选择技巧,并讨论了范式与反范式的设计原则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Schema与数据类型优化

选择优化的数据类型

选择正确的数据类型对于获得高性能至关重要,下面几个原则可以帮助你做出更好的选择。

更小的通常更好

一般情况下尽量使用可以正确存储数据的最小数据类型,更小的数据类型通常更快,因为他们占用更少的磁盘、内存和CPU缓存,并且处理时需要的CPU周期也更少。

简单就好

简单数据类型的操作通常需要更少的CPU周期。整型比字符串操作代价更低,因为字符集和校对规则使字符比较比整数型比较更复杂。

尽量避免NULL

可以为NULL的列需要更多的存储空间,在MySQL里面也需要特殊处理,当可以为NULL的列被索引时,每个索引记录需要一个额外的字节。

在为列选择数据类型时,第一步需要确定合适的大类型:数字、字符串、时间等,下一步是选择具体类型,例如TIMESTAMP和DATETIME都可以存储相同类型的数据,但是TIMESTAMP只使用了DATETIME一半的存储空间,并且会根据时区变化,具有特殊的自动更新能力。

整数类型

有两种类型的数字:整数和实数。如果存储整数,可以使用这几种整数类型:TINYINT(8位),SMALLINT(16位),DEDIUMINT(24位),INT(32位), BIGINT(64位)存储空间。

整数类型可以有UNSIGNED,表示不允许出现负值,这大致可以使正数的上限提高一倍,例如TINYINT UNSIGNED 可以存储的范围是:0-255。MySQL可以为整数类型指定宽度,例如INT(11),对大多数应用这是没有意义的:它不会限制值的合法范围,只是规定了MySQL交互工具来显示字符的个数。对于存储和计算来说,INT(1)和INT(20)是一样的。

实数类型

     实数是带有小数部分的数字,FLOAT和DOUBLE类型支持使用标准的浮点运算和近似计算。DECIMAL类型用于存储精确的小数,DECIMAL(18,9)表示小数点两边将各存储9个数字,一共使用9个字节:小数点钱的数字用4个字节,小数点后的数字用4个字节,小数点本身占1个字节。有多种方法可以指定浮点列所需要的精度,这会使得MySQL使用不同的数据类型,或者在存储时对值进行取舍。

字符串类型

MySQL可以对每个字符串列定义自己的字符集和排序规则,或者说校对规则。

VARCHAR 和 CHAR类型

VARCHAR类型用于存储可变长字符串,是最常见的字符串类型。它比定长类型更节省空间,因为它仅使用必要的空间(越短的字符串使用越少的空间)VARCHAR需要额外的1或者2个字节记录字符串的长度:如果列的最大长度小于或者等于255字节,则只使用1个字节表示,否则使用2个字节。例如VARCHAR(10)的列,需要11个字节的存储空间。但是在UPDATE时候需要使行变得更长,导致需要额外的工作。下面这些情况使用VARCHAR是合适的:字符串列的最长长度比平均长度大很多;列的更新很少,碎片不是问题;使用了像UTF-8这样复杂的字符集,每个字符都使用不同的字节数进行存储。

CHAR 类型是定长的:MySQL总是根据定长的字符串长度分配足够的空间。当存储CHAR值时,CHAR值会根据需要采用空格进行填充以方便比较。CHAR适合存储很短的字符串,或者所有值都接近同一个长度,对于经常更改的数据,CHAR比VARCHAR更好,因为定长的CHAR类型不容易产生碎片。

慷慨是不明智的~

VARCHAR(5)和VARCHAR(200)存储‘HELLO’空间开销是不一样的,更长的列会消耗更多的内存,因为MySQL通常会分配固定大小的内存块来保存内部值,尤其是使用内存临时表进行排序或操作时会特别糟糕。

BOLO和TEXT类型

BLOB和TEXT都是为存储很大的数据而设计的字符串数据类型,分别采用二进制和字符方式存储。

他们属于不同的数据类型家族,

字符类型:  TINYTEXT,SMALLTEXT,TEXT,MEDIUMTEXT,LONGTEXT

二进制类型:TINYBLOB,SMALLBLOB,BLOB,MEDIUMBOLOB,LONGBLOB

MySQL将BLOB和TEXT当做一个对象来处理,当BLOB和TEXT太大时,INNOBD会专门用外部存储区域来进行存储,此时每个值在行内需要1-4字节存储一个指针,然后在外部存储区域存储实际的值。

BLOB存储的是二进制数据,没有排序规则和字符集,而TEXT有字符集和排序规则。尽量不要使用TEXT和BLOB

使用枚举(ENUM)代替字符串类型

    有时候可以使用枚举列代替常用的字符串类型,枚举列可以把一些不重复的字符串存储成一个预定义的集合,MySQL在存储时候非常紧凑,会根据列表值的数量压缩到一个或两个字节中,内部存储是整数而不是字符串。

日期和时间类型

DATETIME:这个类型能保存大范围的值,从1001年到9999年,精度为妙,它把日期和时间封装格式为YYYYMMDDHHMMSS的整数中,与时区无关,使用8个字节存储空间。

TIMESTAMP:TIMESTAMP类型保存1970年1月1日午夜以来的妙数,它和UNIX时间。使用4个字节存储空间。只能存储1970年到2038年。尽可能使用TIMESTAMP,存储空间效率更高。

位数据类型

BIT列在一列中存储一个或多个true/false值,BIT(1)定义一个包含单个位的字段,BIT(2)存储2个位,BIT最大的长度是64位,MySQL把BIT当作字符串类型而不是整数类型,检索BIT(1)结果是一个包含二进制0或者1而不是ASCII的“0”或者“1”。应该谨慎使用BIT类型!

选择标识符

标识符选择合适的数据类型非常重要,通常作为关联表的外键来使用,整数通常是标识列的最好选择,因为他们很快并且可以使用AUTO_INCREMENT

ENUM和SET类型,尽量不使用

字符串类型:避免使用,它们很消耗空间,而且比数字类型慢。对性能有较大的影响!

当使用随机的字符串也需要多加注意,例如MD5()/SHA1()/UUID()产生的字符串。

随机插入值会随机地写到索引的不同位置,所以使用INSERT语句变慢,会导致页分裂、磁盘随机访问,SELECT语句变得很慢,逻辑上相邻的行会分布到磁盘和内存的不同地方。

随机值导致缓存对所有类型的查询语句效果比较差。

特殊类型数据,IPV4地址经常使用VARCHAR(15)列来存储IP地址,然而他们实际上是32位无符号整数,不是字符串。用小数点将地址分成四段表示是为了让人们阅读容易。应该使用无符号整数存储IP地址,mysql使用INET_ATON()和INET_NTOA()函数在这两种表示方法之间转换。

MySQL schema设计中的陷阱

太多的列:MySQL的存储引擎API工作时需要服务器层和引擎层之间通过缓冲格式拷贝数据,然后在服务器层将缓冲内容解码成各个列。

太多的关联:所谓的实体-属性-值设计模式是一个常见的糟糕设计模式,MySQL最多只能关联操作61张表,太多的关联解析和优化查询代价很高,建议每一个查询最好在12个表内做关联。

全能的枚举:枚举设计应该是用整数作为外键关联到字典表后者查找表来查找具体值。

非此发明的NULL:需要存储一个空值到表中时候,也许可以使用0,某个特殊值、空字符串来代替。避免使用NULL!

范式和反范式

     范式化的数据库中,每个事实数据会出现并且出现一次,反范式化中,信息是冗余的,可能存储在多个地方。

范式化的优点和缺点

优点:

1、  范式的更新操作通常比反范式更快

2、  当数据较好地范式化时,就只有很少或者没有重复数据,所以只需要修改更少的数据

3、  范式化的表通常很小,可以更好地放在内存里,所以执行速度更快

4、  没有多余的数据意味着检索列表数据时更少需要DISTINCT或者GROUP BY语句,在非范式画的结构中需要通过GROUP BY 来获得唯一的部门表。

缺点:

范式化设计schema通常需要关联,稍微复杂一些的查询语句在符合范式的schema上都可能需要至少一次关联,可能导致一些索引策略无效.

反范式的优点和缺点:

反范式的schema因为所有数据都在一张表中,可以很好的避免关联。不需要关联的时候,最差情况是全表扫描,比关联要快很多,因为避免了随机I/O

单独的表也能使用更有效的索引策略。

混用范式话和反范式话

实际应用中经常使用混用,最常见的反范式话数据的方法是复制或者缓存,在不同的表中存储相同的特定列,使用触发器更新缓存值。当更新数据的时候,特定列需要更新两次,这时候要评估更新的频率和更新的时长,并和执行SELECT 查询的频率进行比较。

另外一个从父表中冗余数据到字表是由于排序的需要,例如在范式化的schema里面通过作者的名字对消息走排序的代价将会非常高,但是如果在message中缓存author_name字段并建立好索引,则可以非常高效的完成排序。

  总结

MySQL始终坚持简单,需要使用数据库的人应该也同样会喜欢简单的原则:

1、  尽量避免过度设计

2、  使用小而简单的合适数据类型,除非真的需要,尽可能避免使用NULL值。

3、  尽量使用相同数据类型存储相似或者相关的值,尤其是在关联表中使用的列

4、  注意可变长字符串,在临时表和排序时可能导致悲观的按最大长度分配内存

5、  尽量使用整型定义标识列

6、  避免使用MySQL丢弃的特性,例如指定浮点数精度、整数的显示宽度

7、  小心使用ENUM和SET,最好避免使用SET.

范式是好的,但是非范式也是必须的。

1. 用户身体信息管理模块 用户信息管理: 注册登录:支持手机号 / 邮箱注册,密码加密存储,提供第三方快捷登录(模拟) 个人资料:记录基本信息(姓名、年龄、性别、身高、体重、职业) 健康目标:用户设置目标(如 “减重 5kg”“增肌”“维持健康”)及期望周期 身体状态跟踪: 体重记录:定期录入体重数据,生成体重变化曲线(折线图) 身体指标:记录 BMI(自动计算)、体脂率(可选)、基础代谢率(根据身高体重估算) 健康状况:用户可填写特殊情况(如糖尿病、过敏食物、素食偏好),系统据此调整推荐 2. 膳食记录食物数据库模块 食物数据库: 基础信息:包含常见食物(如米饭、鸡蛋、牛肉)的名称、类别(主食 / 肉类 / 蔬菜等)、每份重量 营养成分:记录每 100g 食物的热量(kcal)、蛋白质、脂肪、碳水化合物、维生素、矿物质含量 数据库维护:管理员可添加新食物、更新营养数据,支持按名称 / 类别检索 膳食记录功能: 快速记录:用户选择食物、输入食用量(克 / 份),系统自动计算摄入的营养成分 餐次分类:按早餐 / 午餐 / 晚餐 / 加餐分类记录,支持上传餐食照片(可选) 批量操作:提供常见套餐模板(如 “三明治 + 牛奶”),一键添加到记录 历史记录:按日期查看过往膳食记录,支持编辑 / 删除错误记录 3. 营养分析模块 每日营养摄入分析: 核心指标计算:统计当日摄入的总热量、蛋白质 / 脂肪 / 碳水化合物占比(按每日推荐量对比) 微量营养素分析:检查维生素(如维生素 C、钙、铁)的摄入是否达标 平衡评估:生成 “营养平衡度” 评分(0-100 分),指出摄入过剩或不足的营养素 趋势分析: 周 / 月营养趋势:用折线图展示近 7 天 / 30 天的热量、三大营养素摄入变化 对比分析:将实际摄入推荐量对比(如 “蛋白质摄入仅达到推荐量的 70%”) 目标达成率:针对健
1. 用户管理模块 用户注册认证: 注册:用户填写身份信息(姓名、身份证号、手机号)、设置登录密码(需符合复杂度要求),系统生成唯一客户号 登录:支持账号(客户号 / 手机号)+ 密码登录,提供验证码登录、忘记密码(通过手机验证码重置)功能 身份验证:注册后需完成实名认证(模拟上传身份证照片,系统标记认证状态) 个人信息管理: 基本信息:查看 / 修改联系地址、紧急联系人、邮箱等非核心信息(身份证号等关键信息不可修改) 安全设置:修改登录密码、设置交易密码(用于账等敏感操作)、开启 / 关闭登录提醒 权限控制:普通用户仅能操作本人账户;管理员可管理用户信息、查看系统统计数据 2. 账户资金管理模块 账户管理: 账户创建:用户可开通储蓄卡账户(默认 1 个主账户,支持最多 3 个子账户,如 “日常消费账户”“储蓄账户”) 账户查询:查看各账户余额、开户日期、状态(正常 / 冻结)、交易限额 账户操作:挂失 / 解挂账户、申请注销账户(需余额为 0) 资金操作: 账汇款:支持同行账(输入对方账户号 / 手机号),需验证交易密码,可添加常用收款人 存款 / 取款:模拟存款(输入金额增加余额)、取款(输入金额减少余额,需不超过可用余额) 交易记录:按时间、类型入 / 出 / 存款 / 取款)查询明细,显示交易时间、金额、对方账户(脱敏显示)、交易状态 3. 账单支付模块 账单管理: 月度账单:自动生成每月收支明细,统计总收入、总支出、余额变动 账单查询:按月份、交易类型筛选账单,支持导出为 Excel 格式 还款提醒:若有贷款(简化版可模拟),系统在还款日 3 天前发送提醒 快捷支付: 绑定支付方式:添加银行卡(系统内账户)作为支付渠道 模拟消费:支持输入商户名称金额,完成支付(从账户余额扣减) 支付记录:保存所有消费记录,包含商户、时间、金额、支付状态 4.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值