目录

选择优化的数据类型

整数类型

实数类型

字符串类型

日期和时间类型

位置据类型

选择标识符

特殊类型数据

MySQL schema 设计中的陷阱

范式和反范式

缓存表和汇总表

加快 ALTER TABLE 操作的速度

快速创建 MyISAM 索引


选择优化的数据类型

不管存储哪种数据类型,下面几个简单的原则都有助于做出更好的选择。

更好的通常更小

尽量使用可以正确存储数据的最小数据类型,但是要确保没有低估需要存储的值的范围,因为在schema中的多个地方增加数据类型的范围是一个非常耗时和痛苦的操作

简单就好

简单数据类型的操作通常需要更少的CPU周期

尽量避免NULL

列最好指定为 NOT NULL,除非确实可以是 NULL。如果查询中包含可为 NULL 的列,会使索引、索引统计和值比较都更复杂。当可为NULL的列被索引时,每个索引记录需要一个额外的字节,在MyISAM里甚至还可能导致固定大小的索引变成可变大小的索引。

把 NULL 列改为 NOT NULL 列带来的性能提升比较小,但是用于索引的列最好是 NOT NULL。另外,InnoDB 使用单独的位(bit)存储 NULL 值,包含很多 NULL 值的稀疏数据的空间效率比较高。

整数类型

可用的整型数据有:

TINYINT:8 bit

SMALLINT:16 bit

MEDIUMINT:24 bit

INT:32 bit

BIGINT:64 bit

所有的整数类型都支持 UNSIGNED 属性,表示无符号数据,例如 TINYINT UNSIGNED。有符号和无符号整型数据存储空间一样,性能一样。

MySQL 中可以为整数类型指定宽度,例如 INT(11),这个宽度只是规定了 MySQL 交互工具用来显示字符的个数,不影响存储和计算。

实数类型

可用的实数数据有:

浮点类型:

FLOAT:32 bit。不精确类型,支持浮点运算。

DOUBLE:64 bit。不精确类型,支持浮点运算。

DECIMAL:最多允许 65 个数字,例如 DECIMAL(33,32),DECIMAL(65,0)。可以存储精确的小数,也可以存储比 BIGINT 还大的整数,支持精确计算。因为 CPU 不支持对 DECIMAL 的直接计算,所以 MySQL 服务器自身实现了 DECIMAL 的高精度计算。

MySQL 支持精确类型(DECIMAL),也支持不精确类型(浮点类型,即 FLOAT 和 DOUBLE)。

FLOAT、DOUBLE 和 DECIMAL 类型都可以指定精度。例如 DOUBLE(12,3) 表示最多 9 位整数、3 位小数。DECIMAL(18,9) 表示小数点两边各存储 9 个数字,一共使用 9 个字节(小数点占一个字节)。

DECIMAL 需要的存储空间大,计算开销高,如果数据量很大,可以考虑用 BIGINT 替代 DECIMAL。例如金额需要保证 0.001 的精度,则可以将所有金额乘以 1000 后取整存入 BIGINT 类型的字段,从而避免浮点数计算不准确和 DECIMAL 精确计算代价高的问题。

字符串类型

VARCHAR 和 CHAR 类型

存储引擎存储CHAR或者VARCHAR值的方式在内存中和磁盘上可能不一样,所以MySQL服务器从存储引擎读出的值可能需要转换为另一种存储格式。

VARCHAR

  VARCHAR类型用于存储可变长字符串,比定长类型更省空间,因为它仅使用必要的空间,有一种情况例外,如果MySQL表使用ROW_FORMAT=FIXED创建,每一行都会使用定长存储,这会浪费空间。

VARCHAR需要使用1或者2个额外字节记录字符串的长度,如果列的最大长度小于或等于255字节,则只使用一个字节表示,否则使用两个字节。

