初次数据库设计:我是否过度设计?[关闭]


246

背景

我是CS大学一年级的学生,我做兼职工作是我父亲的小生意。我没有在现实世界中进行应用程序开发的经验。我用Python编写了脚本,用C编写了一些课程,但没有这样的东西。

我父亲的培训业务不多,目前所有课程都通过外部网络应用程序进行计划,记录和跟进。有导出/“报告”功能,但是它非常通用,我们需要特定的报告。我们无权访问实际数据库来运行查询。我被要求设置一个自定义报告系统。

我的想法是创建通用的CSV导出,并将其导入(可能是使用Python)(每天晚上)到办公室中托管的MySQL数据库中,从那里我可以运行所需的特定查询。我没有数据库方面的经验,但了解非常基础的知识。我已经阅读了一些有关数据库创建和常规表单的信息。

我们可能很快就会有国际客户,因此如果发生这种情况,我希望数据库不会爆炸。我们目前也有几个大公司作为客户,分别设有不同的部门(例如ACME母公司,ACME医疗保健部门,ACME身体护理部门)

我提出的架构如下:

  1. 从客户的角度来看:
    • 客户是主表
    • 客户链接到他们工作的部门
      • 部门可以分散在一个国家/地区:伦敦的HR,斯旺西的市场营销等。
      • 部门与公司的部门联系在一起
    • 部门链接到母公司
  2. 从类的角度来看:
    • 会话是主表
      • 老师链接到每个会话
      • 每个会话均会获得一个statusid。例如0-已完成,1-已取消
      • 会话被分组为任意大小的“包”
    • 每个包装都分配给一个客户

我在一张纸上“设计”(更像是乱涂乱画)该架构,试图使其标准化为第三种形式。然后我把电源插头插上到MySQL Workbench和它使人们都非常适合我:
点击查看全尺寸图片

替代文字
(来源:maian.org

我将要运行的示例查询

  • 哪些客户的信用额仍处于闲置状态(将来未安排课程的客户)
  • 每个客户/部门/部门的出勤率是多少(由每个会话中的状态ID衡量)
  • 一个月一个老师上了几节课
  • 标记出勤率低的客户
  • 针对人力资源部门的自定义报告以及部门人员的出勤率

问题

  • 这是工程过度还是我朝着正确的方向前进?
  • 对于大多数查询,需要联接多个表是否会对性能造成重大影响?
  • 我已经向客户端添加了一个“ lastsession”列,因为它可能将是一个常见的查询。这是个好主意还是应该严格规范化数据库?

谢谢你的时间


131
尊敬的一年级CS学生:请继续使用StackOverflow。您的问题很有趣,写得很好并且很有帮助。换句话说,您在提问者中排名前1%。
亚当·克罗斯兰

一个部门可以包含其他部门吗?如果是这种情况,则可以使用“有”表将该部门链接回它所包含的部门。
Mark Schultheiss 2010年

感谢您的友好评论:) Mark,我将不得不再次阅读该项目的文档,但我认为我们没有发现这种情况。感谢您指出。
bob esponja'2

1
我不喜欢您的主键命名惯例。表格中divisions有名为的列divisionid。您不是觉得多余吗?随便命名id。您的表的名称也包括_has_:我会删除它,仅以它为名cities_departments。您的DATETIME列应该是类型,TIMESTAMP除非它们是用户输入的值。我认为拥有citiesand countries表格是个好主意。您可能会遇到麻烦,将表限制为一个表status。考虑使用an INT并对其进行按位比较-这样您可以在那里保留更多含义
james 2015年

@binnyb关于将id用作主键的名称有很多争论,人们在决定之前应该考虑一下。
杰迪

Answers:


42

您问题的其他答案:

1)对于初次遇到这种问题的人,您几乎可以达到目标。我认为到目前为止,关于这个问题的其他人的建议几乎涵盖了它。做得好!

