程序员应知——数据库设计的两个误区(转)

Origin软件XRD全峰拟合保姆级教程:从数据导入到弱峰处理技巧 本文提供了一份Origin软件进行XRD全峰拟合的深度实战指南。文章重点解析了从数据导入预处理、基线锚点视觉化设置,到弱峰拟合的锁定策略与手动干预等核心技巧,旨在帮助用户避开常见错误,获得可靠、精确的拟合结果,从而有效服务于材料结构分析。 阅读详情

写在前面:本来“程序员应知”系列中应该写的都是与程序员密切相关的内容,而数据库设计似乎应该是数据库管理员的工作。然而,在实际的工作环境中,我所经历几乎所有的项目中,数据库设计工作都是由程序员来完成的;就算我们是不需要做数据库设计的程序员,也至少需要对数据库的结构有充分的理解,那样也便于我们编写和维护系统。思量再三,我还是将这篇与数据库设计相关的文章放在了这个系列当中。

在几乎所有的企业级应用程序中,包括各种MIS、ERP、CRM等等,都会使用数据库,这样的好处是显而易见的,很容易地实现了数据层和业务逻辑层的分离,而且对于性能的优化也在一定程度上提供了便利。

然而,在我所经历过的项目中,某些数据库的设计会存在一些问题,尤其普遍的就是下面将要描述的这两点,个人觉得是应该避免的误区,总结出来与大家讨论。

误区之一 备用字段

现象描述:

在数据表中,不仅设计了当前所需要的字段,而且还在其中留出几个字段作为备用。

比方说,我设计了一个人员表(Person),其中已经添加了各种必要的字段,包括姓名(Name)、性别(Sex)、出生年月日(birthday)等等。大功告成之后,我忽然想到,将来系统中应该还会有很多其它与人相关的内容吧,比方说毕业院校,比方说工作单位等等,尽管现在根本不需要填写,以后可能还是会用到的吧。拍脑袋一项,那就加入5个varchar2型的字段,分别叫做Text1、Text2……Text5,然后又想,应该还有一些日期型的字段需要备用,就又建立了三个date型的字段,分别起名叫做date1、date2、date3,……

原因分析:

大家应该已经看出问题了,在这个数据表中存在大量暂时无用的字段,我们可以称之为备用字段,它们的作用是什么呢?就是以防万一,防备可能的情况。

这似乎可以叫做防患于未然,等到时候需要的时候,就不需要在表中增加新的字段了,而且这样做的话,一个表的数据应该会被存储在相邻的物理空间中,这对于性能也是有好处的。

另外的原因就是,在古老的数据库中,如果改变数据库的定义(包括增加字段、改变字段的类型、删除字段等等),那么其中所有的数据就会丢失,所以这项工作非常麻烦,我们需要先建立临时表,将数据备份出来,然后创建新表,将数据导入其中,最后再删除原来的表。

问题所在:

这样的做法对于项目会导致很多问题,而且原先想要解决的问题并不一定能够解决,不信的话,请往下看。

问题一:增加大量备用字段,必定会浪费很多空间,尽管其中可能都没有具体的数据,但是仅仅是空字段也会占据一定的空间的。

问题二:由于命名的特点,如果没有完善的文档管理流程,用不了多久(可能也就是两三年),就没有人能够说清楚到底哪个字段代表的是什么意义了。就算有文档管理,这些管理工作也会比较麻烦,而且在每次使用的时候都需要申请,还有可能会出现冲突的情况。

问题三:增加了这些备用字段就真的会够用吗?不一定,因为我们只是每个类型的字段留出几个备用,如果数量超过,或者要使用特殊的、不常用的类型的时候,还是需要增加新的字段。比方说在上述的Person表中,我们要存储照片,那么可能就要增加一个blob类型的photo字段,这在初期设计的时候可不一定会留出这样的备用字段。而且如果没有完善的管理,谁又能说清楚倒底哪个字段已经被使用,哪个字段还可以使用呢?到时候还不是要增加新的字段。

解决方案:

其实上面的这种设计方式就是一种“过度设计”,我们应该做的就是“按需设计”,在经过详细有效的分析之后,在数据表中只放置必要的字段,而不要留出大量的备用字段。

当需要增加相关的信息的时候,就要具体情况具体分析:

如果数量很少,而且信息的性质与原表密切相关,那么就可以直接在原表上增加字段,并将相关的数据更新进去。