在执行 UPDATA 操作时,如果需要增大行的长度,需要额外工作。如果磁盘当前页的空间不够,不同存储引擎的处理方式不同。MyISAM 会将行拆成不同的片段存储,InnoDB 则需要分裂页来使行可以放进页内。InnoDB 会把过长的 VARCHAR 存储为 BLOB。

CHAR

CHAR是定长的,MySQL总是根据定义的字符串长度分配足够的空间。当存储CHAR值时,MySQL会删除所有的末尾空格。(VARCHAR不会)

VARBINARY

二进制变长字符串,存储字节码而不是字符。

BINARY

二进制定长字符串,存储字节码而不是字符,使用 \0(零字节)填充而不是空格,且检索时不会去掉填充值。

适合使用 VARCHAR 的场景:

字符串列的最大长度比平均长度大得多

列很少更新,所以碎片不是问题

使用 UTF-8 字符集,每个字符用不同的字节数进行存储

适合使用 CHAR 的场景:

短字符串

定长字符串,例如密码的 HASH 值

经常变更的字符串,不易产生碎片

BLOB 和 TEXT 类型

BLOB:二进制方式存储大数据的字符串类型,没有字符集和排序规则。具体的类型有:TINYBLOB, SMALLBLOB, BLOB, MIDIUMBLOB, LONGBLOB

TEXT:字符方式存储大数据的字符串类型,有字符集和排序规则。具体的类型有:TINYTEXT, SMALLTEXT, TEXT, MIDIUMTEXT, LONGTEXT

在 MySQL中,每个BLOB 和TEXT类型的值都是独立对象。当值太大时,InnoDB还会使用专门的外部存储区域来存储,此时行内只需 1-4 个字节存储指针。

MySQL只对每个列的最前max_sort_length字节而不是整个字符串做排序,MySQL不能将BLOB和TEXT列全部长度的字符串进行索引,也不能使用这些索引消除排序。

ENUM 枚举类型代替字符串

有时可以使用枚举列代替常用的字符串类型,MySQL在内部会将每个值在列标中的位置保存为整数,并且在表的.frm文件中保存,”数字-字符串”映射关系的“查找表“。
例:

mysql> CREATE TABLE enum_test(

e ENUM('fish', 'apple', 'dog') NOT NULL

);

mysql>INSERT INTO enum_test(e) VALUES('fish'), ('dog'), ('apple');

MariaDB [foo]> SELECT e + 0 FROM enum_test;

+-------+

| e + 0 |

+-------+

|     1  |

|     3  |

|     2  |

MariaDB [foo]> SELECT e FROM enum_test;

+-------+

|  e     |

+-------+

| fish |

| apple |

|  dog   |

+-------+

枚举字段是根据内部存储的整数而不是定义的字符串进行排序的

可以使用 FIELD() 函数显式指定排序顺序,但会导致 MySQL 无法利用索引消除排序

枚举的缺点,字符串列标固定,添加或删除字符串必须使用ALTER TABLE,因此,对于一系列未来可能会改变的字符串。

日期和时间类型

DATETIME:时间范围 1001 - 9999 年,精度范围 1 秒。内部把日期和时间封装到格式为 YYYYMMDDHHMMSS 的整数中,与时区无关,使用 8 个字节的存储空间。MySQL 默认以可排序、无歧义的格式显示 DATETIME 的值,例如 “2018-04-26 16:51:05”。

TIMESTAMP:TIMESTAMP 显示的值依赖于时区。时间范围 1970 - 2038 年,保存从 1970 年 1 月 1 日凌时开始的秒数,跟 UNIX 的时间戳一样。只使用 4 个字节的存储空间。

如果跨时区访问或存储数据,TIMESTAMP 和 DATETIME 的行为完全不一样。

常见的特殊属性有:

  1. 创建表时,所有的 TIMESTAMP 字段默认为 NOT NULL,且第一个 TIMESTAMP 字段有默认值 CURRENT_TIMESTAMP。
  2. INSERT 插入数据时,如果没有指定第一个 TIMESTAMP 列的值,MySQL 会设置这个列的值为当前时间。
  3. UPDATE 更新数据时,MySQL 会默认更新第一个 TIMESTAMP 列的值为当前时间(除非明确指定值)。

