第一次设计数据库:我是否过度设计了?

背景

我是计算机科学一年级的学生,我在我爸爸的小公司兼职。我没有任何实际应用程序开发的经验。我用Python写过脚本,用C写过一些课程,但没有像这样的。

我爸爸有一家小型培训公司,目前所有的课程都是通过外部网络应用程序安排、录制和跟踪的。有一个导出/“报告”功能,但它是非常通用的,我们需要特定的报告。我们无法访问实际的数据库来运行查询。我被要求建立一个自定义报告系统。

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

我们可能很快就会有国际客户,所以我希望数据库不会爆炸,如果/当这种情况发生时。我们目前也有一些大公司作为客户,他们有不同的部门(例如ACME母公司、ACME医疗保健部门、ACME身体护理部门)。

我想到的模式如下:

  1. 从客户端角度:
    • Clients是主表
    • 客户端与所在部门链接
      • 部门可以分散在全国各地:人力资源部在伦敦,市场部在斯旺西等。
      • 部门与公司的部门相关联
      • 李< / ul > < / >
      • 各部门与母公司有关联
      • 李< / ul > < / >
      • 从类的角度:
        • Sessions是主表
          • 每节课都有一位老师
          • 每个会话都有一个状态号。例如:0 -完成,1 -取消
          • 会话被分组为任意大小的“包”
          • 李< / ul > < / >
          • 每个包分配给一个客户端
          • 李< / ul > < / >

我在一张纸上“设计”(更像是乱写)模式,试图将其正常化到第三种形式。然后我把它插入MySQL工作台,它使它的一切都为我漂亮:
(点击这里查看全尺寸图片)

< p > alt text < br > (来源:maian.org) < /订阅>

我将运行的示例查询

  • 哪些仍有信用的客户是不活跃的(未来没有安排课程的客户)
  • 每个客户/部门/部门的出勤率是多少(以每次会议的状态id来衡量)
  • 一个老师一个月上几节课
  • 标记出勤率低的客户
  • 人力资源部门的自定义报告,包括其部门人员的出勤率

问题(s)

  • 这是设计过度还是我的方向正确?
  • 对于大多数查询,需要连接多个表是否会导致很大的性能损失?
  • 我给客户端添加了一个“lastsession”列,因为这可能是一个常见的查询。这是一个好主意,还是我应该保持数据库严格规范化?

谢谢你的宝贵时间

20876 次浏览

这不是过度设计,这是我处理问题的方式。加入很好,不会有太大的性能损失(这是完全必要的,除非你对数据库进行反规格化,这是不建议的!)对于状态,查看是否可以使用枚举数据类型来优化该表。

你说得对。但是,您可以清理它,并删除一些映射(有*)表。

你能做的就是在部门表中添加CityId和DivisionId。

除此之外,我觉得一切都很好……

我在培训/学校领域工作过,我想我要指出的是,在你所说的“会话”(给定课程的实例)和课程本身之间通常存在M:1的关系。换句话说,你的目录提供了这门课程(“西班牙语101”之类的),但你可能在一个学期中有两个不同的实例(Tu-Th由Smith教授,wed - friday由Jones教授)。

除此之外,这看起来是个不错的开始。我敢打赌,您会发现客户端域(指向“客户端”的图形)比您所建模的要复杂得多,但在获得一些实际数据来指导您之前,不要过于复杂。

我唯一要做的改变是:
1-把你的VARCHAR改成NVARCHAR,如果你想要国际化,你可能需要unicode。< / p >

2-如果可能的话,将int id改为GUIDs (uniqueidentifier)(这可能只是我的个人偏好)。假设您最终拥有多个环境(开发/测试/登台/prod),您可能希望将数据从一个环境迁移到另一个环境。使用GUID id可以大大简化这一点。

3-你公司的三层结构->部门->部门结构可能不够。现在,这可能是过度工程,但你可以推广这个层次结构,这样你就可以支持n层深度。这将使您的一些查询更加复杂,因此可能不值得这样做。此外,任何具有更多层的客户端都可以很容易地“填充”到这个模型中。

4-你在客户端表中也有一个状态,它是VARCHAR,没有到状态表的链接。我希望能更清楚地说明客户状态代表什么。

以下是关于你问题的更多答案:

1)对于第一次遇到这种问题的人来说,你说得很对。我认为到目前为止,其他人在这个问题上的建议几乎涵盖了这个问题。好工作!

2,3)性能的下降很大程度上取决于为特定的查询/过程设置和优化正确的索引,更重要的是记录的数量。除非您的主表中有超过一百万条记录,否则您似乎已经走上了一条足够主流的设计道路,在合理的硬件上,性能不会成为问题。

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

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

所有这些都是为了说明根据所创建的db的角色不同,所采用的设计原则和技巧可能会有所不同。我希望这对你们有帮助。

大多数事情都已经说过了,但我觉得我可以补充一点:年轻的开发人员在一开始就有点过多地担心性能,这是很常见的,而你关于连接表的问题似乎正朝着这个方向发展。这是一个名为“过早优化”的软件开发反模式。试着把这种反射从你的脑海中赶走:)

还有一件事:你真的需要“城市”和“国家”表吗?难道在部门表中有一个“城市”和“国家”列不足以满足您的用例吗?例如,您的应用程序需要按城市和城市按国家列出部门吗?

