MySQL 常见的数据表设计误区汇总

误区一:过多的数据列

MySQL 存储引擎的 API 是按照行缓冲区方式从服务端和存储引擎复制数据。服务端将缓冲区数据解码成数据列。然而,将行缓冲区的格式转换为数据行数据结构的列可能会代价很高。MyISAM 固定使用与服务端匹配的行格式,因此无需转换。然而,MyISAM 的可变行格式以及 InnoDB 的行格式总是需要进行转换。转换的代价依赖于列的数量。如果当数据表的列超过上百列的时候,会引起很高的 CPU 资源消耗——即便是使用到的列很少。曾经看过一篇文章,指的是一个多语言的解决方案,直接简单粗暴地将系统支持的语言用对应的列表示,例如:

CREATE TABLE t_multi_language_news (
  id INT PRIMARY KEY,
  title_cn VARCHAR(32),
  title_en VARCHAR(32),
  title_it VARCHAR(32),
  ...
  content_cn VARVHAR(256),
  content_en VARCHAR(256),
  conntent_it VARCHAR(256),
);

这种方式随着系统支持的语言越多,数据表的列越多,最终导致性能严重下降。如果你设计一个数据表的列数量超过100时,就需要考虑你的设计是否合理了。 **应对方式:**首先是考虑业务本身的设计是否合理,如果确实一个实体需要很多字段来描述,那么可以拆分数据表,通过扩展信息表来做。举个例子,对于资讯类的数据表,因为内容一般占据的空间会比较大,但是在列表不会直接查看,就可以拆成资讯主表和资讯详情表,主表存储标题、时间、摘要、缩略图附件 id 等列表要查看的信息即可。而资讯详情可以存储资讯的内容、来源、原文链接等信息。

误区二:过多的联合查询

MySQL 一次联合查询最多只能61张表。而有些设计主张不做冗余字段设计,这会导致复杂业务时需要连接多张表查询。即便是联合的表数量低于61个,也会引起性能的下降,而且整个 SQL 语句的维护将变得十分困难。作为一个设计的首要原则,就是如果想追求速度的话,一次查询不要跨太多的数据表做联合查询,尤其面临高并发场景的时候。 **应对方式:**首先,对于确定不会改变的字段,可以考虑冗余字段的方式减少联合查询。例如,一家企业的所属省份信息,就可以把省份代码、省份名称冗余了,而无需再通过省份代码去查询省份名称。其次,确实需要查其他表的情况下,可以考虑使用分步查询的方法,通过应用程序完成数据的组装,这种效率在数据表很多的时候会更高效,而且代码也更好维护。 误区三:万能的枚举 例如下面这种表设计:

CREATE TABLE t_countries (
  ...
  country ENUM('', '1', '2', ..., '45'),
  ...
);

这种方式本来可以通过一个以整数为 key的字典的查找表实现。如果是业务上增加了一个枚举,意味着整个表都需要使用 ALTER TABLE更新。而如果是使用应用代码的查找表,只需要增加新的键值对就好了。 **应对方式:**如果枚举确定不会变动(例如性别),那么没问题。如果枚举可能会增加,那么尽可能地通过应用程序来实现。

误区三:滥用 SET替代 ENUM

枚举ENUM 类型是数据表列的值只能是值集合中的一个,而 SET 类型是该列可以有一个或多个值。如果确定一个列只会有一个值,那么就应该优先使用枚举,而不是集合。例如下面的例子就是典型的滥用:

CREATE TABLE t_payment_way (
  ...
  is_default SET('Y', 'N') NOT NULL DEFAULT 'N',
  ...
);

很显然,is_default 要么是 Y,要么是 N,因此这里应该使用 ENUM。 **应对方式:**从业务层面考虑列的值是不是可能有多个,如果只有1个可选值那么就用 枚举ENUM。

误区四:生硬地避免NULL

很多文章都讨论过尽可能地避免使用 NULL,对于大部分场景这是一个好的设计,我们可以通过0,空字符串,约定的值等来表示空值。然而,不要因为这个而生硬套用,如果是这个值本身就是一个无意义的值的时候,那么使用 NULL 可能更合适。例如,如果要是有-1代表一个无意义的整数,可能会导致代码很复杂,甚至可能引起 bug。例如下面的例子:

CREATE TABLE t_person (
  birthday DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
  ...,
);

将一个 DATETIME 类型的默认值设置为全部是0会很奇怪,假设我们要统计人员的年龄平均值的时候,会引起莫名其妙的问题,而这种场景使用 NULL 就不会纳入到统计中来。可以通过设置 MySQL 的 SQL_MODE 参数禁止使用无意义的日期,避免出现这种情况。 **应对方式:**设计表的时候可以尽量使用 NOT NULL 避免空值,但是不要过于生硬,对于有些字段使用默认值无法表名意义或与实际不符时,也是可以选择使用 NULL 列的。只是,需要注意索引列不要使用NULL。而实际上,绝大部分索引列不太可能会是 NULL。

误区五:使用整数替换时间戳