MySQL 内置函数可以实现时间戳和日期的互相转换:

FROM_UNIXTIME():将UNIX 时间戳转为日期。

UNIX_TIMESTAMP():将日期转为 UNIX 时间戳。

位置据类型

BIT(不建议用)

BIT 列中可以存储一个或多个 true/false 值。BIT(n) 定义了存储 n 个位的字段,BIT 列最大支持 64 个位。

BIT 的行为因存储引擎的不同而不同。MyISAM 会打包存储所有的 BIT 列,17 个单独的 BIT 列只需要 17 个位存储(假设没有可为 NULL 的列),只需要 3 个字节。假设存储引擎是 Memory 或 InnoDB,每个 BIT 列使用一个足够存储的最小整数来存放,无法节省存储空间。

MySQL 把 BIT 当做字符串类型,而不是数字类型。当检索 BIT(1) 的值时,结果是一个包含二进制 0 或 1 的字符串,而不是 ASCII 码的 0 或 1。但是在数字上下文的场景中,会自动将位字符转为对应的 ASCII 码。例如,对于存储了 b'00111001' 的 BIT(8) 列,正常检索时得到字符码为 57 的字符‘9’,但是在数字上下文场景中,得到数字 57。

SET

如果需要保存很多 true/false 值,可以合并这些列到一个 SET 数据类型,在 MySQL 内部以一系列打包的位的集合来表示。存储空间利用率高,使用方便(可以在查询中使用 FIELD() 和 FIELD() 函数)。缺点是改变列的定义时,代价较高(需要使用 ALTER TABLE),对于大表很麻烦。

选择标识符

标识列(identifier column)选择合适的数据类型很重要。标识列可以与其他值进行比较,或通过标识列寻找其他列。标识列也可以作为其他表中的外键。

选择标识列的类型时,既要考虑存储类型,也要考虑 MySQL 对这种类型怎么执行计算和比较。例如 MySQL 内部用整数存储 ENUM 和 SET 类型,在比较操作时转为字符串。

整数类型

整数是标识列最佳选择,快,且可以使用 AUTO_INCREMENT

ENUM 和 SET 类型

标识列的糟糕选择。ENUM 和 SET 列适合存储固定信息,例如性别、产品类型。

字符串类型

尽量避免,慢,存储空间大。尤其是 MyISAM,会对字符串压缩索引。

特殊类型数据

例如IPv4,人们经常用VARCHAR(15)列来存储IP地址,然而,它们实际上是32位无符号整数,不是字符串,用小数点将地址分成四段的表示方法只是为了让人阅读容易,所以应该用无符号整数存储IP地址。MySQL 提供了 INET_ATON() 和 INET_NTOA() 函数进行转换。

MySQL schema 设计中的陷阱

太多的列

MySQL的存储引擎API工作时需要在服务器层和存储引擎层之间通过行缓冲格式拷贝数据,然后在服务器层将缓冲内容解码成各个列。从行缓冲中将编码过的列转换成行数据结构的操作代价是非常高的。

太多的关联

如果希望查询执行得快速且并发性好,单个查询最好在12个表以内做关联

全能得枚举

当需要在枚举列表中增加一个新的值时,就要做一次ALTER TABLE操作,在MySQL5.0以及更早的版本中ALTER TABLE是一种阻塞操作,在后续版本中,如果不是在列表的末尾增加值也会一样需要ALTER TABLE。

变相的枚举

枚举(ENUM)列允许在列中存储一组定义值中的单个值,集合(SET)列则允许在列中存储一组定义值中的一个或多个值,因此使用时不要混乱。

范式和反范式

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

范式化的优点

更新操作快

较好的范式化可以减少数据冗余,修改简单

范式化好的表更新

冗余少的数据可以更少的使用 DISTINCT 或 GROUP BY 语句

