请教,“多增加一个(没必要的)字段,减少多表查询”的做法可取么?

cy88310 2010-04-16 09:42:55
表结构:
user(userid,username)
userdisk(diskid,user_id,diskname)
userfile(fileid,disk_id,filename)
现在我在查询userfile列表信息(文件名filename和拥有者姓名username)的时候需要这样多表查询
select C.filename,A.username FROM user A,userdisk B,userfile C WHERE C.disk_id=B.diskid and B.user_id=A.userid
如果我在C表中多增加一个userid字段,
user(userid,username)
userdisk(diskid,user_id,diskname)
userfile(fileid,disk_id,user_id,filename)
那么查询语句就变成:select C.filename,A.username from user A,userfile C where C.user_id = A.userid
各个表之间的关系比较简单,但从数据量大和数据量小的两种情况考虑,这种“多增加一个(没必要的)字段,减少多表查询”的做法可取么?
...全文
335 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
我认为你加上userid这个字段会大大提高你的效率

1,从查询来讲,可能我们只需要查询某个userid的files,那么只需要在userfiles表中查询
如果我们只查询userid的disk,也只需要在userdisk中查询
2,增加一个file,因为file和userid相关,所以增加的时候也只操作一个表
3, 删除file,我们也只需要操作一个表
4,更新file,也只需要删除一个表
5, 删除disk,只需要指明diskid和userid即可,删除语句可以分两条语句来写,不必先删除userfiles表
6,。。。其它


老黎 2010-04-16
  • 打赏
  • 举报
回复

数据库设计做法
1、符合范式
2、对变动不大的表可以适当冗余,比如月报表、年报表

licry01 2010-04-16
  • 打赏
  • 举报
回复
如果user_id, disk_id都是identity类型的、且建有索引, 多加格字段是不可取的
因为有索引的int数据类型检索是二分检索, 速度是相当快的
喜-喜 2010-04-16
  • 打赏
  • 举报
回复
数据库设计指导原则

一、设计数据库之前

1. 考察现有环境
在设计一个新数据库时,你不但应该仔细研究业务需求而且还要考察现有的系统。大多数数据库项目都不是从头开始建立的。通常,机构内总会存在用来满足特定需求的现有系统(可能没有实现自动计算)。显然,现有系统并不完美,否则你就不必再建立新系统了。但是对旧系统的研究可以让你发现一些可能会忽略的细微问题。一般来说,考察现有系统对你绝对有好处。[重要]
— Lamont Adams

2. 定义标准的对象命名规范
检查表名、报表名和查询名之间的命名规范。你可能会很快就被这些不同的数据库要素的名称搞糊涂了。假如你坚持统一地命名这些数据库的不同组成部分,至少你应该在这些对象名字的开头用table、query 或者report 等前缀加以区别。
— rrydenm

如果采用了Microsoft Access,你可以用 qry、rpt、 tbl 和mod 等符号来标识对象(比如tbl_Employees)。我在和SQL Server(或者Oracle)打交道的时候还用过tbl 来索引表,但我用sp_company (现在用sp_feft_)标识存储过程,因为在有的时候如果我发现了更好的处理办法往往会保存好几个拷贝。我在实现 SQL Server 2000 时用udf_ (或者类似的标记)标识我编写的函数。
— Timothy J. Bruce

3. 畅想未来,但不可忘了过去的教训
我发现询问用户如何看待未来需求变化非常有用。这样做可以达到两个目的:首先,你可以清楚地了解应用设计在哪个地方应该更具灵活性以及如何避免性能瓶颈;其次,你知道发生事先没有确定的需求变更时用户将和你一样感到吃惊。
— chrisdk

一定要记住过去的经验教训!我们开发人员还应该通过分享自己的体会和经验互相帮助。即使用户认为他们再也不需要什么支持了,我们也应该对他们进行这方面的教育,我们都曾经面临过这样的时刻“当初要是这么做了该多好⋯⋯”。
— dhattrem