不。看起来你设计得很细致。

我认为在你的设计中,国家和公司实际上是同一个实体,城市和部门也是如此。我将去掉国家和城市表(以及Cities_Has_Departments),并在必要时向公司表添加一个布尔标志IsPublicSector(如果除了简单的Private Sector / PublicSector之外还有其他选择,则添加CompanyType列)。

另外,我认为您在使用部门表时出现了错误。看起来,Departments表可以作为每个客户部门可以拥有的各种部门的参考。如果是,它应该被称为DepartmentTypes。但是您的客户端(我假设是与会者)不属于部门类型,它们属于公司中的实际部门实例。就目前的情况而言,您将知道某个特定客户属于某个地方的人力资源部门,但不知道是哪个部门!

换句话说,客户机应该链接到您称为Divisions_Has_Departments的表(但是我将简单地称之为Departments)。如果是这样,那么如果您想在数据库中使用标准引用完整性,就必须将Cities分解为division,就像上面讨论的那样。

以下是基于商业智能/报告专家和战略/规划经理角色的评论:

  1. 我同意Larry上述的方向。恕我直言,这并不是设计过度,只是有些东西看起来有点不合适。为了保持简单,我将标记客户直接到公司ID,部门描述,部门描述,部门类型ID,部门类型ID。使用部门类型ID和部门类型ID作为查找表和内部报告/分析字段的引用,以实现长期一致性。

  2. 包表包含“信用”列,不应该实际上是绑定到客户基础表,所以如果他们许多包,你可以看到有多少欠的信用是留给未来的类?应用程序可以处理calc并将其集中存储在Client表中。

  3. 公司信息可以使用更多的字段,包括显而易见的地址/电话/等等。信息。我还准备在邓白氏(d&bradstreet)的“DUNs”专栏(站点/分支/最终)中添加长期的,邓白氏(d&bradstreet)有一个庞大的公司目录,你会发现他们的信息对报告/分析非常有帮助。这将解决你提到的多个部门的问题,并允许你为子/部门/分支等卷起他们的层次结构。大军团的。

  4. 你没有提到你将处理多少记录,这可能意味着你要进行一个大型的开发计划,如果使用预先打包的“报告”软件,这个计划可以更快地完成,也会少得多头疼。如果你不是在处理一个大型数据库(<65000)行,确保MS-Access, OpenOffice (Base)或相关的报告/应用程序开发解决方案不能做到这一点。我自己使用甲骨文的免费APEX软件相当多,它附带他们的免费数据库Oracle XE,只需从他们的网站下载即可。

  5. 供参考-报告洞察:对于大型数据库,您通常有两个数据库实例a)事务数据库用于记录每个详细记录。B)报告数据库(数据集市/数据仓库)放置在单独的机器上。欲了解更多信息,请搜索谷歌星型模式和雪花模式。

的问候。

我只想解决连接多个表会导致性能下降的问题。不要害怕规范化,因为你必须做连接。连接在关系数据库中是正常的和预期的,它们被设计为很好地处理它们。您将需要设置PK/FK关系(为了数据完整性,在设计时考虑这一点很重要),但在许多数据库中,FK不会自动建立索引。因为它们将在连接中使用,所以您肯定希望从索引FKS开始。pak通常在创建时获得索引,因为它们必须是唯一的。数据仓库设计确实减少了连接的数量,但通常只有在一个报告中需要访问数百万条记录时,才会达到数据仓库的目的。即使这样,几乎所有的数据仓库都从一个事务数据库开始实时收集数据,然后按照计划(每晚或每月或任何业务需要)将数据移动到仓库。因此,即使稍后需要设计数据仓库以提高报表性能,这也是一个良好的开端。

我不得不说你的设计对于一个计算机科学的大一学生来说是令人印象深刻的。

顺便说一句,值得注意的是,如果你已经在生成csv并想要将它们加载到mySQL数据库中,load DATA LOCAL INFILE是你最好的朋友:http://dev.mysql.com/doc/refman/5.1/en/load-data.html。Mysqlimport也值得一看,它是一个命令行工具,基本上是一个装载数据文件的漂亮包装器。

我想到了几件事:

  1. 这些桌子似乎是用来做报道的,而不是用来真正经营业务的。我认为,当客户签约时,本质上是为参加一系列会议的客户下了订单,该订单可能是为一家公司的多名员工下的。看起来“订单”表确实是您系统的中心,并驱动您的数据捕获和最终报告。(将您一直用于运营业务的纸质文档与数据库设计进行比较,看看是否有逻辑匹配。)

  2. 公司通常没有部门。员工有时会改变部门/部门,甚至可能是在会议期间。公司有时会增加/删除/重命名部门/部门。确保可能实时更改的表内容不会给后续的报告/分组带来困难。由于如此多的联系数据分布在如此多的表中,您可能必须强制执行非常严格的数据输入验证,以保持报告的意义和包容性。例如,当增加一个新客户时,确保他的公司/部门/部门/城市与他的同事有相同的价值观。

  3. “包”的概念一点也不清楚。

  4. 既然你说这是一家小公司,考虑到目前机器的速度和容量,如果性能成为一个问题,那将是令人惊讶的。