在数据库中为某些表创建辅助主键


22

我想在我的某些表中添加“ second_primary_key”,这将是uuid或一些随机的长键。我需要它,因为对于某些表,我不想向我的Web应用程序公开整数。也就是说,在页面“ / invoices”上,我有一个发票列表和一个指向“ / invoices /:id”的链接,其中:id是整数。我不想让用户知道我的系统中有多少张发票,因此我想使用其“ second_primary_key”代替“ / invoices / 123”,从而使URL为“ / invoices / N_8Zk241vNa”

我要隐藏真实ID的其他表也是如此。

我想知道,这是常见的做法吗?实现此目的的最佳方法是什么?

到底该技术叫什么,以便我对此进行搜索?


20
为什么不完全去除整数?
larsbe

4
您可以在表上定义任意数量的唯一键/索引。
abuzittin gillifirca

2
也许您应该将其称为辅助候选密钥。“主要”仅建议一个。
Walter Mitty

4
“第二主要”是矛盾的。您有一个主键,也可以有辅助键。
停止Harming Monica

7
@RobbieDee有没有完全规范化数据库的正当理由。具有候选键或辅助键并不能完全复制数据。
马查多

Answers:


0

您可以添加UUID列,但实际上不需要(也不应该)。这是表示层的问题。您不会幻想说将货币值存储为1,999美元以及1999年。

您只需要某种方式可以即时隐藏应用程序的价值。您可以在应用程序本身或数据库视图中执行此操作。

由于我们只在谈论一个单一的值,因此也许请看一下诸如AES或类似方法的2种加密方式-越轻便越好。

散列可能是另一种可能性-这取决于您是否要取回发票编号,因为散列是一种方法。


48

在关系数据库建模中,拥有“替代主键”是众所周知的概念,它被称为“替代键”,有时也称为“辅助键”。“潜在主键”的集合称为“候选键”。参见https://beginnersbook.com/2015/04/alternate-key-in-dbms/

实施此操作的方式完全取决于您,特别是如果您想隐藏记录的总数。没有“最佳方法”,如果希望ID是否区分大小写,希望在打印的发票上可读,则应检查要求,例如允许的或有用的字符集,最大长度。必须能够正确无误地在电话上将其驱散,依此类推。


11
我还看到了用于描述这种情况的术语“ 自然键代理键”
DanK

2
@Dari:您用粗体字问“此技术叫什么”。并且,如果AES解密(可能是即时进行的)产生了您正在寻找的那种密钥,请使用它,这与我的回答并不矛盾。
布朗

1
@Dari因为它为您的应用添加了完全不必要的开销
Lamak

1
@RobbieDee我们已经知道您不喜欢备用键,但这并不意味着它们没有用。我喜欢引导方法,因为它可以简化许多问题。
T. Sar-恢复莫妮卡

1
@RobbieDee我们不使用SQL Server。我们使用MySql。之所以会发生这种情况,是因为有人会在Prod上创建某些东西,比如ID为1234。在Dev上,自然而然地,我们创建的实体比在prod上做的更多。1234是很久以前由一些一次性实体进行测试的。当我们必须从prod测试实体时,我们必须将其迁移回Dev-并且其主键已在使用中。如果对该实体的引用是基于guid的,则迁移会容易得多。但是,在主键为int或long的情况下,hibernate的性能要好得多,因此我们保持这种状态。我的开发人员并不懒惰或愚昧-他们经验丰富。
corsiKa '17

9

大多数发票都有发票编号,大多数会计规则要求该编号是连续的,否则会计可能不会在年度结果上签字,或者IRS(或您所在国家的类似名称)可能希望在您的标签上进行全面审核。

用户可以从发票编号中推断出您服务了多少客户,或者您更改了发票编号策略之前已有多长时间。

数据库中存储了多少张发票无法衡量您的发票总数。还有其他发现方法,包括向商会要求您提供年度报告。

