代理密钥是否应该向用户公开?


14

通常,在没有自然键的表中,对于用户来说,拥有唯一生成的标识符仍然很有用。如果表具有代理主键(在这种情况下,您一定会希望它具有),该键应该向用户公开还是应将另一个字段用于该目的?

不公开代理键的原因之一是,现在您不能执行保留记录之间关系的操作,而只能更改键值,例如某些类型的删除/重新插入,将数据从一个数据库复制到数据库的许多方法。另一个等等

公开代理键的主要优点是使用您拥有的字段非常简单。

在什么情况下最好直接向用户公开代理密钥?


这个问题的一部分是您需要定义“用户”。用户可能是您公开的API的使用者,也可能是肉肉的人类。两者的答案将不尽相同。
詹姆斯·斯内尔

1
肉质的人类。
psr

可以不同地标识数据的每种情况都应具有不同的标识符。因此,如果新系统与您的数据连接,则期望它具有自己的PK并将其添加到您的数据中。在这种情况下,可见“主要是水的丑陋袋子”是一个“系统”。我的首选解决方案是将实体的键和时间戳(添加,更改和删除)存储在特殊表中。这样,可以容易地分发数据。

Answers:


10

您需要为暴露给需要更改的用户/客户的任何标识符做好准备,并且更改数据库中行的标识并将更改传播到所有外键只是要求中断数据。

如果数据没有自然业务密钥,则可以为“业务标识符”添加一个附加字段。应该针对所使用的流程进行优化。电话键盘输入仅表示数字。通过电话/语音方式避免使用类似的发音符号(B / D,M / N等)。您甚至可以自动生成一些容易记忆的短语(“绿色果冻”)。

这样做的结果是,企业以后可以更改他们想要引用记录的方式,唯一的数据模式更改是为该ID类型添加新列或转换已经存在的ID。更改不会在整个数据库中传播,并且您仍然具有一个随时间有效的ID(代理)。

简而言之,我将避免向用户公开代理键。正如评论所指出的那样,代理密钥几乎应该永远不会改变。相反,企业希望改变一切。如果代理密钥被公开,则企业要更改它只是时间问题。

附带说明一下,当我在此处说“公开”时,是指将密钥提供给用户,希望他们直接使用它(例如致电要求提供其订单号)。


5
这个答案没有道理。代理键永远不会更改,并且您也没有理由不将其公开给用户。
罗伯特·哈维

1
永不说永不。如果后面的设计导致记录合并怎么办?如果您需要扩大身份并转换为身份,该怎么办?
DougM

3
@DougM:然后使用自己的代理键将记录写入到新的统一表中,并在需要时将原始键保留在新表的单独字段(以及标识原始源表的字段)中作为引用。这种合并应该是非常罕见的,并且仅是由于拙劣的设计所致。在我之后重复: 代理。按键 决不。更改。 这就是为什么他们代孕。
罗伯特·哈维,

2
@RobertHarvey我同意代理密钥永远不应更改,这就是为什么我认为它们会产生较差的外部标识符的原因。最终,客户将希望更改引用记录的方式。到那时,您已经将整个系统构建在不可变的代理键的周围,或者您已经预先考虑并在业务标识符和代理键之间设置了一个间接级别。
克里斯·皮特曼

2
@sqlvogel:如果我使用术语“系统生成的主键”而不是“代理”,是否会使事情更清楚?我确实同意您可能想更改生成代理密钥的算法,但这并不会改变其根本不变的质量。
罗伯特·哈维

4

在某些情况下,代理密钥是预期的并且对用户有意义。我最喜欢的示例是“订单号”。订单号并不是真正的自然键:自然键可能是时间戳加用户,或者如果您希望用户在时间戳的粒度范围内生成多个订单,则可能会更多。

但是,用户理解并期望订购号的便利。如果您让用户知道它们,则没有害处,也有很多价值。

另一方面,某些代理键对用户没有意义。当然,我的健康保险公司有一些代用密钥,可以根据我的会员ID,出生日期,携带者等来识别我,但是我不在乎,我关心我卡上的信息(通常包括基于ID的ID)在我的雇主身上,并且在整个世界上都不是唯一的...因此,保险公司的代理钥匙)。


如果用户理解它并希望与之交互,则它不再是代理密钥。代理键被定义为没有商业意义。仅仅因为它是一个ID号并不一定意味着它是一个代理。另外,“根据我的会员ID,出生日期来识别我的一些代理密钥”也没有道理。您是说他们的代理键(没有业务意义)基于可以构成自然键的事物来识别您吗?
凯尔·麦维