2&3)您要获得的性能影响将主要取决于为特定查询/过程(更重要的是记录数量)具有和优化正确的索引。除非您要在主表中谈论超过一百万条记录,否则您似乎已经步入了一个足够主流的设计轨道,以至于合理的硬件性能不会成为问题。

就是说,这与您的问题3有关,从一开始,您可能就不会真正担心此处的性能或对规范化正统的超敏感性。这是您要构建的报告服务器,而不是基于事务的应用程序后端,在性能或规范化的重要性方面,该服务器具有完全不同的配置文件。支持实时注册和计划应用程序的数据库必须注意需要几秒钟才能返回数据的查询。报表服务器功能不仅对复杂和冗长的查询具有更大的容忍度,而且提高性能的策略也大不相同。

例如,在基于事务的应用程序环境中,您的性能改进选项可能包括将存储过程和表结构重构到第n级,或者为少量的常用数据开发缓存策略。在报表环境中,您当然可以执行此操作,但是通过引入快照机制可以对性能产生更大的影响,在快照机制中,计划的进程运行并存储预配置的报表,并且用户访问快照数据时不会对数据库层造成压力。每个请求的基础上。

所有这些都是漫长的花言巧语,以说明在您要创建的数据库的作用下,您采用的设计原则和技巧可能会有所不同。希望对您有所帮助。


1
1.谢谢,这令人放心!2&3。我仍然不知道索引如何工作,这是我计划阅读的内容。如果我们曾经遇到过达到一百万条记录的“问题”,那么可能会有预算聘请经验丰富的开发人员:P感谢您对现有的不同数据库角色的了解,这对我来说是新的,并且非常有趣。我将研究快照,因为您所描述的基本上是项目的最终目标。
bob esponja

如果您了解表,则索引的基础非常简单。从概念上讲,索引可以(通常是)实现为一个表,该表具有很少的列,其内容是从主表中复制的,而引用又是返回到主表的,该表的行被keot排序以便快速访问。B + Tree是最常见的索引排列方式,但是索引优化是大型公司拥有差异化技术的地方,因此,如果您尝试太深地应用类比,它就会变得模糊。
pojo-guy

14

您有正确的主意。但是,您可以清理它,并删除一些映射表(has *)。

您可以在Departments表中添加CityId和DivisionId。

除此之外,我认为一切都很好...


4
如果他想在不同部门或城市之间重复使用部门定义,我认为他需要映射表。
Jacob G 2010年

1
是的,我同意.....但是听起来像一个部门只能在一个城市/一个区中。如果没有,那么他的确是正确的。
牧师贡佐

我在办公室有一篇写有“规范”的Wiki文章,我将不得不再次阅读,但是Jacob G是正确的,IIRC的某些部门跨部门。ACME父母的一个人力资源部门负责ACME医疗保健和ACME身体护理。如果可以的话,我可以简化一下,谢谢您的建议。
bob esponja '02

6

我唯一要做的
更改是:1-将VARCHAR更改为NVARCHAR,如果您要进行国际化,则可能需要unicode。

2-如果可能的话,将您的int id更改为GUID(唯一标识符)(这可能只是我的个人喜好)。假设最终您拥有多个环境(开发/测试/登台/生产),则可能需要将数据从一个迁移到另一个。拥有GUID ID可以大大简化此操作。

3-您公司的三层->部门->部门结构可能不够。现在,这可能是过度设计,但是您可以概括该层次结构,以便可以支持n层深度。这会使您的某些查询更加复杂,因此可能不值得取舍。此外,可能会有任何具有更多层的客户端都可以很容易地“塞入”该模型。

4-您在客户端表中还有一个状态,该状态是VARCHAR,并且没有到状态表的链接。我希望那里的客户状态代表什么更加清晰。


1-谢谢,我在变音符号和UTF8方面遇到了麻烦,为此我要提出另一个问题。也许这就是问题所在。2-我在这里阅读了一些其他问题,对此有很多矛盾的意见,我将在这个问题上做更多的阅读。3-我将再次和爸爸再说一遍,看看我写的“规范”,看看这是否值得我们研究。-续下一条评论
bob esponja '02

