VARCHAR 作为数据库中的外键/主键好还是坏?
Posted
技术标签:
【中文标题】VARCHAR 作为数据库中的外键/主键好还是坏?【英文标题】:VARCHAR as foreign key/primary key in database good or bad? 【发布时间】:2011-01-07 09:09:10 【问题描述】:如果我使用 ID nr:s 而不是 VARCHARS 作为外键会更好吗? 使用 ID nr:s 而不是 VARCHARS 作为主键会更好吗? 通过 ID nr 我的意思是 INT!
这就是我现在拥有的:
category table:
cat_id ( INT ) (PK)
cat_name (VARCHAR)
category options table:
option_id ( INT ) (PK)
car_id ( INT ) (FK)
option_name ( VARCHAR )
我可以有这个想法:
category table:
cat_name (VARCHAR) (PK)
category options table:
cat_name ( VARCHAR ) (FK)
option_name ( VARCHAR ) ( PK )
还是我的想法完全错了?
【问题讨论】:
那我就用数字吧,谢谢大家! 好决定。 VARCHAR 可用于支持继承的数据库或遗留代码。增加字母也更困难(尽管绝对不是不可能)。 为什么需要增加字母? 你不会的。这有点开玩笑。 递增字母... FTL 【参考方案1】:我会说可以将 VARCHAR 用作 主键和外键。
我可以预见的唯一问题是,如果您有一张桌子,比如说 Instruments(共享工具),并且您将 PRIMARY/FOREIGN KEY 创建为 VARCHAR,而 CODE 会发生变化。
这确实发生在证券交易所,并且需要您重命名此代码的所有引用,而作为 ID nr 不需要您这样做。
总之,我想说这取决于您的预期用途。
编辑
当我说 CODE 时,我指的是 GOOG 或任何其他共享的股票代码。这些代码可能会随着时间而改变,假设您查看 Dirivative/Future 工具。
【讨论】:
感谢您的回答,请解释“代码”...请查看此 Q 以了解我的预期用途:***.com/questions/2100008/… 即使某个键确实发生了变化,如果您的数据库正确设置为级联更改,这应该不是问题。 @Tony 我想我从来没有遇到过这样的情况,我想要级联更改。事实上,我从来没有使用过开启级联的数据库 :-) @MatthieuF:没错,键(希望如此!)不会改变,但我想如果它们改变了,你可能不得不以一种或另一种方式处理它。 [把我的脖子放在这里]我更喜欢使用自然键,因此我不得不考虑这种可能性:)【参考方案2】:将 VARCHAR 用于任何 KEY 的问题是它们可以容纳 WHITE SPACE。空格由任何非屏幕可读字符组成,例如空格制表符、回车符等。当您开始寻找为什么表不返回最后带有额外空格的记录时,使用 VARCHAR 作为键会让您的生活变得困难他们的钥匙。
当然,您可以使用 VARCHAR,但您必须非常小心输入和输出。它们还占用更多空间,并且在执行查询时可能会更慢。
整数类型有一个包含 10 个有效字符的小列表,0,1,2,3,4,5,6,7,8,9。它们是用作键的更好解决方案。
如果您想获得更快查找的优势,您始终可以使用基于整数的键并将 VARCHAR 作为唯一值。
【讨论】:
但是数字标识符的问题是它们难以阅读,并且您在查看数据时总是需要连接到其他表以获得它们的含义。想象一下一个表,它关联三个(或更多)其他表,所有 ID 都是整数?您有三列没有直接意义的数字。 @Tony:立即可读的数据通常意味着非规范化数据。 @OMG Ponies:我同意你的观点,但这并不总是非规范化数据的直接迹象。在@astander 给出的示例中(证券交易所公司代码),为公司使用 CHAR 键非常有意义。它们都是独一无二的,但也非常易读。 这里没有随机的。股票代码更改并非闻所未闻(SUN -> JAVA)。同一个公司,怎么处理?独一无二 - 没有。不是你获得国际化的那一刻。或者不仅使用股票,还使用其他金融工具。股票代码 - 哪一个?有多种符号体系(路透社等)具有标准化(但不同)代码。 -1。您的倒数第二句话要么不正确,要么非常具有误导性。整数类型中的“字符”对数据库没有任何意义,它只是字节值的视觉表示。 INT 与 VARCHAR(4) 一样快,BIGINT 与 VARCHAR(8) 一样快(假设所有字符的长度都是一个字节)。【参考方案3】:使用 int 你可以在 4 个字节中存储多达 20 亿个 varchars 你不能需要 10 个字节左右来存储它,如果你使用 varchars 还有一个 2 字节的开销
所以现在你将每个 PK 和 FK 中的 6 个额外字节加上 2 字节 varchar 开销
【讨论】:
是的,我的意思是,归根结底,VARCHAR 中的每个字符都是处理器的二进制数。它只需要使用每个字母的 ASCII 查找表来完成翻译工作。 “A” == 65 == 00000000 01000001。这是为每个字母存储的。事实上,如果你使用单词作为键,那么在你使用可能的数字组合之前,你会用完英文单词 LONG 仅两个字节。 我认为查询速度不会特别受使用 VARCHAR 的影响。我工作的一个数据库在一些具有超过 400 万条记录的表上使用 CHAR 主键,并且查询在一秒钟内执行。 IU 认为代理整数键不会有很大的不同。 @Tony char 没有 varchar 的 2 字节开销,而且我的表也在十亿行范围内,因此每个键额外 2 字节是 7 GB 我必须为 SAN 空间支付额外费用一个表......然后备份需要更长的时间等等当你有大表时,你需要优化的不仅仅是几百万行 公平点。我目前拥有的数据库是我使用过的最大的数据库,所以是的,我可以看到那些额外的几个字节会导致问题。另外,考虑一下我没有任何 VARCHAR 键,只有 CHAR! :) 开销仍然是开销。它可能没有那么重要,但除非有充分的理由,否则它仍然不是一个好主意,除非有充分的商业理由。【参考方案4】:这两种方法都没有错,尽管这个问题可能会引发通常的争论,后者更好:自然键或代理键。
如果您使用 CHAR 或 VARCHAR 作为主键,您最终会在某些时候将其用作外键。正如@astander 所说,归根结底,这取决于您的数据以及您将如何使用它。
【讨论】:
大声笑。有时我在想,未来是否会因为这些问题而引发战争。但是,您是对的,它始终取决于数据及其使用方式。就个人而言,我已经被使用非整数类型作为 PK 烧毁了太多次,所以我忍受了与记录没有直接关系的 PK 的“非人类可读性”。【参考方案5】:如果您将类别名称添加到 ID 中,如果您决定重命名类别,将会遇到问题。
【讨论】:
【参考方案6】:当我在做设计工作时,我会问自己:我在这些数据中是否有任何东西可以保证是非 NULL、唯一且不变?如果是这样,那就是主键的候选人。如果没有,我知道我必须生成一个要使用的键值。然后,假设我的候选键恰好是 VARCHAR,然后我查看数据。它的长度是否合理(例如,20 个字符或更少)?还是 VARCHAR 字段相当长?如果它很短,它可以用作键 - 如果它很长,也许最好不要将它用作键(尽管如果考虑到它是主键,我可能无论如何都必须索引它)。至少我担心的一部分是主键必须被索引,并且可能会被用作其他表的外键。 VARCHAR 字段的比较往往比数字字段的比较慢(尤其是二进制数字字段,如整数),因此使用长 VARCHAR 字段作为键可能会导致性能下降。 YMMV。
【讨论】:
【参考方案7】:我的 2 美分:
从性能的角度来看,使用 CHAR 或 VARCHAR 作为主键或索引是一场噩梦。
我测试了复合主键(INT + CHAR、INT + VARCHAR、INT + INT),到目前为止,INT + INT 是最好的性能(加载数据仓库)。如果只保留数字主键/索引,可以说性能提高两倍。
【讨论】:
以上是关于VARCHAR 作为数据库中的外键/主键好还是坏?的主要内容,如果未能解决你的问题,请参考以下文章
使用 SQL 和 C# 将表 1 的主键分配为表 2 中的外键
为啥我需要将子表的主键作为父表的外键,而不是相反的 1:1 识别关系?