如果数量较大,或者并非是原表对象至关重要的属性,那么就可以新增一个表,然后通过键值连接起来。

对于表的数据的存储位置所导致的性能问题,我们可以通过在特定时间对数据库的数据进行重组来解决,而这项工作对于长期运行的数据库来说,也是需要定期进行的。

误区之二 有意义的编码

现象描述:

使用有意义的编码作为一条记录的ID,甚至作为数据库的主键存在,例如,一个员工的编码设置为0203004,其中02代表员工所在分公司,03代表员工所在部门,004代表员工进入到该部门的序号。

原因分析:

ID的设置方式大概有以下几种,一种是纯粹的流水号,从1开始,每次加1,或者对其将以改进,将数字转换成为字符串的格式,比方说“0000001”;一种是无意义的随机编码,比方说GUID;还有一种就是有意义的编码,特定的位数会代表一定的意义。

我想之所以大家这么喜欢使用这种方式,主要是因为想要从编码中就能够得到一些信息,甚至有些程序中还有专门的对编码进行解析的模块。就像我们的身份证号码一样,看到身份证号就可以知道办身份证时的所在地、生日、性别等信息。

问题所在:

其实有意义的编码会导致很多问题,请看:

问题一:对编码资源的浪费。如果是纯粹的流水号,那么从1到10000就可以代表一万条记录,但是,如果使用有意义的编码,很可能1000条记录就会让五位的编码不够用。我就遇到过真正的情况,我们公司的投保单号码的第一位就是有意义的,代表的时该投保单所属的渠道,后面跟着很长的一串数字(9位)。理论上来说,这些编码永远都不会用完,但是,最开始的三个渠道使用的是1、4、7三个编码,但是一次新保险法的实行,导致原有的投保单作废,于是又启用了三个数字2、5、8,接下来公司改名,三个渠道又分别将投保单报废,重新启用新的开头数字,就这样,短短的几年间,所有的投保单号码全都被用完了,其实打印出来的投保单不过100万张。

问题二:不一定是唯一的,难以作为主键。想一下,我们的身份证号码就是这样的。原先15位的时候,后三位是序号,而男性会使用奇数,女性会使用偶数,这样就是说,一个地区同一天生日的人,男女都不能超过500人,否则就会导致号码的重复,尽管出现这种现象的概率比较低,但是还是客观存在的。

问题三:代表的意义不一定准确。比方说用带有意义的编码来为员工定义工号,其中可能会有部门、职务等等意义,但是如果员工在部门间发生了调动,或者职级发生了改变,是否需要改变他的编码呢?改变吧,那么所有的历史数据都要随之修改一次,工作量会非常大;不改变吧,那么代表的意义就不再准确,我们就无法从编码中得到该员工准确的信息。

解决方案:

所以,对于编码,非常不建议使用有意义的编码,要么使用纯粹的流水号,但这样可能需要定义一个范围比较大的类型,对于海量记录的数据,可能会不够用;那样的话就可以使用GUID,这样编码永远都不会重复,而且会有大量的编码资源可用。

 

从上面的两点我们可以看出,在数据库设计的过程中,有一些在非常多系统中都使用了,但是却带来了很多问题的方法,对于这种情况,我们就应该仔细思考,然后痛下决心,坚决抵制。

 

 

 

   回复   引用   查看     
#15楼 2010-07-01 09:28 | 金色海洋(jyk)       
数据库的主键,一定不能是有意义的,绝对不能用什么有意义的号来代替,像什么工号、身份证号、订单号、手机号、物料号等等,都是不可以的。

lz已经说得很详细了,不知道为什么还有人反对。

主键是给数据库看的,有意义的编号是给人来看的。

两个字段分别表示不就可以了吗?

第一个字段是主键,无意义的编码,给数据库用。

另一个字段是有意义的编码,给人看的。

这样,在程序的角度,或者数据库的角度,这个有意义的编码就可以随便去改,怎么改都不会影响数据的完整性。因为数据库不关心这个字段。

估计有人会反驳我的这个“随意去改”的这个说法吧,恩早有预料了。

所以我做了一个限定:在程序、数据库的角度是可以随便改的。
MIPI video mode 和 command mode 的区别 1、何为LCD RAM? LCD 是指字面意思是液晶显示屏(Liquid Crystal Display), 而RAM: 随机存取存储器(Random-Access Memory),两者完全是风马牛不相及的东西。 下图是一个标准的LCD的爆炸图(不含TP),请注意图中红色mark的地方:控制IC-- LCD的大脑。所谓的LCD RAM自然是指此大脑是否包含RAM. 题外话<不感兴趣的... 阅读详情