但是,我会将发票锁定在用户登录屏幕后面,因此并非每个人都可以要求它。然后,在用户登录时,他们可以使用ajax方法来请求其未结清的发票等。这可以保护您的数据,通过ajax隐藏URL(通常没人会费心查看ajax请求构建方式的详细信息) ,您可以控制数据的显示和提供方式。


7
在银行业务中(带有支票号码)使用的一种常见策略是,不从1开始增加计数,而是出于这个确切原因而增加一些数字。
DanK

我认为这就是为什么id是一个额外的主键,而不是替换旧的主键的原因。
亚历山大

1
我不会称它为主键。我会很a,以UUID作为名称,但从本质上讲,它只是表中的另一个索引字段。报价单编号,发票编号等。这是一个字段,但不是主键。主键必须是唯一的,并且可以在内部用于关系映射。如果索引的字段可以通过where查询快速搜索。userXveryY.where('invoice_number','foobarbaz10')。get();
Tschallacka

1
您正在回答一个技术问题,并提出一个论点,即由于美国的特殊性(不需要顺序发票号,在商会的报告)而不需要。IMO这不能很好地回答这个问题。
RemcoGerlich

7

您也许可以为此使用hashid,它专门用于解决这种情况。

它将您的数据库ID编码为短哈希(类似于YouTube视频的URL),并且不需要您在表中添加任何辅助键。


2
名称有点误导,因为它不是哈希,而是可逆的函数。但这似乎是解决该问题的完美解决方案。
疯狂的酸奶,

2
@CrazyYoghurt是的……他们在这里解决了命名的原因:hashids.org/#why-hashids
Eric King

3

您可以创建另一个唯一键,但不能。没有给出的原因。有更简单的隐藏表大小的方法。

N_8Zk241vNa表中每行的存储成本为12个字节,而索引中的存储成本甚至更高。这对于您的需求而言是非常浪费的。

加密整数id不会浪费空间,并且在运行时几乎没有成本。如何执行取决于您的编程语言和/或数据库。

请注意,使用AES时,您将获得128位整数,这意味着base64中有22个字符,可能比您想要的更多。像DES或3DES这样的块大小为64的密码可以为您提供11个字符,就像您想要的一样。

对不同的表使用不同的键。

如果您只需要隐藏表大小,则可以对所有表使用通用顺序。请注意,如果许多表中频繁插入,则可能会成为瓶颈。使用诸如Hibernate和Hi-Lo算法之类的方法,此问题就消失了。


确实-存储此值只是为了隐藏另一个值是错误的。
罗比·迪

在这种情况下,这可能是可行的,因为发票ID并不是真正机密的,但作为一般规则,如果将来需要在某些时候屏蔽数据,则使用机密ID作为数据库中的关系结构将引起头疼的事情。最好将它们视为属性。
DanK

我如何在这里申请aes?
Dari

@Dari如何将AES应用于任何事物?不知道您的语言,没人能说。通常,AES与一起使用byte[],您可以用id四个或八个字节写入您的密码,添加唯一的表号并加密(输入必须恰好是16个字节)。如果有可供选择的模式,则欧洲央行是正确的。
maaartinus

@DanK什么?您是否声称AES不安全?在不知道密钥的情况下,攻击者没有什么比存储属性更好的了。没有。+++我想,我不理解您的评论。
maaartinus

0

恕我直言,无法创建两个不同的主键。当然,您可以将该uuid放入数据库中,以使其作为当前主键的“别名”。您可以在具有唯一约束的那列上放置索引,但是主键(从本质上来说)是单个表中的单个。可以有复合主键,但这不是您想要的。

因此,我建议将其放在那里,但只能与索引一起使用。您可以创建处理组件以通过PK以及其他唯一列查询数据。处理“ / invoices / ...”的请求时,只需检查参数-如果它是整数,则搜索ID,否则搜索uuid。或者,当ID搜索未找到任何内容时,您可以将uuid搜索作为后备。

