【问题标题】:Negative integer indexes: are they evil?负整数索引:它们是邪恶的吗?
【发布时间】:2011-01-04 17:53:19
【问题描述】:

我正在设计这个数据库。

它需要包含几十个表,其中包含我们提供的记录(一堆默认值)以及用户可以添加的记录。为了不让用户中弹,有必要不让他修改默认记录。

有很多方法可以促进这一点,但我喜欢为受保护记录提供负整数索引,同时保留 0 作为无效记录 ID 并为用户记录提供正整数索引的想法。

CREATE TABLE t1 (
    ixt1  integer AUTOINCREMENT,
    d1    double,
    CONSTRAINT pk_ixt1 PRIMARY KEY (ixt1),
    CONSTRAINT ch_zero CHECK (ixt1 <> 0)
);

-2 | 171.3 <- canned record
-1 | 100.0 <- canned record
 1 | 666.6 <- user record

这看起来不错的原因:

  • 它不会占用更多空间

  • 很容易理解

  • 它不需要很多额外的表来实现

  • “select * from table”获取所有相关记录,无需额外间接

  • 罐头记录可以负向增长,用户记录可以正向增长

但是,我对数据库设计还比较陌生。在使用这个解决方案一段时间后,我开始担心使用负索引可能不好,因为

  • 不同 DBMS 之间可能无法一致支持负索引,因此难以编写与数据库无关的代码

  • 在 recid 0 处插入一些东西可能太容易搞砸了

  • 这可能会导致难以使用期望具有非负值的整数索引的工具(可能像 db 网格)。

也许还有其他一些非常明显的原因会使这成为一个非常糟糕的主意。

那么最终的答案是什么?负整数索引是邪恶的吗?

【问题讨论】:

  • 我注意到您的主键上有AUTOINCREMENT,这最终如何与您的策略配合使用?您是手动计算所有新记录的正确主键还是只计算私有(负)记录?
  • 只有私有(负)密钥会被显式设置。顺便说一句,我不知道这种特殊的 SQL 语法适用于任何 DBMS。这只是为了说明。

标签: sql database-design indexing


【解决方案1】:

我在一个非常大的计费系统上工作。我们有一个非常相似的问题......需要将一些记录标记为“特殊”。客户的数据库中有数千万行受影响表的现有数据,将所有这些数据迁移到新结构(即添加一列)被认为是不可接受的。

决定完全按照您的建议行事。

这样做的问题是,您需要所有业务逻辑都了解(并记住)负索引的特殊含义并正确处理它。这很容易出错(根据经验)。

除非你有非常强烈的支持这种非传统方法的特殊情况,否则我建议你坚持使用更传统的额外专栏。这是大多数开发人员习惯的,因此不太可能导致错误。我希望我们能咬紧牙关并添加额外的列。

【讨论】:

  • +1 表示“所有业务逻辑都必须知道特殊含义”。
  • 我非常感谢这是来自经验。但在我看来,就难度而言,添加一个额外的列是等效的。如果您添加了一个额外的列而不是使用负索引,您的代码会有什么不同?
  • 我认为最大的问题是开发人员(无论是现在,还是在 5 年内保持这一点的人)希望将特殊含义建模为列而不是应用特殊含义解释索引的数值。其他人也指出,如果将来需要额外的“特殊”含义,则无法扩展此设计,因此人们必须检查索引的符号并检查列是否有任何新状态。
  • 所以使用这种方法会降低软件的可维护性。我也赞同这个论点,特别是因为你不得不处理替代方案。
【解决方案2】:

其中最重要的缺陷是“智能钥匙”问题。

负整数可以很好地作为键。在所有数据库中。

没有工具需要正整数索引值。

这个比较容易搞砸,因为索引有一个“规则”,它并不明显,在你中了彩票并离开后没人会记得。

此外,当您发明第三个状态代码(“预罐头”与“客户特定罐头”与“产品线发明的其他罐头”与“版本 3 之前的旧罐头”)时,您'注定了。

“智能钥匙”的问题在于您要求钥匙完成两项不相关的工作。

  1. 它是记录的唯一标识符。这就是钥匙应该是的。

  2. 您还要求它提供状态、控制和授权以更改属性。哎呀。这充满了危险。您无法扩展含义,因为它只是埋在键中。

只需添加一个带有“拥有者”的列。如果它由“神奇的超级用户”拥有,则不会向用户显示。如果您不相信您的应用程序开发人员会执行此操作,请使用 VIEW 来确保这一点。

如果它由“神奇的超级用户”拥有,那么它就是默认数据,并且适用于该所有权的任何规则。

【讨论】:

  • +1 用于使密钥执行两项工作。钥匙就是钥匙,这就是它所需要的一切。通过添加其他列使行变得特别。
  • 坏主意。负整数索引并不邪恶,但您的设计并不明显。 “容易理解”,可能。但是从架构中可以立即看出,不。最好有一个名为 is_canned 或 is_protected 的布尔/位列。
  • 任何在数据库中声明为“布尔”的东西都会变成多个值。布尔值永远不应该被视为一个持久的、描述性的属性;这是一个基于属性的条件,而不是一等属性。
  • 所以这里的基本论点是让密钥做两件事是一个坏主意,既因为它不可扩展,又因为它出乎意料。我买那个;这就是为什么我要尝试使用整数键而不是 UUID。但是,放弃并在那个额外的专栏上沮丧确实让我有点难过。使用负键和正键非常简洁,并且可以很好地细分表格。似乎它应该是 /something/ 的优雅解决方案。 =)
  • "简洁" == 代码味道。当实现隐藏在另一个对象的值中时,要非常小心简洁。当您是 Don Knuth 编写可以被证明是最小的算法时,这没关系。但是对于您的问题(约束不充分),您无法证明这种“罐头”/“用户”二分法是问题的持久特征。
【解决方案3】:

这是您的数据,但我认为这不是一个好主意。像这样的“索引”值应该是没有意义的——不要使用符号或数字范围或其他任何东西来表示“某事”或“其他事”。我认为从长远来看,最好有一个“记录类型”列,清楚地表明你正在查看什么样的记录。根据我的经验,这是一种更好的方法。

祝你好运。

【讨论】:

    猜你喜欢
    • 2012-01-23
    • 2011-01-02
    • 1970-01-01
    • 2011-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多