范式化设计的 schema 的缺点:

是通常需要关联查询。

反范式化的优点

所有数据都在一张表中,避免了关联。

最常见的混用范式化和反范式化的例子是复制或缓存,在不同的表中存储相同的特定列。可以通过触发器更新冗余列。

缓存表和汇总表

缓存表,表示存储那些可以比较简单从schema其他表获取数据的表

汇总表,保存的是使用GROUP BY语句聚合数据的表

完全独立的缓存表和汇总表,可以存储少量冗余数据。

缓存表是实时维护的。

汇总表是定期重建的。

可以使用物化视图(MySQL 需要借助工具 Flexviews)和计数器表。

加快 ALTER TABLE 操作的速度

MySQL 执行 ALTER TABLE 时,通常是用新的结构创建一个空表,从旧表中查出所有数据插入新表,再删除旧表。

大部分 ALTER TABLE 操作会中断 MySQL 服务。有几种方式可以避免停机:

  1. 主备结构时,可以在不提供服务的备用库执行操作,完成后再主备切换。
  2. 影子拷贝:用新的表结构创建新表,然后通过重命名和删表操作交换两张表。可以使用 Facebook 的“online schema change”工具。

改变或删除列的默认值时,可以使用 ALTER COLUMN(不一定重建表)或 MODIFY COLUMN(需要重建表)。列的默认值存储在表的 .frm 文件中。

只修改.frm文件

下面的操作是有可能不需要重建表的:

移除(不是增加)一个列的AUTO_INCREMENT属性

增加、移除或更改ENUM和SET常量。如果移除的是已经有行数据用到其值的常量,查询将会返回一个空字串值

基本技术是为想要的表创建一个新的.frm文件,然后用它替换掉已经存在的那张表的.frm文件

  1. 创建一张有相同结构的空表,并进行所需要的修改(例如增加ENUM常量)
  2. 执行FLUSH TABLES WITH READ LOCK。这将会关闭所有正在使用的表,并且禁止任何表被打开。
  3. 交换.frm文件
  4. 执行UNLOCK TABLES来释放第2步的读锁

快速创建 MyISAM 索引

ALTER TABLE 时,先禁用索引,载入数据后再启用索引,可以高效载入数据。

这个方法对唯一索引无效,因为DISABLE KEYS只对非唯一索引有效

操作步骤

  1. 用需要的表结构创建一张表,但不包括索引
  2. 载入数据到表中以创建.MYD文件
  3. 按照需要的结构创建另外一张空表,这次要包含索引。这会创建需要的.frm和.MYI文件。
  4. 获取读锁并刷新表。
  5. 重命名第二张表的.frm和.MYI文件,让MySQL认为是第一张表的文件。
  6. 释放读锁
  7. 使用REPAIR TABLE来重建表的索引。该操作会通过排序来构建所有索引,包括唯一索引。