4-为了简洁起见,我没有讨论这个主要问题:客户端的状态是它们是活动的(剩余会话)还是无效的(没有会话剩余)。更清楚地说,您是要为col指定一个更具描述性的名称吗?例如enrollment_status?感谢您的输入。
bob esponja '02

re#4-除了您更清楚的名字之外,如果只有两个状态,有效/无效,那么为什么不将其设为一点呢?
Jacob G 2010年

3
对GUID表示不同意,不寒而栗。他们的表现可能很糟糕。除非您需要替换,否则不要使用它们。
HLGEM 2010年

1
仅当您在表中谈论10百万行时,性能才发挥作用。如果您具有这种类型的结构,则可以通过顺序引导和广告素材索引来减轻这种情况。否则,在打折GUID时,“性能”是一团糟。
Jacob G

6

否。您似乎在设计较高的细节水平。

我认为,国家和公司与城市和分区在设计中实际上是同一实体。我将删除“国家和城市”表(和Cities_Has_Departments),并在必要时向“公司”表(或“公司类型”列中添加布尔标志IsPublicSector)(如果选择的范围比“私人部门/公共部门”更多,则为“公司类型”列)。

另外,我认为您对Departments表的使用存在错误。看起来,部门表可以用作每个客户部门可以拥有的各种部门的参考。如果是这样,则应将其称为DepartmentTypes。但是您的客户(我认为是参与者)不属于部门TYPE,而是属于公司中实际的部门实例。从目前的情况来看,您将知道给定的客户属于某个地方的HR部门,但不属于哪个部门!

换句话说,客户应该链接到您称为Divisions_Has_Departments的表(但我将其简称为Departments)。如果是这样,则如果要在数据库中使用标准参照完整性,则必须如上所述将城市分为多个部门。


国家/地区表适用于是否/何时我们的客户在一个以上国家/地区开展业务,并且每个国家/地区都有不同的人力资源部门。这样,我们就可以使用要处理的部门所在的国家/地区的数据来创建报告。对于部门和城市,我认为我们有一个拥有独立人力资源部门的客户。对于它们在其中设有总部的两个城市。或者至少是出于这种原因,我将坐下来重新考虑一下,看看它们是否真的必要。没想到CompanyType,我会找出这是否是我们需要跟踪的东西。
bob esponja

RE:部门表,我最初的想法是将其用作实际部门,部门名称为类型。在我看来,并非只有部门类型,这似乎更合乎逻辑。关于知道哪个部门以及某人属于哪个部门,我以为将部门链接到城市和部门(与公司链接)是可以的。我说错了吗 对于将城市划分为多个分区,一些分区跨越多个城市,我想甚至是国家。我会再次调查。感谢您的输入。
bob esponja '02

5

顺便说一句,值得注意的是,如果您已经在生成CSV并将其加载到mySQL数据库中,则LOAD DATA LOCAL INFILE是您最好的朋友:http : //dev.mysql.com/doc/refman/5.1/ zh / load-data.html。Mysqlimport也值得研究,它是一个命令行工具,基本上是一个很好的包装加载数据infile的工具。


3

已经说了很多事情,但是我觉得我可以添加一件事:年轻的开发人员通常会担心性能过高,而且您有关联接表的问题似乎也朝这个方向发展。这是一种称为“ 过早优化 ” 的软件开发反模式。试着消除你脑海中的反射:)

还有一件事:您是否真的需要“城市”和“国家”表?在Departments表中是否没有“ city”和“ country”列足以满足您的用例?例如,您的应用程序需要按城市列出按城市列出的部门吗?