关于生成一些“随机”的uuid:为什么不像“获取ID,添加常量,转换为十六进制”之类的东西。ID的惰性将提供uuid的唯一性,对于普通凡人,十六进制数更难读取+添加常量将避免像00000001这样的uuid。


1
“为什么不像“获取ID,添加常数,转换为十六进制”之类的东西-因为这很容易弄清楚-给我一个URL,然后我将查看系统中的所有其他发票。IMO没问题真正解决的问题,只是它可能创造的问题
。– CompuChip

处理“ / invoices / ...”的请求时,只需检查参数- 如果它是整数,则搜索ID,否则搜索uuid ”(据我所知,这是要防止有人通过ID搜索(/invoices/123/invoices/124,...),因此您只能通过URL中的UUID进行搜索。
TripeHound

另外,并非所有十六进制数字都包含字母。总是无法区分基本整数和生成的十六进制数是不可能的。
TRiG

如我所料,@ CompuChip,您对计算机感兴趣:-),因此您可以识别十六进制数字。但是,Q的写法不是直接显示发票编号,而是让其他人知道有多少张发票。当我向我的妻子,母亲,邻居显示一些十六进制数字时,他们将不知道“奇怪的文字”是什么。如果将根据Q中的发票编号收到有关安全性问题的通知,那么我将为此目的建议一些复杂的哈希方法。
亚尔达(Jarda)

@TripeHound他仍然可以在内部或某些受访问限制的入口点中通过ID进行搜索……
Jarda

0

如果两个键都指向同一事实,并且它们永远不会发生冲突。为什么不使用某些标量函数从原始密钥派生另一个密钥,该标量函数会创建原始密钥的自定义哈希码。

或者,您可以创建一个附件映射表,该表将存储密钥的两个版本。该表将充当字典来查找辅助键。

根据我的理解,键是隐式索引,添加索引越多,插入速度就越慢。


+1是,添加可能带有索引的大字符串列肯定不是其他人建议的无值操作。除了存储开销,随着索引的添加,插入速度开始降低。
罗比·迪

0

针对您的特定用例的另一种方法是,您无需创建数据库和应用程序,而只需创建到发票的自定义路由,因此/ invoices /:f(id)其中f(id)是id的一部分功能。

定制路由负责将请求映射到正确的操作服务器端。


0

这是一种完全可以接受的做法,也称为“备用键”(AK)。基本上,AK是另一个唯一索引或唯一约束。

您甚至可以根据AK创建外键约束。

一个可能的用例就像您所解释的那样:您在一个不断增加的标识号上具有群集的PK,但是您不希望此号被显示或用作搜索条件,因为它很容易被猜到。因此,此外,您还有一个随机的唯一标识符或参考号作为AK,这就是您提供给用户的ID


0

有几种键/索引。主键是一个特殊的唯一索引,正如答案所说,您当然可以创建另一个唯一键。我同意,除非有充分的理由,否则最好不要公开数据库内部信息。

由于问题与发票和编号有关,因此研究会计行业如何期望发票编号看起来可能是值得的:http : //smallbusiness.chron.com/assign-invoice-numbers-52422.html

具有作为主键的内部ID和带有应用程序/客户可见发票编号的另一个唯一字段的内部ID似乎很麻烦。但是当客户想采用一种新的发票编号方案时,情况并非如此。在那种情况下,您不会打扰其他表中的内部ID及其关系来重新编号整个蜡球。您将按原样保留内部ID,然后重新编号非内部发票编号。

理想情况下,您应尽量不要将表与可能更改的键/外键绑定在一起,并使内部表和关系对应用程序层透明。


0

去吧。

这与博客文章等通常具有的“ slug”字段没什么不同-一种独特的方式来引用与主键分开的数据库记录,适合在URL中使用。我从未听说过有人反对这些。

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.