选择合适的数据类型

在使用MySQL创建数据表的时候会遇到一个问题,如何为字段选择合适的数据类型.比如创建一个员工信息表,每个字段都可以用很多种类型来定义,

int,char,float等等.

char和varchar

char和varchar都是用来存储字符串类型的数据,但是他们保存和检索的方式不一样.char属于固定长度的字符类型,二varchar属于可变成的字符类型

值  char(4) 存储需求 varchar(4) 存储需求
'' '   ' 4个字节 ''  1个字节
'ab' 'ab ' 4个字节 'ab' 3个字节
'abcd' 'abcd' 4个字节 'abcd' 5个字节
'abcdefg' 'abcd' 4个字节 'abcd' 5个字节

由于char是固定长度的,所以它的处理速度比varchar快得多,但是其缺点是浪费存储空间,程序需要对尾行空格进行处理,所以对那些变化不打并且查询速度有较高的要求的数据可以考虑使用char类型来存储

  在mysql中,不同的存储引擎对char和varchar的使用原则有所不同

  • MyISAM存储引擎

    • 建议使用固定长度的数列代替可变长度的数据列
  • InnoDB存储引擎
    • 建议使用varchar类型,对于InnnoDB数据表,内部的行存储格式没有区分固定长度和可变长度,因此使用char列不一定比可变长度的varchar性能好
    • 由于char平均占用空间多余varchar,因此varchar来UI消化需要处理的数据航的存储总量和磁盘I/O是比较好的.

TEXT和BLOB

介绍

在选择大文本的时候我们会优先选择text类型或者blob比如文章.

那么TEXT和BLOB最主要的区别是 BLOB能用来保存二进制数据比如照片.而text智能保存字符串数据,比如文章和日记.

根据存储的文本长度不同和存储的字节不同我们可以使用

MEDIUMTEXT,LONGTEXT和MUDIUMBLOB,LONGBLOB

常见问题

空洞问题

BLOB和text在执行了大量的删除操作时,会留下很大的'空洞',以后填入这些'空洞'的记录在插入的性能上回有影响.为了提高性能,建议使用OPTIMIZE TABLE功能对类表进行碎片整理,

避免空洞带来的性能问题

空洞例子:

CREATE TABLE t (
id VARCHAR(100),
context TEXT
);
INSERT INTO t VALUES(1,repeat('haha',100));
INSERT INTO t VALUES(2,repeat('haha',100));
INSERT INTO t VALUES(3,repeat('haha',100));
insert into t select * from t;
insert into t select * from t;
.....
insert into t select * from t;

这时候文件的大小为:

删除id=1的数据,那么就是删除了1/3的数据:

mysql> delete from t where id=1;
Query OK, 32768 rows affected (0.63 sec)

再看文件大小,我们可以看到文件大小还是96MB,这就形成了空洞.

我们用OPTIMIZE进行优化:

mysql> optimize table t;

此时我们再看文件,已经变成了60MB,文件大大的缩小了,说明'空洞被收回了'

文件索引

使用合成索引来提高大文本字段的查询性能:

合成索引就是根据大文本的字段的内容建立一个散列值,并且把这个值存储在单独的数据列中,接下来可以通过检索散列值来找到数据.

但是,要注意这种技术只能用于精确匹配(对于< >=等范围搜索是没有用的)

可以使用MD5()函数来生成散列值.

下面介绍一下合成索引的方法:

CREATE TABLE t (
id VARCHAR(100),
context BLOB,
hash_value char(32)
);
INSERT INTO t VALUES(1,repeat('beijing',2),MD5(context)); INSERT INTO t VALUES(1,repeat('beijing2008',2),MD5(context)); mysql> select * from t where hash_value=md5(repeat('beijing2008',2));
+------+------------------------+----------------------------------+
| id | context | hash_value |
+------+------------------------+----------------------------------+
| 1 | beijing2008beijing2008 | 0fe88accc8741a9d1bc323bd286866bb |
+------+------------------------+----------------------------------+