【MySQL】Schema与数据类型优化相关推荐

  1. MySQL Schema与数据类型的优化

    选择优化的数据类型: 1. 更小的通常更好: 一般情况下,应该尽量使用可以正确存储数据的最小数据类型.更小的数据类型通常更快,因为他们占用更少的磁盘,内存和cpu缓存,并且处理时需要的cpu周期也更少 ...

  2. mysql schema数据混乱_MySQL之Schema与数据类型优化

    选择优化的数据类型 MySQL支持的数据类型非常多,选择正确的数据类型对于获得高性能至关重要.不管存储哪种类型的数据,下面几个简单的原则都有助于做出更好的选择: 更小的通常更好 一般情况下,应该尽量使 ...

  3. mysql eva模型_第四章 Schema 与数据类型优化

    1.选择优化的数据类型 更小的通常更好 一般情况下选择可以正确存储数据的最小数据类型.更小的类型通常更快,占用更少的硬盘.内存.CPU等.但要确保没有递归需要存储的值的范围. 简单就好 简单数据类型的 ...

  4. Mysql高性能笔记(一):Schema与数据类型优化

    1.数据类型 1.1.几个参考优化原则 a.  更小的通常更好 i.更小的数据类型,占用更少磁盘.内存和CPU缓存,需要的CPU周期更少 ii.如果无法确定哪个数据类型是最好的,就选择不会超过范围的最 ...

  5. 高性能MySQL(2)——Schema与数据类型的优化

    良好的逻辑设计和物理设计是高性能的基石,应该根据系统将要执行的查询语句来设计 schema,这往往需要权衡各种因素. 一.选择优化的数据类型 MySQL支持的数据类型非常多,选择正确的数据类型对于获得 ...

  6. MySQL高性能及性能优化技巧---更适合开发人员

    更新次数 更新时间 首发 2021.10.25 第一次更新 2021.10.26 1.删除了书中大量不必要的存储引擎类型 2.摘要完毕Mysql架构与历史部分 第二次更新 2021.10.29 1.摘 ...

  7. MySQL查询过程及Scheme设计与数据类型优化

    MySQL查询过程 我们总是希望MySQL能够获得更高的查询性能,最好的办法是弄清楚MySQL是如何优化和执行查询的.一旦理解了这一点,就会发现:很多的查询优化工作实际上就是遵循一些原则让MySQL的 ...

  8. mysql 数值 字符 优化,教你如何进行Mysql数据类型优化

    1. 版本 1)操作系统版本 cat /proc/version Linux version 3.10.0-957.5.1.el7.x86_64 (mockbuild@kbuilder.bsys.ce ...

  9. mysql表设计很多非常大的varchar_聊一聊数据库(MySQL)设计中的数据类型优化

    良好的逻辑设计和物理设计事高性能的基石,在进行数据库设计时,我们应该要考虑到未来将会执行的查询语句,这就需要对各种因素进行权衡.本文将会聊一聊数据库(MySQL)设计中有关数据类型优化的一些内容.以下 ...

最新文章

  1. Linux的10个游戏
  2. 最新!压缩为rar格式方法,目前只能用:WinRAR压缩工具-rar压缩格式的版权所有者。
  3. ServerBootstrap的启动流程
  4. boost::hana::second用法的测试程序
  5. LeetCode 424. Longest Repeating Character Replacement
  6. Redis PK Memcached,哪个更牛叉
  7. Java BigDecimal stripTrailingZeros()方法与示例
  8. 北大保安又双叒…出“传奇”!这次是挑战“天下第一考”
  9. 不用数学讲清马尔可夫链蒙特卡洛方法?
  10. 容器编排技术 -- Kubernetes kubectl edit 命令详解
  11. java开发者工具开源版_6种开源工具可帮助教育工作者保持井井有条
  12. 怎样进行大数据的入门级学习
  13. c# mysql 汉字乱码_在C#和MySQL中存取中文字符时避免乱码的方法
  14. 重学JavaScript系列之一_引用类型
  15. 【论文解读】“推荐系统”加上“图神经网络”
  16. JFinal开发8个常见问题
  17. ulipad.4.1.zip linux,在ubuntu中安装ulipad
  18. 使用面包板的一点小注意
  19. 解决vue项目背景图片在IE和火狐上不显示的问题
  20. HCIP-Routing Switching V2.5考试大纲

热门文章

  1. F2FS nat entry涉及的数据结构(linux 5.18.11)
  2. spark 不在 sudoers 文件中。此事将被报告。
  3. 喂!喂!喂!一起来做Python日常练习题啊!(>^ω^<)
  4. 多任务环境中如何喂看门狗?
  5. 升学教育过程中:关于收费、退费的规定
  6. 【万字干获】阿里妈妈搜索推荐广告预估模型2021思考与实践
  7. 聊聊从脑神经到神经网络
  8. 海阳顶端网php,海阳顶端网的ASP木马的一个漏洞和利用
  9. 在线运行 Linux,真滴牛逼。
  10. 获取屏幕浏览器的宽高