4. 了解你的业务
一旦你认为你已经明确 了业务内容,你最好同客户进行一次系统的交流。采用客户的术语并且向他们解释你所想到的和你所听到的。同时还应该用可能、将会和必须等词汇表达出系统的关系基数。这样你就可以让你的客户纠正你自己的理解然后做好下一步的ER 设计。[重要]
— teburlew

5. 创建数据字典和ER图表
一定要花点时间创建ER 图表和数据字典。其中至少应该包含每个字段的数据类型和在每个表内的主外键。创建ER 图表和数据字典确实有点费时但对其他开发人员要了解整个设计却是完全必要的。越早创建越能有助于避免今后面临的可能混乱,从而可以让任何了解数据库的人都明确如何从数据库中获得数据。[重要]
— bgumbert

有一份诸如ER 图表等最新文档其重要性如何强调都不过分,这对表明表之间关系很有用,而数据字典则说明了每个字段的用途以及任何可能存在的别名。对SQL 表达式的文档化来说这是完全必要的。
— vanduin.chris.cj

6. 从输入输出下手
在定义数据库表和字段需求(输入)时,首先应检查现有的或者已经设计出的报表、查询和视图(输出)以决定为了支持这些输出哪些是必要的表和字段。举个简单的例子:假如客户需要一个报表按照邮政编码排序、分段和求和,你要保证其中包括了单独的邮政编码字段而不要把邮政编码糅进地址字段里。
— peter.marshall

7. 理解客户需求
看起来这应该是显而易见的事,但需求就是来自客户(这里要从内部和外部客户的角度考虑)。不要依赖用户写下来的需求,真正的需求在客户的脑袋里。你要让客户解释其需求,而且随着开发的继续,还要经常询问客户保证其需求仍然在开发的目的之中。一个不变的真理是:“只有我看见了我才知道我想要的是什么”必然会导致大量的返工,因为数据库没有达到客户从来没有写下来的需求标准。而更糟的是你对他们需求的解释只属于你自己,而且可能是完全错误的。[重要]
— kgilson

二、设计表和字段

1. 检查各种变化
我在设计数据库的时候会考虑到哪些数据字段将来可能会发生变更。比方说,姓氏就是如此(注意是西方人的姓氏,比如女性结婚后从夫姓等)。所以,在建立系统存储客户信息时,我倾向于在单独的一个数据表里存储姓氏字段,而且还附加起始日和终止日等字段,这样就可以跟踪这一数据条目的变化。
— Shropshire Lad

2. 采用有意义的字段名
除非你在使用只面向你的缩写字段名的系统,否则请尽可能地把字段描述的清楚些。当然,也别做过头了,比如Customer_Shipping_Address_Street_Line_1 I 虽然很富有说明性,但没人愿意键入这么长的名字,具体尺度就在你的把握中。
— Lamont Adams

3. 标准化不能过头
对那些不熟悉标准化一词(normalization )的人而言,标准化可以保证表内的字段都是最基础的要素,而这一措施有助于消除数据库中的数据冗余。标准化有好几种形式,但Third NormalForm(3NF)通常被认为在性能、扩展性和数据完整性方面达到了最好平衡。简单来说,3NF 规定:
· 表内的每一个值都只能被表达一次
· 表内的每一行都应该被唯一的标识(有唯一键)
· 表内不应该存储依赖于其他键的非键信息
遵守3NF 标准的数据库具有以下特点:有一组表专门存放通过键连接起来的关联数据。比方说,某个存放客户及其有关定单的3NF 数据库就可能有两个表:Customer 和Order。Order 表不包含定单关联客户的任何信息,但表内会存放一个键值,该键指向Customer 表里包含该客户信息的那一行。更高层次的标准化也有,但更标准是否就一定更好呢?答案是不一定。事实上,对某些项目来说,甚至就连3NF 都可能给数据库引入太高的复杂性。
— Lamont Adams

为了效率的缘故,对表不进行标准化有时也是必要的,这样的例子很多。曾经有个开发财务分析软件的活就是用非标准化表把查询时间从平均40 秒降低到了两秒左右。虽然我不得不这么做,但我绝不把数据表的非标准化当作当然的设计理念。而具体的操作不过是一种派生。所以如果表出了问题重新产生非标准化的表是完全可能的。
— epepke

