代码之家  ›  专栏  ›  技术社区  ›  DeveloperDan Asaf

淹没在茫茫人海中

  •  8
  • DeveloperDan Asaf  · 技术社区  · 15 年前

    我继承的一个应用程序跟踪对材料样本执行的实验室测试结果。数据存储在一个表(tblSampleData)中,主键为SampleID,235列表示潜在的测试结果。问题是每个样本只执行几个测试,因此每行包含200多个空值。实际上,还有第二个类似的表(tblSampleData2),它还有215个主要为空的列和SampleID的主键。这两个表有一对一的关系,大多数样本ID在这两个表中都有一些数据。

    这是一个糟糕的数据库设计吗?如果是这样的话,哪条范式规则被打破了?如何查询此表以确定哪些列组通常与数据一起填充?我的目标是,假设45个表有10列,空值更少。我该怎么做?如何避免破坏现有应用程序?

    到目前为止,这些表格有大约20万条样本记录。用户要求我为更多的测试添加更多的列,但我宁愿构建一个新表。这明智吗?

    10 回复  |  直到 15 年前
        1
  •  1
  •   Kenny Evitt    15 年前

    我不确定设计是否真的那么糟糕。空值的存储成本应该相对较低。在SQLServer中,每行都有一个内部位字段(或多个字段),用于指示哪些列值为空。

    如果应用程序的性能不需要改进,并且由于更改表模式而进行重构的成本效益也不是正面的,那么为什么要更改它呢?

        2
  •  9
  •   DCNYAM    15 年前

    根据我从您对数据库的描述中收集到的信息,更好的设计可能如下所示:

    包含始终与样本关联的字段的样本表。例如,

    Sample
    ------ 
    SampleID 
    SampleDate 
    SampleSource
    

    然后,一个测试类型表,其中可以执行的每种类型的测试都有一个条目。

    TestType
    --------
    TestTypeID
    TestName
    MaximumAllowedValue
    

    最后,创建一个中间表,该表表示上述两个表之间的多对多关系,并保存测试结果。

    TestResult
    ----------
    SampleID
    TestTypeID
    TestResult
    

    这将消除空值,因为TestResult表只包含对每个样本实际执行的测试的条目。我曾经设计过一个数据库,目的和我相信你正在做的几乎一样,这就是我采取的方法。

        3
  •  4
  •   Community CDub    5 年前

    Entity Attribute Value model (EAV)。关于何时适合使用EAV的描述非常符合您的用例:

    这种数据表示类似于存储稀疏矩阵的节省空间的方法,其中只存储非空值。

    生产数据库中EAV建模的一个例子是可以应用于患者的临床发现(既往病史、当前主诉、体检、实验室测试、特殊调查、诊断)。在所有的医学专业中,这些测试可以达到数十万(每个月都会有新的测试)。然而,大多数去看医生的人的发现相对较少。

    在您的特定情况下:

    • 实体是一个材料样本。
    • 该值是特定样本的测试结果。

    EAV有一些严重的缺点,并且产生了许多困难,所以它应该只在合适的时候应用。如果需要在一行中返回特定样本的所有测试结果,则不应使用它。

    在不破坏现有应用程序的情况下,很难修改数据库以使用此结构。

        4
  •  1
  •   Nathan Hughes    15 年前

    仅仅因为没有破坏任何正规形式的规则并不意味着它不是糟糕的数据库设计。通常情况下,最好采用较小行的设计,因为这样可以在一个页面中容纳更多行,从而减少数据库的工作量。在当前的设计中,数据库服务器必须占用大量空间来保存空值。

    避免破坏现有的应用程序是困难的部分,如果其他应用程序只需要读访问权限,您可以编写一个看起来与旧表相同的视图。

        5
  •  1
  •   Jonathan    15 年前

    如果您确实更改了表结构,我建议使用一个名为tblSampleData的视图,该视图返回与表现在相同的数据。这样可以保持一些兼容性。

        6
  •  1
  •   John    15 年前
    1. . 将数据存储在结构化二进制文件或DBM/ISAM表中。

    2. 在这种情况下,缺乏标准化并不是世界末日,因为这些数据是“只读的” ,只有一个键,它和其他任何东西都没有关系。所以不应该担心更新异常。你只需要担心原始数据是一致的。

    3. 那些空值没有什么大不了的 如果在整个应用程序中将空值视为具有相同含义的“特殊值”。 定义 没有理由 意思大错特错。

    4. 我说让它正常化。要么定义特殊值,要么创建一个大型表。或者,为VB和PHP程序员保留空值,并正确地分割数据。如果需要支持遗留代码,请创建一个视图来连接备份的数据。从你描述的情况来看,你说的是要花几个小时的时间来纠正这件事。这不是什么坏事。

        7
  •  0
  •   iDevlop    15 年前

    假设你有40个测量通道的测试机X。如果您知道在每个测试中测试人员只使用几个通道,您可以将设计更改为:

    测试:testId,testDate

    您可以使用交叉表随时检索上一个布局。

        8
  •  0
  •   KM.    15 年前

    我将使用1个主表,其中每个示例有1行,它将包含每个示例应有的所有列:

    Sample
    -------
    SampleID  int auto increment PK
    SampleComment
    SampleDate
    SampleOrigin
    ....
    

    然后,我将为每个不同的测试或类似测试的“类”添加一个表,并包括与这些测试相关的所有列(使用实际的测试名称,而不是XYZ):

    TestMethod_XYZ
    ---------------
    SampleID    int FK Sample.SampleID
    MeltTemp
    BurnTemp
    TestPersonID
    DateTested
    ...
    
    TestMethod_ABC
    ---------------
    SampleID    int FK Sample.SampleID
    MinImpactForce
    TestPersonID
    DateTested
    ....
    
    TestMethod_MNO
    ---------------
    SampleID    int FK Sample.SampleID
    ReactionYN
    TimeToReact
    ReactionType
    TestPersonID
    DateTested
    ...
    

        9
  •  0
  •   Alix Axel    15 年前

    EAV是一个选项,但是查询会杀死你。

    是否可以选择将数据迁移到像MongoDB这样的NoSQL数据库?我相信这将是解决你问题的最有效和最简单的方法。既然你提到你基本上是在做CRUD查询,NoSQL应该相当有效。

        10
  •  0
  •   Larry Lustig    15 年前

    结构 而不是简单地添加一些 多个“定义”测试的表。更糟糕的是,它需要对现有表进行结构更改,而不是添加新表。

    1. 尝试发现代表任何单个测试所需的最大测量数。如果测试返回的数据类型不同,则需要找出最大测试返回的每个数据类型的最大值。创建一个仅包含这些列的表,标记为Meas1、Meas2等,而不是400列,可能需要10.或40.然后创建一组表,描述每列对每个测试的“意义”。根据存储的测试类型,此信息可用于提供有意义的提示和报告列标题。这不会完全消除空值,但会大大减少空值,并且只要任何新测试可以“适合”到指定的度量值中,新测试就可以作为数据而不是结构更改添加。

    2. 找出每个测试的实际度量列表,并创建一个单独的表来保存每个测试的结果(基本信息,如测试ID、运行者、时间等仍然放在一个表中)。这是一个多表继承模式(我不知道它是否有真实的名称)。您仍然需要为每个新的测试创建一个新的“数据”表,但是现在您将不会接触其他现有的生产表,您将能够实现完美的标准形式。

    我希望这能提供一些开始的想法。

    推荐文章