通常,发生的情况是为您提供了一个员工ID号,以便在员工系统中将您与同名的其他人区分开。在您的保险卡上,它可能会列出您的公司和员工ID。但是,健康保险公司通常会生成自己的内部ID,可以在所有系统中使用它,而不是使用从您的雇主那里获得的名称,出生日期和雇员ID。这些生成的密钥是替代密钥还是自然密钥?取决于您询问的人(请查看en.wikipedia.org/wiki/Surrogate_key上的 2个其他定义)
Alan Shutko

1

如果代理密钥是正确生成的GUID / UUID *,则仅应公开它。公开连续代理密钥是OWASP十大安全问题中的第4个。

*实际上,最好假定它不是出于这些目的而正确生成的,除非您知道它是由密码安全的随机或伪随机数生成器创建的。


2
从您的答案尚不清楚GUID如何提高安全性。
罗伯特·哈维,

1
@RobertHarvey-我想是因为它们不是顺序的,因此无法猜测。
Bobson


@RobertHarvey,澄清了。
彼得·泰勒

1

如果表没有自然键,则代理键允许这样的行。

surrogate_key  some_name
--
1              Wibble
2              Wibble
...
17             Wibble
...
235            Wibble

我称这些人工键代替代理键,但是这种区别对这个问题并不重要。

现在,假设有重要数据通过外键引用这些代理键,那么如果最终用户知道代理键值,最终用户将如何知道要更新哪一行?


将该列标记为“ surrogate_key”有点矛盾,但是然后说它们是“人工键而不是替代键”。如果由于这些人工键没有任何业务意义而仅用作唯一标识符,因此将其称为自然键(公开),则应创建一个新的替代键。即,将归化的surrogate_key重命名为具有业务意义的名称,将其公开给客户,并创建一个新的相似列作为内部操作的真实替代。不够理想,但仍比公开真实替代更好。
凯尔·麦维

@KyleMcVay:这并不矛盾。它尊重代理的含义,代理的基本思想是“替代”。一个代理键替代自然键。(科德和一般用途的关系理论代理键在这个意义上)一个表没有自然键不能在这个意义上代理键。但是它可以具有使用的任意值,而不是其他任何值。这就是我所说的人工钥匙。
Mike Sherrill'Cat Recall'17

您的定义并非不正确,但我认为替代键已具有替代替代单词sursurgate之外的特定于行业的含义。如果您打算将密钥公开给客户,我会认为该密钥现在具有商业意义。它已归化,现在在逻辑上应视为它所代表实体的一部分。按照这种逻辑,就没有暴露的代理密钥之类的东西。如果您要公开一个人工密钥,那么它就不再是替代密钥,您需要一个新密钥。
凯尔·麦维

0

用外行的话来说:

  • 应该向用户隐藏代理。
  • 您应该向用户公开其他一些业务候选键。
  • 如果不存在其他候选密钥,则应显示PK。但是在这种情况下,由于PK不能替代其他列,因此不被视为代理。

为什么必须显示PK?我认为这是我的问题-自动生成的PK是否正确称为代理密钥是切线的。
psr

1
@psr您的问题标题为“ 代理密钥曾经公开”。我说不。但是您必须显示其他一些密钥。如果没有其他键,则必须显示唯一的键。切向地阐明,在这些情况下,键实际上不是替代键,因为它不能替代任何其他列。
TulainsCórdova'13

问题是您应该添加一列还是显示您拥有的键。
psr

@psr我改写了我的答案以使其更加清晰。
图兰斯·科尔多瓦

1
我发现这是微不足道的区别。如果您的规则是每个表都有一个人工键(属于我的),并且只有人工键参与联接(这也是我的原则),则该键是替代的概念,因为其他键可能是可用是无关紧要的。
罗伯特·哈维

0

您只应向用户公开一个字段,该字段可以直接或向您报告缺陷时向用户提供有用的信息。

相反,当“代理主键”是识别用户执行的交互的记录(简单或复杂)的主要手段时,则应始终公开“代理主键”。


0

您是否将密钥公开给最终用户都没有关系。您的应用程序应执行必要的授权,例如,仅知道订单ID便无法允许他们访问通常无法访问的内容。

注意:这里假设基于Web或n层的应用程序可以/可行进行服务器端授权。如果您有直接执行sql的VB应用程序,那就是整个“另一个问题”。


如问题中所述,在保留外键关系的同时不能插入然后删除记录该怎么办?
psr

与将密钥公开给用户有什么关系?也许我不理解您对“暴露”一词的使用。我正在基于您的意思是“可以被用户看到”的假设。
GrandmasterB
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.