1
我可能会尝试,它一直在计算helloworld.c的大O,并进行优化当我遵循获取3NF数据库的步骤时,Cities和Countrys表只是产生了它们自己。我想他们提供的优势是城市/国家/地区名称的连贯性。就像我们在慕尼黑获得客户一样,由于某种原因,任何将新学生加入日程安排系统的人都决定将其称为慕尼黑,而不是像以前的学生那样称呼慕尼黑。另外,我们可能需要按城市列出部门,我必须检查一下。谢谢。
bob esponja '02

2
在数据库的设计阶段进行优化至关重要!这不是过早的优化,因为当数据库拥有数百万条记录时,很难重新进行数据库的重新设计。
HLGEM

1
我没有说他不应该对自己的设计进行压力测试:)
Hans Westerbeek 2010年

3

根据作为商务智能/报告专家和战略/计划经理的角色发表以下评论:

  1. 我同意拉里的上述指示。恕我直言,这不是工程过度,有些事情看起来有点不合适。为简单起见,我将客户直接标记到公司ID,部门描述,部门描述,部门类型ID,部门类型ID。使用部门类型ID和部门类型ID作为对查询表和内部报告/分析字段的引用,以实现长期一致性。

  2. Packs表包含“ Credit”列,这实际上是否不应该绑定到Client基本表,所以如果它们有很多Pack,您可以看到还剩下多少贷项用于以后的课程?该应用程序可以处理calc并将其集中存储在Client表中。

  3. 公司信息可以使用更多字段,包括明显的地址/电话/等。信息。我还准备长期添加D&B“ DUN”列(“站点/分支/最终”),Dun and Bradstreet(D&B)拥有大量公司目录,以后您会发现他们的信息非常有帮助用于报告/分析。这将解决您提到的多部门问题,并允许您汇总其针对sub / division / branchs / etc的层次结构。大军团。

  4. 您没有提到要使用多少条记录,这可能意味着您需要为大型开发计划做好准备,而使用预先打包的“报告”软件可以更快,更轻松地完成工作。如果您不处理大型数据库(<65000)行,请确保MS-Access,OpenOffice(基础)或相关的报表/应用程序开发解决方案无法解决问题。我本人使用甲骨文的免费APEX软件很多,它带有免费的数据库Oracle XE,只需从其站点下载即可。

  5. 仅供参考-报告洞察力:对于大型数据库,通常有两个数据库实例a)交易数据库,用于记录每个详细记录。b)报告数据库(数据集市/数据仓库)位于单独的计算机上。有关更多信息,请搜索google Star Schema和Snowflake Schema。

问候。


1.您是说将所有这些列添加到客户表中吗?我认为这会破坏规范化,也难以保持一致,但我不确定我是否正确理解。2.数据包是连续的,只有最新的数据包才有未偿信用额,因此无需跟踪多个数据包。在这种情况下,您仍然建议将其存储在客户端表中吗?3.弄清楚客户公司的结构似乎将非常有帮助,谢谢。
bob esponja 2010年

4.我必须检查明年我们期望的客户和会话数,但是对于我来说,会话​​表在一年左右的时间内到达这么多行似乎是可行的。我将研究报告软件,这并不是我想到的。5.看来这是我偶然到达的情况;该Web应用程序将成为我们的“交易数据库”,而该项目就是我们的“仓库数据库” :)谢谢您的输入。
bob esponja

1.是,在客户表中添加“公司ID,部门描述,部门描述,部门类型ID,部门类型ID”列。客户属于一家公司,公司内的部门类型不同(IT / Ops / Admin / etc。),部门类型也不同(销售/人力资源/营销业务类别)。2.我只是认为Credit与客户或公司相关,而不与会话包相关。这是您可以做出的商业决定。
威尔

拉里还提到将公司和国家合并。我完全同意并回到有关D&B参考的观点。我会使用SiteID或唯一的名称来允许同一公司的多个位置,然后将部门链接到唯一的SiteID之一。
威尔

2

