代码之家  ›  专栏  ›  技术社区  ›  Jon

数据库设计首选项:在SQL 2000中使用日期时间和位

  •  2
  • Jon  · 技术社区  · 15 年前

    我需要举例说明:

    在数据库表中指定日期时间和位是否有最佳实践或首选项?

    在我的数据库中有一个小部件表。我需要知道一个小部件是否“关闭”,它的“关闭日期”业务规则说,如果一个小部件关闭,它必须有一个关闭日期。如果一个小部件没有关闭,它不应该有一个“关闭日期”。

    为了设计这个,我可以执行以下操作:

    (例1):

    CREATE TABLE [Widget]
    (
        [WidgetID] INT IDENTITY(1,1)
        ,[ClosedDate] DATETIME NULL
    )
    

    或(例2):

    CREATE TABLE [Widget]
    (
        [WidgetID] INT IDENTITY(1,1)
        ,[IsClosed] BIT NOT NULL CONSTRAINT [DF_Widget_IsClosed] DEFAULT (0)
        ,[ClosedDate] DATETIME NULL
    )
    

    我认为示例1更干净,因为它少了一个需要担心的列。但是,每当我需要评估一个小部件是否关闭时,我都需要额外的步骤来确定closeddate列是否不是空的。

    示例2产生了额外的开销,因为现在我必须保持isclosed和closeddate值同步。

    设计这样的东西有没有最佳实践? 例如2,查询表是否更具性能?我为什么要选择一种设计而不是另一种?

    注意:我将通过ORM工具和存储过程访问这个值。

    4 回复  |  直到 15 年前
        1
  •  5
  •   MaxiWheat    15 年前

    我认为选项1更好。数据完整性得到了更好的保持(不可能有一个带有相反标志的结束日期),在超大表的情况下,占用的磁盘空间更少,而且查询仍然可以执行,并且对于团队成员来说是清晰易懂的。

        2
  •  2
  •   Steven Sudit    15 年前

    第一个更好。检查空值很便宜,但是保留一个单独的标志可以使关闭日期尚未关闭。

        3
  •  2
  •   JBrooks    15 年前

    我认为isclosed列是一个计算列。

    CREATE TABLE [Widget](    
    [WidgetID] INT IDENTITY(1,1),
    [ClosedDate] DATETIME NULL,
    IsClosed AS CAST(CASE WHEN ClosedDate IS NULL THEN 0 ELSE 1 END AS BIT)
    )
    

    原因是您没有存储任何内容,现在可以对应用程序代码和存储的进程进行编码以使用此列。如果您的业务规则发生更改,您可以将其转换为实列,而无需更改其他代码。否则,您将在整个应用程序代码和存储过程中散布业务逻辑。这样,它只在一个地方。

    最后,当您移动到sql2005时,可以添加“persisted”子句。因此,它将被存储,稍微提高性能,并且您将不会遇到保持它们同步的问题。

        4
  •  0
  •   JP Alioto    15 年前

    我不会将语义指定为空。这样做将使您的业务逻辑冒泡,您将得到类似于…

    public class Widget
    {
      // stuff
    
      public bool IsClosed
      {
        // what do you put here?
        // it was null in the db so you have to use DateTime.MinDate or some such.
        return( _closeDate == ?? );  
      }
    
      // more stuff
    }
    

    以这种方式使用空值是不好的。空的意思是“我不知道”。你在给那个答案赋予语义意义,而实际上你不应该这样做。关闭状态是关闭状态,关闭日期是关闭日期,不要合并。(例如,上帝禁止你想重新打开一个小部件,但仍然记得它最初关闭的时候。)

    埃里克·利珀特 nice blog post 也可以用这种方式使用空值(kidna)。