相关推荐

ADS笔记,新旧两组仿真数据进行绘图和列表对比

原理图器件参数的不同,怎么进行对比观看,操作如下。

彭辉荣的博客 3867

Multiple representations of the same entity are being merged 综合解决方案

目录问题来源解决方式hibernateSpringSpringBoot 问题来源 java.lang.IllegalStateException: Multiple representations of the same entity are being merged. 因为试图给 某一个new 的Transient对象 的某一个属性赋一个 已经Persistent 对象或者Detached 对象值。导致最后save 或者merge 这个Transient对象报这个错误。 解决方式 hibernate

Amo℃柠檬 2078

360加固DEX解密与ELF修复技术解析

本文深入解析360加固的DEX解密与ELF修复技术,详细介绍了其多层保护机制、Java层入口分析、Native层加载流程及反调试绕过技巧。通过RC4和zlib解密技术,结合Frida工具实现内存Dump和ELF文件修复,为逆向工程师提供实用解决方案。

weixin_29327525的博客 506

程序员为什么要学习数据库

程序员为什么要学习数据库 1、几乎任何一个企业级应用,都要用到数据库。 2、无论开发、测试、运维还是架构师,数据库都是加分神器! 3、小的软件企业分工不明确,全能型人才能得到更多的机会(就业和提升) 4、外包和自由程序员必备 结语: 时间: 2020-07-04 ...

weifc-wei 的博客 1021

深入解析NRF52832安全DFU Bootloader实现机制与蓝牙OTA升级流程

本文深入解析了NRF52832芯片安全DFU Bootloader的实现机制与蓝牙OTA升级流程。详细阐述了Bootloader的核心概念、双区升级策略、源码初始化流程以及蓝牙DFU服务的数据传输协议,并提供了从环境搭建、密钥生成到编译烧录、生成升级包的完整实战指南,帮助开发者构建安全可靠的无线固件更新系统。

weixin_29188043的博客 490

安装Anaconda和Labelme的教程

1 登录Anaconda官网,选择Download https://www.anaconda.com/distribution/ 2 选择你想下载的Python版本,选择你的操作系统和位数,然后点击Download按钮就开始下载了 3 开始安装 下面两个框框都勾选 点击next,等待安装成功 打开Anaconda Navigator 点击红色圈圈的按钮 在cmd中输入 (1)创建虚拟环境 conda create -n labelme python=3.6 (2)激活虚拟环境 conda activa

qq_42178122的博客 3807

Multiple representations of the same entity are being merged解决方法

最近在写网站过程中发现自己hibernate学的还不到家,好多错误,特地来记录一下这个错误: java.lang.IllegalStateException: Multiple representations of the same entity are being merged.错误信息 java.lang.IllegalStateException: Multiple representati

Monet Zheng的查漏补缺 5691

Open3D 点云转深度图像【2026最新版】

python版本Open3D 实现的点云转深度图像,博客长期更新,本文最新更新时间为:2026年5月10日。

点云侠的博客 2835

Multiple representations of the same entity are being merged解决方案

在此记录一下,项目中出现的问题:Multiple representations of the same entity are being merged顾名思义:当出现问题的时候,先考虑出现问题的原因,以及发生的场景,还原当时的面貌,这是一个侦探该有的逼格,真相只有一个。        回归正题:不扯淡蛋了,根据经验,首先我想到的,元素重复merge了,但是问题来了,如果元素重复merge就会造成...

chajinglong的专栏 5289

一文吃透 SAP IDoc 状态码:从 TEDS1 到 WE02 排障,再到 ABAP 自动化监控

在 SAP 集成场景里,IDoc 往往是最常见、也最容易被低估的一条生命线:采购订单、发票、主数据、库存移动……只要系统之间要稳定地交换结构化业务数据,IDoc 就经常登场。真正让人头疼的,并不是 IDoc 本身,而是它在链路里到底走到了哪一步、卡在了哪里、该找谁背锅。这篇文章把常用的 IDoc 状态码按出站、入站拆开讲清楚,并且把每个状态对应的真实世界故障现象、排查入口、以及可以落地的 ABAP 监控代码串起来,让你看到状态码就能想到动作。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 404