之前有讲到过时间格式如何选择的问题,实际上有些开发者会使用整数来存储时间戳,他们的理由是这样效率更高。从某种意义上来说,可能会提高一点效率,但是帮助不大,因为在 MySQL 内部DATETIME 和 TIMESTAMP 本身就是用整数存储的。而如果使用整数存储时间的话,意味着应用程序中需要做时间转换,或者是 SQL 语句要对指定的字段进行时间转换,带来的收益可能得不偿失。 **应对方式:**尽可能地使用 DATETIME 存储时间,如果需要存储秒级精度一下的时间,那么可以考虑使用 BIGINT 来存储。

误区六:忘记字段的最大存储范围

在实际中设计表的时候会忘记数据类型的存储范围,比如使用 TINYINT(2)并不是只能存储两位整数,实际TINYINT(2) 可以存储的范围是-128-127。 存储超过255的整数。这种错误在使用整数类型的时候很容易出现问题,在插入整数的时候,MySQL 不会检查实际的整数位数,而是按对应存储字节数的范围存入,这种情况假设不注意会存入无意义的值。例如下面的 INSERT 操作会成功,而我们可能误以为 TINYINT(2)只能存储2位整数:

CREATE TABLE t_int_test (
    id INT PRIMARY KEY,
    number TINYINT(2)
);

INSERT INTO t_int_test (id, number) VALUES (3,123);

应对方式:在应用程序中做数据校验。

结语:

在实际设计数据表的过程中,除了需要考虑每个字段的数据类型之外,还需要考虑存储空间大小。对于常用的一些字段,如时间、标题、备注等,最好是内部形成一定的规范,大家遵照规范执行,并且增加校验能够避免很多问题。

以上就是MySQL 常见的数据表设计误区汇总的详细内容,更多关于MySQL 数据表设计误区的资料请关注我们其它相关文章!

(0)