由于这种技术只能用于精确匹配,从一定程度上减少了I/O,提高了查询效率.如果需要对BLOB字段进行模糊查询,MYsql提供了前缀索引,也就是只为字段的前n列创建索引

create index idx_blob on t(context(100));
mysql> desc select * from t where context like "beijing%" \G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t
type: range
possible_keys: idx_blob
key: idx_blob
key_len: 103
ref: NULL
rows: 2
Extra: Using where
1 row in set (0.04 sec)

对context的前100个字符进行模糊查询,就可以用前缀索引.

注意这里的%不能放在前面,否则不能命中索引

避免使用select *

不要用select * 检索大型的BLOB或者TEXT值

除非能够确定约束条件where只会找到需要的数据,否则很可能毫无目的在网络上传输大量的值.

用户可以用搜索索引列,决定需要的那些数据行,然后从符合条件的数据中检索BLOB或者TEXT

分表

水平分表,在某些环境中,如果把这些大型的列数据移动到第二章表数据中,那么把原数据表中的数据列转换成固定长度的数据行格式,

那么它就是有意义的.这会减少表中的碎片,可以得到固定长度的性能优势.

浮点数和定点数

在MYSQL中用float,double来标识浮点数.当一个字段被定义浮点类型后,如果插入的数据精度超过该列定义的实际精度,那么会采取四舍五入的办法来得到实际的值.

定点数不同于浮点数,他是用字符串的形式存存放的,所以插入的实际值精度大于实际定义的精度,如果在传统模式下,会直接报错,不能插入数据.

CREATE TABLE test(c1 float(10,2),c2 decimal(10,2));

INSERT INTO text VALUES(131072.32,131072.32);

mysql> select * from test;
+-----------+-----------+
| c1 | c2 |
+-----------+-----------+
| 131072.31 | 131072.32 |
+-----------+-----------+

可以看到c1列的值从131072.32 变成了131072.31,这是上面的数值在使用单精度浮点数表示时,产生了误差.

注意:

  • 浮点数存在误差问题
  • 对货币等对精度要求比较高的数据,应该用定点数表示或存储
  • 在变成中,如果用到浮点数,要特别注意误差问题,尽量避免做浮点数比较

日期类型的选择

  • 根据实际需要选择能够满足的最小存储的日期类型,如果只需要记录年,那么用一个字节来存储的YEAR类型就而已满足.而不需要用4个字节的date,不仅节省空间,还提高查询效率
  • 如果要记录年月日时分秒,并记录比较久远,那么最好使用datetime,不要使用timestamp
  • 如果记录的日期需要不同的时区的用户使用,那么最好使用timestamp,因为日期类型中,只有他能够和实际时区相对应