7.91版本unidbg调用方式

【代码】xhs最新7.91版本unidbg调用方式。

Codeooo 博客 1106

CascadeType.MERGE报错解决:Multiple representations of the same entity are being merged

一、问题 我有三个实体有很多关系: 角色实体: @Entity public class Role { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer roleID; private String roleName; private String description; @ManyToMany(cascade = {CascadeType.MERGE,

HD243608836的博客 1229

《Autosar_MCAL高阶配置》总目录_培训教程持续更新中...

《Autosar_MCAL高阶配置》总目录_培训教程持续更新中...

「汽车电子助手」的博客 1万+

程序员应知——数据库设计的两个误区

写在前面:本来“程序员应知”系列中应该写的都是与程序员密切相关的内容,而数据库设计似乎应该是数据库管理员的工作。然而,在实际的工作环境中,我所经历几乎所有的项目中,数据库设计工作都是由程序员来完成的;就算我们是不需要做数据库设计的程序员,也至少需要对数据库的结构有充分的理解,那样也便于我们编写和维护系统。思量再三,我还是将这篇与数据库设计相关的文章放在了这个系列当中。在几乎所有的企业级应用程序中,包括各种MIS、ERP、CRM等等,都会使用数据库,这样的好处是显而易见的,很容易地实现了数据层和业务逻辑层的分

凌云工作室 1万+

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

程序员应知——索引

这里是“程序员应知”这个系列的索引,按照发布日期排列,:) 每次发布新的文章,我会更新这个列表,希望可以给大家带来方便。

凌云工作室 6542

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

[转载] 程序员应知——数据库设计的两个误区

<br />写在前面:本来“程序员应知”系列中应该写的都是与程序员密切相关的内容,而数据库设计似乎应该是数据库管理员的工作。然而,在实际的工作环境中,我所经历几乎所有的项目中,数据库设计工作都是由程序员来完成的;就算我们是不需要做数据库设计的程序员,也至少需要对数据库的结构有充分的理解,那样也便于我们编写和维护系统。思量再三,我还是将这篇与数据库设计相关的文章放在了这个系列当中。<br />在几乎所有的企业级应用程序中,包括各种MIS、ERP、CRM等等,都会使用数据库,这样的好处是显而易见的,很容易地实现

Kim_expert的专栏 420

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

程序员应具备的素质

发信人: awl (Addison Wesley Longman), 信区: Program 标  题: 程序员应具备的素质 发信站: 鼓浪听涛 (Sun Jun 10 07:51:14 2001), 转信 http://www.linuxbyte.net/ShowArt.php3?ID=2173 程序员是一种技术工作,在IT的发展中有相当重要的地位,从底层硬件通讯协议的 建立,到数据传输层的处理

Tisan的专栏 1924

程序员的十大思维误区

作为老码农老程序员,日常工作中打交道最多的也是程序员,在这个过程中,我发现不少程序员在技术、产品等方面的思维有各种各样的小问题。现在我就来回忆一下,把这些我认为不太好的思维习惯记录下来,在提醒自己的同时,也供程序员朋友们参考,不必对号入座,有则改之,无则加勉,或者你甚至认为这些不是思维误区都可以的,我也不知道起怎么样的标题比较合适,且称“程序员的十大思维误区”吧,祝阅读愉快! 测试人员不按我的实...

qf2019的博客 311

【程序员副业指南】从0开始,如何在知乎打造你的技术影响力与变现之路?

本文为程序员提供了在知乎平台上开展副业的详细指南。首先,文章分析了知乎作为程序员副业平台的独特优势,包括精准的用户画像、长尾流量、多样的内容形式和变现路径。接着,文章详细介绍了从账号注册、基础设置到精准定位的步骤,强调了内容创作的重要性,并提供了内容类型选择、创作策略和优快云文章转知乎的优化建议。此外,文章还探讨了内容运营与推广的技巧,以及通过内容付费、广告带货和引流私域等多种方式实现变现的途径。最后,文章提醒程序员在运营过程中应保持长期主义、持续学习、避免过度营销、注意版权和保持谦逊的心态。总之,本文为

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 1373
上一篇: 经过一年时间的沉淀 再次回首 TCP Socket服务器编程 (转)
下一篇: 数据库优化系列(转)
ulark
博客等级 码龄17年 31粉丝 530原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值