首次数据库设计:我是否过度工程?

时间:2010-02-23 18:18:07

标签: mysql database database-design schema database-normalization

背景

我是第一年的CS学生,我兼职为我父亲的小生意做准备。我没有任何实际应用程序开发经验。我用Python编写过脚本,用C编写一些课程,但是没有这样的。

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

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

我们可能很快就会开始拥有国际客户,所以我希望数据库在发生这种情况时不会爆炸。我们目前还有几家大公司作为客户,有不同的部门(例如ACME母公司,ACME医疗保健部门,ACME身体护理部门)

我提出的架构如下:

  1. 从客户的角度来看:
    • 客户是主要的表格
    • 客户与他们所工作的部门相关联
      • 各个部门可以分散在一个国家:伦敦的人力资源部门,斯旺西的市场营销部门等。
      • 部门与公司的分部相关联
    • 分部与母公司
    • 相关联
  2. 从课程角度来看:
    • 会话是主要表格
      • 教师与每个会话相关联
      • 每个会话都有一个statusid。例如。 0 - 已完成,1 - 已取消
      • 会话被分组为任意大小的“包”
    • 每个包都分配给客户
  3. 我在一张纸上“设计”(更像是潦草书写)模式,试图将其标准化为第三种形式。然后我将它插入到MySQL Workbench中,这对我来说非常适合:
    Click here for full-sized graphic

    alt text http://maian.org/img/schema.png

    我将运行的示例查询

    • 哪些有信用额度的客户仍处于闲置状态(未来未安排课程的客户)
    • 每个客户/部门/部门的出勤率是多少(以每个会话中的状态ID衡量)
    • 一个老师一个月有多少课
    • 标记出勤率低的客户
    • 人力资源部门的自定义报告,包括其所在部门人员的出勤率

    问题(S)

    • 这是过度工程还是我走对了路?
    • 对于大多数查询,是否需要连接多个表会导致性能大幅下降?
    • 我在客户端添加了“lastsession”列,因为它可能是一个常见的查询。这是一个好主意还是我应该严格规范化数据库?

    感谢您的时间

11 个答案:

答案 0 :(得分:41)

您的问题还有一些答案:

1)对于第一次接近这样的问题的人来说,你几乎已成为目标。我认为到目前为止,其他人对这个问题的指示几乎涵盖了它。干得好!

2& 3)您将采取的性能影响很大程度上取决于为您的特定查询/过程拥有和优化正确的索引,更重要的是依赖于记录量。除非您在主表中谈论超过一百万条记录,否则您似乎有望采用足够主流的设计,在合理的硬件上性能不会成为问题。

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

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

所有这些都是一个冗长的咆哮,以说明你所使用的设计原则和技巧可能因你正在创建的数据库的作用而有所不同。我希望这很有帮助。

答案 1 :(得分:14)

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

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

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

答案 2 :(得分:6)

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

2-如果可能,将你的int id更改为GUID(uniqueidentifier)(这可能只是我个人的偏好)。假设您最终到达了多个环境(dev / test / staging / prod),您可能希望将数据从一个环境迁移到另一个环境。让GUID ID变得更加容易。

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

4-客户端表中的状态也是VARCHAR,并且没有指向Statuses表的链接。关于客户状态代表什么,我希望更清楚一点。

答案 3 :(得分:6)

没有。看起来你的设计水平很高。

我认为国家和公司在您的设计中实际上是同一个实体,城市和部门也是如此。我将摆脱Countries和Cities表(以及Cities_Has_Departments),并在必要时将一个布尔标志IsPublicSector添加到Companies表(如果有更多选择而不仅仅是私有部门/公共部门,则添加一个CompanyType列。)

另外,我认为您使用Departments表时出错。看起来Departments表可以作为每个客户部门可以拥有的各种部门的参考。如果是这样,它应该被称为DepartmentTypes。但是您的客户(我认为是参加者)不属于部门类型,他们属于公司的实际部门实例。按照现在的情况,你会知道某个客户属于某个人力资源部门,但不属于哪个部门!

换句话说,客户端应该链接到您调用Divisions_Has_Departments的表(但我会简称为Departments)。如果是这样,那么如果要在数据库中使用标准参照完整性,则必须按照上面的讨论将City折叠为Divisions。

答案 4 :(得分:5)

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

答案 5 :(得分:3)

大多数事情都已经说过,但我觉得我可以添加一件事:年轻的开发人员在前期担心性能有点过于常见,而且关于加入表格的问题似乎进入了那个方向。这是一个名为“Premature Optimization”的软件开发反模式。试着消除你的反思:)

还有一件事:你认为你真的需要“城市”和“国家”牌桌吗?部门表中的“城市”和“国家/地区”列是否足以满足您的使用案例?例如。您的申请是否需要按国家/地区按城市列出部门?

答案 6 :(得分:3)

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

  1. 我同意拉里的上述指示。恕我直言,它并没有过多的设计,有些东西看起来有点不合适。为了简单起见,我会将客户端直接标记为公司ID,部门描述,部门描述,部门类型ID,部门类型ID。使用部门类型ID和部门类型ID作为查询表和内部报告/分析字段的参考,以实现长期一致性。

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

  3. 公司信息可以使用更多字段,包括明显的地址/电话/等。信息。我也准备长期添加D& B“DUN”专栏(网站/分支/旗舰版),Dun和Bradstreet(D& B)有一个庞大的公司目录,你会发现他们的未来信息对报告/分析非常有帮助。这将处理您提到的多分区问题,并允许您汇总其子/分区/分支/等的层次结构。大军团。

  4. 您没有提到您将使用多少记录,这可能意味着为一项大型开发计划做好准备,这项计划本可以通过预先打包的“报告”软件更快地完成,而且更少令人头疼。如果您不处理大型数据库(< 65000)行,请确保MS-Access,OpenOffice(Base)或相关的报表/应用程序开发解决方案无法解决问题。我自己使用Oracle的免费APEX软件,它附带了他们的免费数据库Oracle XE,只需从他们的网站上下载。

  5. FYI - 报告洞察:对于大型数据库,您通常有两个数据库实例a)用于记录每个详细记录的事务数据库。 b)报告位于单独机器上的数据库(数据集市/数据仓库)。有关更多信息,请搜索Google Star Schema和Snowflake Schema。

  6. 问候。

答案 7 :(得分:2)

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

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

答案 8 :(得分:1)

它没有过度设计,这就是我如何处理这个问题。加入很好,不会有太大的性能损失(除非你不推荐将数据库标准化,否则这是完全必要的!)。对于状态,请查看是否可以使用枚举数据类型来优化该表。

答案 9 :(得分:1)

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

除此之外,它看起来是一个好的开始。我打赌你会发现客户端域(通向“客户端”的图形)比你建模的更复杂,但是在你有一些真实的数据来指导你之前不要过分。

答案 10 :(得分:0)

有些事情浮现在脑海中:

  1. 这些表格似乎适合报道,但并未真正开展业务。我想当客户报名时,基本上会为客户出席会议列表的订单,该订单可能是针对一家公司的多名员工。这似乎是一个“订单”表,它真的会成为您系统的核心,并推动您的数据捕获和最终报告。 (将您用于运行业务的纸质文档与数据库设计进行比较,看看是否存在逻辑匹配。)

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

  3. “包”概念根本不清楚。

  4. 由于您表示这是一项小型企业,考虑到当前机器的速度和容量,如果性能成为问题,那将会令人惊讶。