MySQL 请选择合适的列

思维导图
点击图片,可查看大图。

介绍

情况:如果你的表结构设计不良或你的索引设计不佳,那么请你优化你的表结构设计和给予合适的索引,这样你的查询性能就能提高几个数量级。——数据越大,索引的价值越能体现出来。

我们要提高性能,需要考虑的因素:

1、设计架构

2、设计索引

3、评估查询性能

今天要讲的是表列的设计,暂不谈索引设计。我会在下一章讲索引设计。

选择数据类型

选择正确的数据类型,对于提高性能至关重要。

下面给出几种原则,有利于帮助你选择何种类型。

1、更小通常更好。

  使用最小的数据类型。——更少的磁盘空间,内存和CPU缓存。而且需要的CPU的周期也更少。

2、简单就好。

  整数代价小于字符。——因为字符集和排序规则使字符比较更复杂。

  1>mysql内建类型(如timestamp,date)优于使用字符串保存。

  2>使用整数保存ip地址。

3、尽量避免NULL——如果计划对列进行索引,尽量避免把列设置为NULL

  尽可能把字段定义为NOT NULL。——可以放置一个默认值,如‘',0,特殊字符串。

  原因:

    (1)MYSQL难以优化NULL列。NULL列会使索引,索引统计和值更加复杂。

    (2)NULL列需要更多的存储空间,还需要在MYSQL内部进行特殊处理。

    (3)NULL列加索引,每条记录都需要一个额外的字节,还导致MyISAM中固定大小的索引变成可变大小的索引。

决定列的数据类型,我们应该遵循下面两步。

第一步、大致决定数据类型。——判断是数字,字符串还是时间等。这通常很直观。

第二步、确定特定的类型。

  很多数据类型能够保存同类型的数据,但是我们要发现,他们在存储的范围,精度和物理空间之间的差别(磁盘或内存空间)。如:datetime和timestamp能保存同样类型的数据:日期和时间。——timestamp使用datetime一半的空间;能保存时区;拥有特殊的自动更新能力。

品味数据类型

整数

1、存储类型——数据范围为-2^(n-1)到2^(n-1)-1,这里的n是所需存储空间的位数。

     类型名称    占用位数      数据范围    TINYINT     8   -2^7 ~ 2^7-1   SMALLINT     16     -2^15~2^15-1     MEDIUMINT       24     -2^23~2^23-1   INT     32   -2^31~2^23-1   BIGINT     64    -2^63~2^63-1

2、unsigned属性表示不允许负数,并大致把正上限提高了一倍。如TINYINT UNSIGNED保存的范围为0到255而不是-127到128

3、MYSQL对整数类型定义宽度,比如int(1)和int(22)对于存储和计算是一样的。只规定了MYSQL的交互工具(如命令行客户端)用来显示字符的个数。

实数

实数有分数部分(小数部分)。

存储类型:FLOAT和DOUBLE,DECIMAL。

占用大小:FLOAT 4个字节,DOUBLE 8个字节。DECIMAL受到MYSQL版本影响,早期版本254个数字,5.0以上65个数字。

区别:1、FLOAT和DOUBLE支持标准浮点运算进行近似计算。

   2、DECIMAL进行DECIMAL运算,CPU并不支持对它进行直接计算。浮点运算会快一点,因为计算直接在CPU上进行。

     3、DECIMAL只是一个存储格式,在计算时会被转换为DOUBLE类型。

   4、DECIMAL(18,9)使用9个字节,小数点前4个字节,小数点1个字节,小数点后4个字节。

   5、DECIMAL只有对小数进行精确计算的时候才使用它,如保存金融数据。

字符串类型

1、varchar

  (1)保存可变长字符串。

    理解:比固定长度占用更少的存储空间,因为它只占用自己需要的空间。例外情况:使用ROW_FORMAT=FIXED创建的MyISAM表,它为每行使用固定长度的空间,可能会造成浪费。

  (2)存储长度信息。如果定义的列小于或等于255,则使用1个字节存储长度值,假设使用latin1字符集,如varchar(10)将占用11个字节的存储空间。反过来,varchar(1000),则占用1002个字节的存储空间。

  (3)节约空间,对性能有帮助。

  (4)5.0版本以上,无论是取值还是保存,MySQL都会保留字符串末尾的空格。

