2009-09-04 56 views
2

我需要通过例子来说明这一点:数据库设计偏好:使用DateTime和SQL中的BIT 2000

是否有一个最佳做法或偏好数据库中的表指定DateTime和BIT?

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

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

(实施例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是清洁器因为这是一个不必担心的专栏。但是,无论何时我需要评估一个Widget是否已关闭,我都需要额外的一步来确定ClosedDate列是否为NULL。

示例2会产生额外开销,因为现在我必须保持IsClosed和ClosedDate值同步。

在设计这样的东西时,是否有最佳实践? 查询表格对于例子2来说性能更高吗?我有什么理由选择另一种设计吗?

注意:我将通过ORM工具以及存储过程访问此值。

+0

使“IsClosed”成为计算列,只有当ClosedDate不为空时才为true - 请参阅JBrooks的答案 - 为您提供两种方案中最好的方法! – 2009-09-04 05:08:13

回答

5

我认为选项1更好。数据完整性得到了更好的保留(不可能有一个封闭的日期与一个标志说反过来),在超大型表的情况下占用较少的磁盘空间,查询仍然是高性能和明确的,以帮助队友理解。

2

第一个比较好。检查空值是便宜的,而保留一个单独的标志可以有一个封闭的日期,但没有关闭。

0

我不会将NULL的语义含义。通过你的业务逻辑和这样做会泡你会得到这样的代码......

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 
} 

在方式使用空是坏的。 NULL(和null)表示“我不知道”。在实际中,你正在为该答案分配语义含义,你不应该这样做。关闭状态是关闭状态,关闭日期是关闭日期,不要组合它们。 (上帝禁止你曾经想重新打开一个Widget,但是仍然记得当它在第一时间关闭时)。

Eric Lippert有一个nice blog post关于以这种方式使用null(kidna)也是如此。

+0

在C#中,你会使用DateTime吗? (可为空值)来对应数据库字段,所以这就是你在这个return语句中要做的。我不能说我同意你的建议,因为它违背了DRY。 – 2009-09-04 01:33:27

+2

我刚刚阅读Lippert的文章,并没有看到它如何支持你的观点。 Null表示不存在任何值,这与任何现有值都不同,包括空值。在这种情况下,空关闭日期意味着不存在关闭日期,因为它没有关闭。如果您想重新打开并记录之前的关闭日期,我建议您将其放入历史记录表中。 – 2009-09-04 01:37:08

+0

我也不同意。在你的例子中,你会简单地返回_closeDate.HasValue()(在C#中) – Shawson 2017-07-25 13:15:41

2

我认为你有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) 
) 

的原因是你没有任何存储,现在你可以把你的应用程序代码和存储的特效使用此列。如果您的业务规则发生变化,您可以将其转换为真实的列,并且不需要更改其他代码。否则,您将在业务逻辑中散布整个应用程序代码和存储特效。这样,它只在1个地方。

最后,当您移动到SQL2005时,您可以添加“Persisted”子句。因此,它将被存储以提高性能,并且保持它们不会同步。

+0

+1完美 - 我的想法确切!您正在使用的一列,以及一个计算列(它会自动更新)来表示状态。 – 2009-09-04 05:07:37

+0

这是一个有趣的妥协。首先,即使没有持久化,您也可以在其上创建一个索引,从而有效地保留索引。另一方面,我非常适合使用null来表示空值。 – 2009-09-04 11:41:06