使用积分类型的主键是否更有效地存储?

时间:2016-02-09 20:58:39

标签: sql sql-server tsql database-design

这就是我的意思。假设我有一个名为Names的表,它只是一个唯一的名称列表,

      Names 
================
      name
================
    "Charlie" 
----------------
    "George"
----------------
    "Bernie"
----------------

和另一个引用这些名称的表,

        OtherTable  
=========================
  ... |   name    | ....
=========================
  ... | "Charlie" | ....
-------------------------
  ... | "Charlie" | ....
-------------------------
  ... | "Charlie" | ....
-------------------------

数据库引擎是否在OtherTable中存储实际名称?或者通过存储一些隐藏的引用来优化它们?

如果没有,那意味着我应该向Names添加一列

id |   Names 
==================
1  |     name
==================
2  |   "Charlie" 
------------------
3  |   "George"
------------------
4  |   "Bernie"
------------------

并像

一样引用它
        OtherTable  
=========================
  ... |  name_id | ....
=========================
  ... |    1     | ....
-------------------------
  ... |    1     | ....
-------------------------
  ... |    1     | ....
-------------------------

然而,Names表上的附加列作为主键是不必要的,因为唯一的names可以像主键一样服务(除了它可能稍微少一点)高效地按name查找,因为字符串比较比整数比较慢。

这不是Catch-22的情况吗?

3 个答案:

答案 0 :(得分:6)

功能和逻辑方面应优先于(非常)次要的效率方面。

链接有意义的列(作为name列)的问题是有意义的列往往会受到更改。例如。您可能会发现名称中的拼写错误并想要更改它。另一方面,作为PK的标识列在这种意义上是没有意义的,除了作为内部使用的标识符并且通常不向用户显示之外没有其他意义。由于没有人关心它的真正价值,没有人会想要改变它。

字符串可以区分大小写,可以具有不同的长度,不同的排序规则,不同的编码和不同的类型(varchar,nvarchar,char,nchar)。 int很简单(intintint)。

如果您使用名称表作为与其他表无关的简单查找表,即,如果您只是想将其用作填充文本框但不需要任何参照完整性的便捷方式(无外国语)键),然后你可以将它用作主键。

顺便说一下:数据库不会创建任何神奇的,隐藏的引用,但它完全按照你的要求去做。

答案 1 :(得分:1)

数据库将实际数据值存储在表中。如果查找表的主键是字符串,则该字符串可能会在OtherTable中多次存储。

根据数据的性质,使用Names表的合成整数主键可能更节省空间。但是,您可以为加入两个表格做额外工作而不是仅从name获取OtherTable而为此付出代价。另一方面,当“查理”决定他现在想要被称为“查尔斯”时,合成密钥更容易更新name值。与几乎任何架构决策一样,您必须确定权衡是否值得。

答案 2 :(得分:0)

在“其他”表中,引擎将存储您在创建列时所指示的内容(即字符串)。所以是的,那里有冗余。

在此特定方案中,您通过使用对相同数据的较短引用替换字符串来执行一种数据压缩形式。许多通用压缩算法都做了类似的事情。

如果您关心节省空间,这是一件有效的事情。这是一个复杂的权衡,有许多优点和缺点。

你不会错过任何我认为的主要方面。