我只想解决以下问题:连接到多个表会导致性能下降。不要害怕标准化,因为您必须进行联接。在关系数据库中,联接是正常且期望的,并且它们设计用于处理它们。您将需要设置PK / FK关系(为了确保数据完整性,这在设计时必须考虑),但是在许多数据库中,FK不会自动建立索引。由于将在连接中使用它们,因此您一定要从索引FKS开始。PK通常必须具有创建索引,因为它们必须唯一。数据仓库的设计确实减少了联接的数量,但通常只有到一个报表中有数百万条记录需要访问时,才能达到数据仓库的目的。即便如此,几乎所有数据仓库都从事务数据库开始,以实时收集数据,然后按计划(每晚或每月或任何业务需求)将数据移至仓库。因此,即使您以后需要设计数据仓库来提高报告性能,这也是一个好的开始。

我必须说,您的设计对于CS一年级学生来说是令人印象深刻的。


1

它并没有过度设计,这就是我要解决的问题。联接很好,不会对性能造成太大影响(除非您不建议对数据库进行非规范化,否则这是完全必要的!)。对于状态,请查看是否可以使用枚举数据类型来优化该表。


枚举是邪恶的。每次您需要扩展枚举时,都必须重建表-可以这样做,直到表的大小变为GB。
马丁2010年

感谢克里斯的意见和建议,我担心自己会创建一个过于复杂的怪物。马丁,状态非常明确且静态:基本上是0级,取消了1级,没有打开2级。我认为这三个涵盖了班级的任何可能结果。在这种情况下使用枚举仍然不是一个好主意吗?
bob esponja

在我看来,这对于枚举似乎是完美的。提前满足所有可能的结果。int也可以用应用程序中的枚举或静态int表示。并不重要:)如果使用某种工具编辑数据库,枚举会更好看。
克里斯·丹尼特

当您的大型表格必须全天候(24x7)在线运行并且需要更改枚举时,枚举可能会出现问题(也许邪恶太强了)。鉴于您是从头开始填充表格-不必担心。给定足够小的数据集,您不妨只使用字符串。
马丁

1

我曾在培训/学校领域工作,我想指出的是,您所谓的“课程”(给定课程的实例)与课程本身之间通常存在M:1的关系。换句话说,您的目录提供了该课程(“西班牙语101”或其他课程),但是您可能在一个学期中有两个不同的实例(史密斯教授Tu-Th,琼斯教授Wed-Fri)。

除此之外,这似乎是一个好的开始。我敢打赌,您会发现客户端域(导致“客户端”的图形)比您建模的更为复杂,但是在您掌握了一些实际数据之前,请不要过分考虑。


如果我正确地理解了您的话,事实并非如此。“课程”只是后续课程的组。这不是传统的基于学期的系统。我想不出可以添加到客户端域中的任何其他内容,您有任何示例吗?同样,我担心我已经因为复杂性而大吃一惊,但事实并非如此:)感谢您的投入。
bob esponja '02

0

我想到了几件事:

  1. 这些表似乎适合于报告,但并不是真正开展业务。我认为,当客户签约时,本质上是为该客户参加会议列表下了订单,并且该订单可能是针对一家公司中的多个员工的。似乎“订单”表确实位于系统的中心,并推动数据捕获和最终报告。(将您用于运营业务的纸质文档与数据库设计进行比较,以查看是否存在逻辑匹配。)

  2. 公司通常没有部门。员工有时会更改部门/部门,甚至可能在会议中期。公司有时会添加/删除/重命名部门/部门。确保表中可能的实时更改内容不会使后续报告/分组变得困难。由于将如此大量的联系数据分散在许多表格中,您可能必须执行非常严格的数据输入验证,以使报告有意义且包容。例如,当添加新客户时,请确保其公司/部门/部门/城市与他的同事匹配相同的值。

  3. “包装”的概念还不清楚。

  4. 由于您指出这是一家小企业,因此考虑到当前计算机的速度和容量,如果性能成为问题,这将令人惊讶。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.