mysql设计表结构数据类型的选择的更多相关文章

  1. navicat如何导出mysql数据表结构

    我们在创建数据库时会对字段进行设置,比如类型.长度等,如果字段多的话一个个设置非常麻烦,可以从其他地方已有的表导入数据表结构,怎么操作呢?我们拿navicat导出mysql数据表结构为例: 1.点击“ ...

  2. 用户中心mysql数据库表结构的脚本

    /* Navicat MySQL Data Transfer Source Server : rm-m5e3xn7k26i026e75o.mysql.rds.aliyuncs.com Source S ...

  3. mysql数据库表结构导出

    mysql数据库表结构导出 命令行下具体用法如下: mysqldump -u用戶名 -p密码 -d 数据库名 表名 > 脚本名; 导出整个数据库结构和数据 mysqldump -h localh ...

  4. mysql对比表结构对比同步,sqlyog架构同步工具

    mysql对比表结构对比同步,sqlyog架构同步工具 对比后的结果示例: 执行后的结果示例: 点击:"另存为(S)" 按钮可以把更新sql导出来.

  5. MySQL复制表结构表数据

    MySQL复制表结构 表数据 1.复制表结构及数据到新表CREATE TABLE 新表 SELECT * FROM 旧表这种方法会将oldtable中所有的内容都拷贝过来,当然我们可以用delete ...

  6. MySQL 查看表结构

    mysql查看表结构命令,如下: desc 表名; show columns from 表名; describe 表名; show create table 表名; use information_s ...

  7. mysql查看表结构命令

    mysql查看表结构命令 mysql查看表结构命令,如下: desc 表名;show columns from 表名;describe 表名;show create table 表名; use inf ...

  8. Mysql 复制表结构 及其表的内容

    顺便转一下Mysql复制表结构.表数据的方法: 1.复制表结构及数据到新表CREATE TABLE 新表 SELECT * FROM 旧表 这种方法会将oldtable中所有的内容都拷贝过来,当然我们 ...

  9. mysql查看表结构,字段等命令

    mysql查看表结构命令,如下: desc 表名; show columns from 表名; describe 表名; show create table 表名;

随机推荐

  1. linux socket读数据错误解释

    EINTR 表示某种阻塞的操作,被接收到的信号中断,造成的一种错误返回值. EAGAIN   从字面上来看,是提示再试一次.这个错误经常出现在当应用程序进行一些非阻塞(non-blocking)操作( ...

  2. Atitit.编程语言原理---方法重载的实现与设计 调用方法的原理

    Atitit.编程语言原理---方法重载的实现与设计 调用方法的原理 1. 重载包括:普通方法的重载和构造方法的重载 1 1.1. 横向重载”和“纵向重载”1 1.2. 方法签名通过  方法名称,参数 ...

  3. 92. Reverse Linked List II【Medium】

    92. Reverse Linked List II[Medium] Reverse a linked list from position m to n. Do it in-place and in ...

  4. sigpending

    信号的阻塞:通过sigprocmask()将信号集sigset_t中的信号设置为阻塞.SIG_BLOCK是指对相应信号的“递送阻塞”,内核在递送一个原来被阻塞的信号给进程时(而不是在产生该信号时),才 ...

  5. 深度解析丨秒懂nova3手机上超酷炫的AR应用及开发

    此前在HUAWEI nova3发布会中,相信大家都已经感受到了AR能力带来的惊喜: 现实场景召唤圣斗士,随时随地交流合影: 点击观看视频:https://v.qq.com/x/page/m1344f6 ...

  6. UVA 1640 The Counting Problem UVA1640 求[a,b]或者[b,a]区间内0~9在里面各个数的数位上出现的总次数。

    /** 题目:UVA 1640 The Counting Problem UVA1640 链接:https://vjudge.net/problem/UVA-1640 题意:求[a,b]或者[b,a] ...

  7. 第一百九十节,jQuery,编辑器插件

    jQuery,编辑器插件 学习要点: 1.编辑器简介 2.引入 uEditor 编辑器(Editor),一般用于类似于 word 一样的文本编辑器,只不过是编辑为 HTML 格式的.分类纯 JS 类型 ...

  8. 用关键字interface定义接口,通过关键字implements来实现接口

    [定义]Java中,能够完成特定功能的,由若干属性和方法组织成的,相对独立的属性和方法的集合. [用途]实现类的多继承,以解决Java只能单继承,不支持多继承的问题. [特点] 用关键字interfa ...

  9. GetWindowText 卡死的一种可能的原因

    最近一个项目中碰到GetWindowText经常卡死的问题,这个项目有多个线程,检查代码发现发生死锁的是一个数据线程和一个UI线程. 示意图大致如下(data thread和UI thread在同一个 ...

  10. Laravel5.1 路由 -基础

    什么是路由? 大K简单的说下,路由是用户访问我们程序的一个入口,比方说 你在浏览器输入:www.myblogs.com/create 就会打开一个页面,我们接收到这一个请求后后台需要做一些事儿来反馈给 ...