过分标准化可要小心,这样做可能会导致性能上出现问题。虽然地址和电话表分离通常可以达到最佳状态,但是如果需要经常访问这类信息,或许在其父表中存放“首选”信息(比如Customer 等)更为妥当些。非标准化和加速访问之间的妥协是有一定意义的。
— dhattrem

4. 不活跃或是不采用的指示符
增加一个字段表示所在记录是否在业务中不再活跃挺有用的。不管是客户、员工还是其他什么人,这样做都能有助于再运行查询的时候过滤活跃或者不活跃状态。同时还消除了新用户在采用数据时所面临的一些问题,比如,某些记录可能不再为他们所用,再删除的时候可以起到一定 的防范作用。[重要]
— theoden

5. 使用角色实体定义属于某类别的列
在需要对属于特定类别或者具有特定角色的事物做定义时,可以用角色实体来创建特定的时间关联关系,从而可以实现自我文档化。这里的含义不是让PERSON 实体带有Title 字段,而是说,为什么不用PERSON 实体和PERSON_TYPE 实体来描述人员呢?然后,比方说,当 John Smith, Engineer 提升为John Smith, Director 乃至最后爬到John Smith, CIO 的高位,而所有你要做的不过是改变两个表PERSON 和PERSON_TYPE 之间关系的键值,同时增加一个日期/时间字段来知道变化是何时发生的。这样,你的PERSON_TYPE 表就包含了所有PERSON 的可能类型,比如Associate、Engineer、Director、CIO 或者CEO 等。还有个替代办法就是改变PERSON 记录来反映新头衔的变化,不过这样一来在时间上无法跟踪个人所处位置的具体时间。[重要,通过时间戳追踪系统的变化情况]
— teburlew

6. 提防大小写混用的对象名和特殊字符
过去最令我恼火的事情之一就是数据库里有大小写混用的对象名,比如CustomerData。这一问题从Access 到Oracle 数据库都存在。我不喜欢采用这种大小写混用的对象命名方法,结果还不得不手工修改名字。想想看,这种数据库/应用程序能混到采用更强大数据库的那一天吗?采用全部大写而且包含下划符的名字具有更好的可读性(CUSTOMER_DATA),绝对不要在对象名的字符之间留空格。
— bfren

7. 小心保留词
要保证你的字段名没有和保留词、数据库系统或者常用访问方法冲突,比如,最近我编写的一个ODBC 连接程序里有个表,其中就用了DESC 作为说明字段名。后果可想而知!DESC 是DESCENDING 缩写后的保留词。表里的一个SELECT *语句倒是能用,但我得到的却是一大堆毫无用处的信息。
— Daniel Jordan

8. 避免使用触发器
触发器的功能通常可以用其他方式实现。在调试程序时触发器可能成为干扰。假如你确实需要采用触发器,你最好集中对它文档化。
— kol

9. 包含版本机制
建议你在数据库中引入版本控制机制来确定使用中的数据库的版本。无论如何你都要实现这一要求。时间一长,用户的需求总是会改变的。最终可能会要求修改数据库结构。虽然你可以通过检查新字段或者索引来确定数据库结构的版本,但我发现把版本信息直接存放到数据库中不更为方便吗?[重要]
— Richard Foster

10. 列命名的技巧
我们发现,假如你给每个表的列名都采用统一的前缀,那么在编写SQL 表达式的时候会得到大大的简化。这样做也确实有缺点,比如破坏了自动表连接工具的作用,后者把公共列名同某些数据库联系起来,不过就连这些工具有时不也连接错误嘛。举个简单的例子,假设有两个表:Customer 和Order。Customer 表的前缀是cu_,所以该表内的子段名如下:cu_name_id、cu_surname、cu_initials 和cu_address 等。Order 表的前缀是or_,所以子段名是:or_order_id、or_cust_name_id、or_quantity 和or_description 等。