只分配真正需要的空间
使用varchar(5)和varchar(200)保存'hello'占用空间是一样的。——这里应该指的是磁盘上的空间。
那么使用较短列有何优势?——巨大的优势
  较大的列会使用更多的内存,因为MySQL通常会分配固定大小的内存块(如varchar(200)会用200个字符大小的内存空间)来保存值(然后对值进行trim操作,最后放入磁盘)或取值。——这对排序或使用基于内存的临时表尤其不好。

2、char

  (1)固定长度。

  (2)保存值时,去掉末尾的空格。

  咱们再看看varchar

  (3)char常用于很短字符串或长度近似相同的字符串的时候很有用。如存储用户密码的MD5哈希值,它的长度总是一样的。

  char优于varchar的地方?

  1>> 对于经常改变的值,char优于varchar,因为固定长度行不容易产生碎片。——当最长长度远大于平均长度,并且很少发生更新的时候,通常适合使用varchar。

  2>>对于很短的列,char的效率也是高于varchar的。如对于单字节字符集(如latin1),char(1)只会占用1个字节,而varchar(2)会占用2个字节(有一个字节用来存储长度的信息)。

3、text

用于保存大量数据。

  (1)InnoDB在它们较大的时候会使用“外部”存储区域来进行保存。——所以需要足够的外部存储空间来保存实际的值。

  (2)排序方式不同于其他字符类型,不会按照完整长度进行排序,而只是按照max_sort_length规定的前若干个字节进行排序。

 

4、使用ENUM代替字符串类型

  (1)ENUM列可以存储65 535个不同的字符串。

  (2)以紧凑方式保存。根据列表中值的数量,把它们压缩到1到2个字节中。

  (3)MySQL在内部把每个值都保存为整数,以表示值在列表中的位置。

  (4)保留了一份“查找表”,来表示整数和字符串在表的.frm文件中的映射关系。

  (5)ENUM字符列是固定的,添加、删除字符串须使用ALTER TABLE。

  (6)使用案例:权限表中使用ENUM来保存Y值和N值。

使用方法:

在对enum列使用order by的时候,是按数字排序的,而不是字符串排序。

日期和时间类型

DATETIME:保存大范围的值。封装格式:YYYYMMDDHHMMSS。——与时区无关,使用8字节存储空间。

TIMESTAMP:保存自1970年1月1日午夜(格林尼治标准时间)以来的秒数。——使用4字节存储空间。

通常使用TIMESTAMP,它比DATETIME更节约空间。有时人们把Unix的时间戳保存为整数值,但是这通常没有任何好处。——这种格式处理起来不太方便,我们并不推荐它。

经验交谈

  1、我们在为列选择数据类型的时候,不仅要考虑存储类型大小,还要考虑MySQL如何对它们进行计算和比较。例如:MySQL在内部把ENUM和SET类型保存为整数,但是在比较的时候把它们转换为字符串。

  2、我们要在相关表中使用同样的类型,类型之间要精确匹配,包括诸如UNSIGNED这样的属性。

  3、混合不同的数据类型会导致性能问题,即使没有性能问题,隐式的类型转换也能导致难以察觉的错误。

  4、选择最小的数据类型要考虑将来留出的增长空间。如,中国的省份,我们知道不会有成千上万个,因此不必用INT。TINYINT就足够了,它比INT小3字节。

  5、整数通常是最佳的数据类型,因为它速度快,并且能使用AUTO_INCREMENT。

  6、要尽可能避免字符串做为列的数据类型,因为它们占用了很多空间并且通常必整数类型要慢。MyISAM默认情况下为字符串使用了压缩索引,这使查找更为缓慢。

  

总结

若有错误,望请大侠指教一、二,不胜感激!

参考文献:《高性能MYSQL》

(0)