相关推荐

  • Mysql 索引该如何设计与优化

    什么是索引? 数据库索引是一种数据结构,它以额外的写入和存储空间为代价来提高数据库表上数据检索操作的速度.通俗来说,索引类似于书的目录,根据其中记录的页码可以快速找到所需的内容.--维基百科 常见索引有哪些? 普通索引:最基本的索引,没有任何限制 唯一索引:与"普通索引"类似,不同的就是:索引列的值必须是唯一,但允许有空值 主键索引:它是一种特殊的索引,不允许有空值 全文索引:仅可用于 MyISAM 表,针对较大的数据,生成全文索引很耗时占空间 组合索引:为了提高多条件查询效率,可建立

  • MySQL分表实现上百万上千万记录分布存储的批量查询设计模式详解

    我们知道可以将一个海量记录的 MySQL 大表根据主键.时间字段,条件字段等分成若干个表甚至保存在若干服务器中. 唯一的问题就是跨服务器批量查询麻烦,只能通过应用程序来解决.谈谈在Java中的解决思路.其他语言原理类似.这里说的分表不是 MySQL 5.1 的 partition,而是人为把一个表分开存在若干表或不同的服务器.1. 应用程序级别实现见示意图 electThreadManager 分表数据查询管理器它为分表的每个database or server 建立一个 thread pool

  • mysql分表分库的应用场景和设计方式

    很多朋友在论坛和留言区域问mysql在什么情况下才需要进行分库分表,以及采用何种设计方式才是最优的选择,根据这些问题,小编为大家整理了关于MySQL分库分表的应用场景和最优的设计方式举例. 一. 分表 场景:对于大型的互联网应用来说,数据库单表的记录行数可能达到千万级甚至是亿级,并且数据库面临着极高的并发访问.采用Master-Slave复制模式的MySQL架构, 只能够对数据库的读进行扩展,而对数据库的写入操作还是集中在Master上,并且单个Master挂载的Slave也不可能无限制多,Sl

  • MySQL数据库设计之利用Python操作Schema方法详解

    弓在箭要射出之前,低声对箭说道,"你的自由是我的".Schema如箭,弓似Python,选择Python,是Schema最大的自由.而自由应是一个能使自己变得更好的机会. Schema是什么? 不管我们做什么应用,只要和用户输入打交道,就有一个原则--永远不要相信用户的输入数据.意味着我们要对用户输入进行严格的验证,web开发时一般输入数据都以JSON形式发送到后端API,API要对输入数据做验证.一般我都是加很多判断,各种if,导致代码很丑陋,能不能有一种方式比较优雅的验证用户数据呢

  • 浅谈mysql的索引设计原则以及常见索引的区别

    索引定义:是一个单独的,存储在磁盘上的数据库结构,其包含着对数据表里所有记录的引用指针. 数据库索引的设计原则: 为了使索引的使用效率更高,在创建索引时,必须考虑在哪些字段上创建索引和创建什么类型的索引. 那么索引设计原则又是怎样的? 1.选择唯一性索引 唯一性索引的值是唯一的,可以更快速的通过该索引来确定某条记录. 例如,学生表中学号是具有唯一性的字段.为该字段建立唯一性索引可以很快的确定某个学生的信息. 如果使用姓名的话,可能存在同名现象,从而降低查询速度. 2.为经常需要排序.分组和联合操

  • MySQL备份恢复设计思路

    背景 首先交代一下背景,由于某些因素的限制,我们公司目前的备份策略采用的是隔天全备的方案,增量备份则使用的是binlog server的方式,那么如何快速恢复就成为了我们需要思考的问题 恢复需求 根据我以往的一些经验来说,通常需要从备份恢复数据的场景有如下几种: 1.被误删库了 2.被误删表了,类型为TRUNCATE或者DROP 3.被误删列了,类型为ALTER ... DROP COLUMN 4.被误删数据了,类型为DELETE或者UPDATE或者REPLACE 5.表空间损坏或出现坏块了 根

  • PHP+MySQL投票系统的设计和实现分享

    系统不大,完成这个系统的过程我分了三个步骤 •数据库设计 •系统框架设计 •前端美化 数据库的设计 设计三张表:投票结果统计表(count_voting),投票人记录表(ip_votes),用户表(user) 投票结果统计表用于统计最后的投票记录,我给它弄了4个字段:被投票项的名称(SelectName),被投票项标签名(LabelName)(起到分类的作用),票数(CountVotes). 投票人记录表用于登记投票人的ip(IP),地理位置(Location),投票时间(VoteTime),被

  • PHP+Mysql树型结构(无限分类)数据库设计的2种方式实例

    我们经常需要在关系型数据库中保存一些树状结构数据,比如分类.菜单.论坛帖子树状回复等.常用的方法有两种: 1. 领接表的方式: 2. 预排序遍历树方式: 假设树状结构如下图: 领接表方式 主要依赖于一个 parent 字段,用于指向上级节点,将相邻的上下级节点连接起来,id 为自动递增自动,parent_id 为上级节点的 id.一目了然,"Java"是"Language"的子节点. 我们要显示树,PHP 代码也可以很直观,代码如下: 复制代码 代码如下: <

  • MySQL20个高性能架构设计原则(值得收藏)

    开源数据库架构设计原则 01. 技术选型 选择成熟的平台和技术,同时是最熟悉的,能做到极致的,用好不用坏,用熟不用生.目前业界的MySQL主流分支版本有Oracle官方版本的MySQL.Percona Server.MariaDB. 02. 高可用选择 高可用解决方案探讨的本质上是低宕机时间解决方案,可以理解成高可用的反面是不可用,绝大部分情况下数据库宕机才会导致数据库不可用.随着技术发展,开源数据库方面很多高可用组件(主从复制.半同步.MGR.MHA.Galera Cluster),对应场景,

  • Mysql数据库设计三范式实例解析

    三范式 1NF:字段不可分; 2NF:有主键,非主键字段依赖主键; 3NF:非主键字段不能相互依赖; 解释: 1NF:原子性 字段不可再分,否则就不是关系数据库; 2NF:唯一性 一个表只说明一个事物; 3NF:每列都与主键有直接关系,不存在传递依赖; 第一范式(1NF) 即表的列的具有原子性,不可再分解,即列的信息,不能分解, 只要数据库是关系型数据库(mysql/oracle/db2/informix/sysbase/sql server),就自动的满足1NF.数据库表的每一列都是不可分割的

  • 如何设计高效合理的MySQL查询语句

    MySQL查询语句大家都在用,但是应该如何设计高效合理的MySQL查询语句呢?下面就教您MySQL查询语句的合理设计方法,分享给大家学习学习. 1.合理使用索引 索引是数据库中重要的数据结构,它的根本目的就是为了提高查询效率.现在大多数的数据库产品都采用IBM最先提出的ISAM索引结构.索引的使用要恰到好处,其使用原则如下: ●在经常进行连接,但是没有指定为外键的列上建立索引,而不经常连接的字段则由优化器自动生成索引. ●在频繁进行排序或分组(即进行group by或order by操作)的列上

  • MySQL 可扩展设计的基本原则

    前言 随着信息量的飞速增加,硬件设备的发展已经慢慢的无法跟上应用系统对处理能力的要求了.此时,我们如何来解决系统对性能的要求? 只有一个办法,那就是通过改造系统的架构体系,提升系统的扩展能力,通过组合多个低处理能力的硬件设备来达到一个高处理能力的系统,也就是说,我们必须进行可扩展设计. 一.什么是可扩展性 在讨论可扩展性之前,可能很多朋有会问:常听人说起某某网站某某系统在可扩展性方面设计的如何如何好,架构如何如何出色,到底什么是扩展?怎样算是可扩展?什么又是可扩展性呢?其实也就是大家常听到的 S

  • 专业级的MySQL开发设计规范及SQL编写规范

    在团队开发过程中为了项目的稳定,代码的高效,管理的便捷制定内部种开发设计规范是必不可少的, 这里分享一份我们定义MySQL开发设计规范包括表设计规范,字段设计规范,SQL编写规范 数据库对象命名规范 数据库对象 命名规范的对象是指数据库SCHEMA.表TABLE.索引INDEX.约束CONSTRAINTS等的命名约定 数据库对象命名原则 命名使用具有意义的英文词汇,词汇中间以下划线分隔 命名只能使用英文字母.数字.下划线 避免用MySQL的保留字如:call.group等 所有数据库对象使用小写

随机推荐