这样从数据库中选出全部数据的SQL 语句可以写成如下所示:
Select * from Customer, Order
Where cu_surname = "MYNAME"
and cu_name_id = or_cust_name_id
and or_quantity = 1;
在没有这些前缀的情况下则写成这个样子:
Select * from Customer, Order
Where Customer.surname = "MYNAME"
and Customer.name_id = Order.cust_name_id
and Order.quantity = 1

第1 个SQL 语句没少键入多少字符。但如果查询涉及到5 个表乃至更多的列你就知道这个技巧多有用了。[可取]
— Bryce Stenberg

三、选择主键和索引

1. 数据挖掘要预先计划
可操作数据仓库(ODS)和数据仓库(DW)这两种环境下的数据索引是有差别的。在DW 环境下,你要考虑销售部门是如何组织销售活动的。他们并不是数据库管理员,但是他们确定表内的键信息。这里设计人员或者数据库工作人员应该分析数据库结构从而确定出性能和正确输出之间的最佳条件。
— teburlew

2. 分解字段用于索引
为了分离命名字段和包含字段以支持用户定义的报表,请考虑分解其他字段(甚至主键)为其组成要素以便用户可以对其进行索引。索引将加快SQL 和报表生成器脚本的执行速度。比方说,我通常在必须使用SQL LIKE 表达式的情况下创建报表,因为 case number 字段无法分解为year、serial number、case type 和defendant code 等要素。性能也会变坏。假如年度和类型字段可以分解为索引字段那么这些报表运行起来就会快多了。[重要]
— rdelval

3. 别忘了索引
索引是从数据库中获取数据的最高效方式之一。95%的数据库性能问题都可以采用索引技术得到解决。作为一条规则,我通常对逻辑主键使用唯一的成组索引,对系统键(作为存储过程)采用唯一的非成组索引,对任何外键列采用非成组索引。不过,索引就象是盐,太多了菜就篌了。你得考虑数据库的空间有多大,表如何进行访问,还有这些访问是否主要用作读写。[重要]
— tduvall

大多数数据库都索引自动创建的主键字段,但是可别忘了索引外键,它们也是经常使用的键,比如运行查询显示主表和所有关联表的某条记录就用得上。还有,不要索引memo/note 字段,不要索引大型字段(有很多字符),这样作会让索引占用太多的存储空间。
— gbrayton

4. 不要索引小型表
不要为小型数据表设置任何键,假如它们经常有插入和删除操作就更别这样作了。对这些插入和删除操作的索引维护可能比扫描表空间消耗更多的时间。
— kbpatel

5. 不要采用用户的输入作为主键
在确定采用什么字段作为表的键的时候,可一定要小心用户将要编辑的字段。通常的情况下不要选择用户可编辑的字段作为键。这样做会迫使你采取以下两个措施:
· 在创建记录之后对用户编辑字段的行为施加限制。假如你这么做了,你可能会发现你的应用程序在商务需求突然发生变化,而用户需要编辑那些不可编辑的字段时缺乏足够的灵活性。当用户在输入数据之后直到保存记录才发现系统出了问题他们该怎么想?删除重建?假如记录不可重建是否让用户走开?
· 提出一些检测和纠正键冲突的方法。通常,费点精力也就搞定了,但是从性能上来看这样做的代价就比较大了。还有,键的纠正可能会迫使你突破你的数据和商业/用户界面层之间的隔离。
所以还是重提一句老话:你的设计要适应用户而不是让用户来适应你的设计。
— Lamont Adams

四、保证数据的完整性

1. 用约束而非商务规则强制数据完整性
只要有可能,请采用数据库系统实现数据的完整性。这不但包括通过标准化实现的完整性而且还包括数据的功能性。在写数据的时候还可以增加触发器来保证数据的正确性。不要依赖于商务层保证数据完整性;它不能保证表之间(外键)的完整性所以不能强加于其他完整性规则之上。[重要]
— Peter Ritchie