相关推荐

  • MySql数据引擎简介与选择方法

    一.数据引擎简介 在MySQL 5.1中,MySQL AB引入了新的插件式存储引擎体系结构,允许将存储引擎加载到正在运新的MySQL服务器中. 使用MySQL插件式存储引擎体系结构,允许数据库专 业人员为特定的应用需求选择专门的存储引擎,完全不需要管理任何特殊的应用编码要求.采用MySQL服务器体系结构,由于在存储级别上提供了一致和简单的 应用模型和API,应用程序编程人员和DBA可不再考虑所有的底层实施细节.因此,尽管不同的存储引擎具有不同的能力,应用程序是与之分离的. MySQL支持数个存储

  • 浅谈MySQL存储引擎选择 InnoDB与MyISAM的优缺点分析

    下面先让我们回答一些问题: ◆你的数据库有外键吗? ◆你需要事务支持吗? ◆你需要全文索引吗? ◆你经常使用什么样的查询模式? ◆你的数据有多大? 思考上面这些问题可以让你找到合适的方向,但那并不是绝对的.如果你需要事务处理或是外键,那么InnoDB 可能是比较好的方式.如果你需要全文索引,那么通常来说 MyISAM是好的选择,因为这是系统内建的,然而,我们其实并不会经常地去测试两百万行记录.所以,就算是慢一点,我们可以通过使用Sphinx从InnoDB中获得全文索引. 数据的大小,是一个影响你

  • 选择MySQL数据库进行连接的简单示例

    一旦获得MySQL服务器的连接,需要选择一个特定的数据库工作.这是因为MySQL服务器可能有一个以上的数据库. 从命令提示符,选择MySQL数据库: 这是很简单的选择一个特定的数据库mysql>提示符.选择一个特定的数据库,可以使用SQL命令. 例子: 下面是一个例子,选择数据库称为 TUTORIALS: [root@host]# mysql -u root -p Enter password:****** mysql> use TUTORIALS; Database changed mysq

  • MySQL 请选择合适的列

    思维导图 点击图片,可查看大图. 介绍 情况:如果你的表结构设计不良或你的索引设计不佳,那么请你优化你的表结构设计和给予合适的索引,这样你的查询性能就能提高几个数量级.--数据越大,索引的价值越能体现出来. 我们要提高性能,需要考虑的因素: 1.设计架构 2.设计索引 3.评估查询性能 今天要讲的是表列的设计,暂不谈索引设计.我会在下一章讲索引设计. 选择数据类型 选择正确的数据类型,对于提高性能至关重要. 下面给出几种原则,有利于帮助你选择何种类型. 1.更小通常更好. 使用最小的数据类型.-

  • MySQL如何选择合适的索引

    先来看一个栗子 EXPLAIN select * from employees where name > 'a'; 如果用name索引查找数据需要遍历name字段联合索引树,然后根据遍历出来的主键值去主键索引树里再去查出最终数据,成本比全表扫描还高. 可以用覆盖索引优化,这样只需要遍历name字段的联合索引树就可以拿到所有的结果. EXPLAIN select name,age,position from employees where name > 'a'; 可以看到通过select出的字段

  • MySQL为id选择合适的数据类型

    选择 id 的数据类型,不仅仅需要考虑数据存储类型,还需要了解 MySQL 对该种类型如何计算和比较.例如,MySQL 将 ENUM 和 SET 类型在内部使用整型存储,但是在字符串场景下会当做字符串进行比较.一旦选择了 id 的数据类型后,需要保证引用 id 的相关数据表的数据类型一致,而且是完全一致,这包括属性,例如长度.是否有符号!如果混用不同的数据类型可能导致性能问题,即便是没有性能问题,在进行比较时的隐式数据转换可能导致难以捉摸的错误.而如果在实际开发过程中忘记了数据类型不同这个问题,

  • 如何选择合适的MySQL日期时间类型来存储你的时间

    构建数据库写程序避免不了使用日期和时间,对于数据库来说,有多种日期时间字段可供选择,如 timestamp 和 datetime 以及使用 int 来存储 unix timestamp. 不仅新手,包括一些有经验的程序员还是比较迷茫,究竟我该用哪种类型来存储日期时间呢? 那我们就一步一步来分析他们的特点,这样我们根据自己的需求选择合适的字段类型来存储 (优点和缺点是比较出来的  , 跟父母从小喜欢拿邻居小孩子跟自己比一样的) datetime 和 timestamp datetime 更像日历上

  • MySQL选择合适的备份策略和备份工具

    目录 一.多地部署 二.备份的常见分类 1.物理备份 VS 逻辑备份 1)物理备份 2)逻辑备份 2.离线备份 VS 在线备份 3.全量备份 VS 增量备份 三.MySQL中的备份工具 1.物理备份 2.逻辑备份 四.mysqlbackup VS mysqldump 五.如何检测备份的有效性 六.RTO 和 RPO 1.RTO 2.RPO 七.总结 前言: 在确定备份策略和选择备份工具时,应从业务的RTO和RPO出发,结合存储成本综合考虑.数据库备份的重要性毋庸置疑,可以说,它是数据安全的最后一

  • Mysql索引选择以及优化详解

    索引模型 哈希表 适用于只有等值查询的场景,Memory引擎默认索引 InnoDB支持自适应哈希索引,不可干预,由引擎自行决定是否创建 有序数组:在等值查询和范围查询场景中的性能都非常优秀,但插入和删除数据需要进行数据移动,成本太高.因此,只适用于静态存储引擎 二叉平衡树:每个节点的左儿子小于父节点,父节点又小于右儿子,时间复杂度是 O(log(N)) 多叉平衡树:索引不止存在内存中,还要写到磁盘上.为了让一个查询尽量少地读磁盘,就必须让查询过程访问尽量少的数据块.因此,要使用"N 叉"

  • MySQL 大表添加一列的实现

    问题参考自: https://www.zhihu.com/question/440231149 ,mysql中,一张表里有3亿数据,未分表,要求是在这个大表里添加一列数据.数据库不能停,并且还有增删改操作.请问如何操作?答案为个人原创 以前老版本 MySQL 添加一列的方式: ALTER TABLE 你的表 ADD COLUMN 新列 char(128); 会造成锁表,简易过程如下: 新建一个和 Table1 完全同构的 Table2 对表 Table1 加写锁 在表 Table2 上执行 AL

  • MySQL 数据类型选择原则

    小而美 通常来说,尽可能使用占用存储空间小的数据类型来存储数据.这类数据类型通常也会更快,并且占用的磁盘空间.内存乃至缓存都更小,而且占用的 CPU 处理周期也少. 但是,务必准确估计要存储的数据值的范围.因为在数据表结构的多个地方扩充数据范围会是一个痛苦且耗时的过程.如果在犹豫哪种数据类型合适,那就选择你认为不会超出范围的最小空间的类型(在系统早期或者数据表 数据不多的情况下也可以进行调整). 简单至上 数据类型越简单意味着处理数据的 CPU 周期越少.例如,整型相比字符型而言,处理起来更容易

  • android通过蓝牙接收文件打开时无法自动选择合适的应用程序

    通过蓝牙接收文件,从历史传输记录打开,无法自动选择合适的应用程序 但是从file manager打开这个新接收的文件,是可以选择对应的应用程序(比如video player打开.3gp..mp4文件) 历史传输记录打开download的文件,是通过接收文件时对方传过来的mime type来选择适合的APP打开该文件 如果出现提示"未支持格式的文件",或者使用了错误的APP来打开该文件 原因在于发送方发送文件时填的mime type存在问题 如下的log是mtk接收方的log,请注意黄色

  • 详解MySQL 表中非主键列溢出情况监控

    今天,又掉坑了. 之前踩到过MySQL主键溢出的情况,通过prometheus监控起来了,具体见这篇MySQL主键溢出复盘 这次遇到的坑,更加的隐蔽. 是一个log表里面的一个int signed类型的列写满了.快速的解决方法当然还是只能切新表来救急了,然后搬迁老表的部分历史数据到热表. 亡羊补牢,处理完故障后,赶紧写脚本把生产的其他表都捋一遍. 下面是我暂时用的一个检测脚本,还不太完善,凑合用 分2个文件(1个sql文件,1个shell脚本) check.sql 内容如下: SELECT ca

随机推荐