2. 分布式数据系统
对分布式系统而言,在你决定是否在各个站点复制所有数据还是把数据保存在一个地方之前应该估计一下未来5 年或者10 年的数据量。当你把数据传送到其他站点的时候,最好在数据库字段中设置一些标记。在目的站点收到你的数据之后更新你的标记。为了进行这种数据传输,请写下你自己的批处理或者调度程序以特定时间间隔运行而不要让用户在每天的工作后传输数据。本地拷贝你的维护数据,比如计算常数和利息率等,设置版本号保证数据在每个站点都完全一致。
— Suhair TechRepublic

3. 强制指示完整性
没有好办法能在有害数据进入数据库之后消除它,所以你应该在它进入数据库之前将其剔除。激活数据库系统的指示完整性特性。这样可以保持数据的清洁而能迫使开发人员投入更多的时间处理错误条件。[可取]
— kol

4. 关系
如果两个实体之间存在多对一关系,而且还有可能转化为多对多关系,那么你最好一开始就设置成多对多关系。从现有的多对一关系转变为多对多关系比一开始就是多对多关系要难得多。[重要]
— CS Data Architect

5. 采用视图
为了在你的数据库和你的应用程序代码之间提供另一层抽象,你可以为你的应用程序建立专门的视图而不必非要应用程序直接访问数据表。这样做还等于在处理数据库变更时给你提供了更多的自由。
— Gay Howe

6. 使用查找
控制数据完整性的最佳方式就是限制用户的选择。只要有可能都应该提供给用户一个清晰的价值列表供其选择。这样将减少键入代码的错误和误解同时提供数据的一致性。某些公共数据特别适合查找:国家代码、状态代码等。
— CS Data Architect

五、其他小技巧

1. 文档、文档、还是文档
对所有的快捷方式、命名规范、限制和函数都要编制文档。
— nickypendragon

采用给表、列、触发器等加注释的数据库工具。是的,这有点费事,但从长远来看,这样做对开发、支持和跟踪修改非常有用。
— chardove

取决于你使用的数据库系统,可能有一些软件会给你一些供你很快上手的文档。你可能希望先开始在说,然后获得越来越多的细节。或者你可能希望周期性的预排,在输入新数据同时随着你的进展对每一部分细节化。不管你选择哪种方式,总要对你的数据库文档化,或者在数据库自身的内部或者单独建立文档。这样,当你过了一年多时间后再回过头来做第2 个版本,你犯错的机会将大大减少。[重要]
— mrs_helm

2. 保存常用信息
让一个表专门存放一般数据库信息非常有用。我常在这个表里存放数据库当前版本、最近检查/修复(对Access)、关联设计文档的名称、客户等信息。这样可以实现一种简单机制跟踪数据库,当客户抱怨他们的数据库没有达到希望的要求而与你联系时,这样做对非客户机/服务器环境特别有用。
— Richard Foster
cy88310 2010-04-16
  • 打赏
  • 举报
回复
哪位大虾能不能从数据库设计原则的高度讲下,小弟受教了
fsse2000 2010-04-16
  • 打赏
  • 举报
回复
一般情況下 不需要冗余。
如果比較慢的話,建立索引 和 臨時表 來提高查詢速度。

只是某些特定的情況下,允許冗余。
最好先不要冗余,不然習慣了,對以后自己的設計有習慣性的影響。
jwwyqs 2010-04-16
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 fredrickhu 的回复:]
数据量大的话 造成冗余过多 不可取 查询速度可以通过索引来提高
数据量小的话 允许适当冗余 可取
[/Quote]
up
永生天地 2010-04-16
  • 打赏
  • 举报
回复
我觉得数据量大,还是有必要的
Yang_ 2010-04-16
  • 打赏
  • 举报
回复
这可能不是“多增加一个(没必要的)字段”,而是修改了实体间的关系
--小F-- 2010-04-16
  • 打赏
  • 举报
回复
数据量大的话 造成冗余过多 不可取 查询速度可以通过索引来提高
数据量小的话 允许适当冗余 可取

34,590

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server相关内容讨论专区
社区管理员
  • 基础类社区
  • 二月十六
  • 卖水果的net
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