假设我有一个这样的数据库;
Product with columns [ProductName] [Price] [Misc] [Etc]
Order with columns [OrderID] [ProductName] [Quantity] [Misc] [Etc]
ProductName是Product的主键,属于某种字符串类型且唯一。
OrderID是主键和某种整数类型,而ProductName是外键。
假设我将Product的主键更改为整数类型的新列,即[ProductID]
。
这会减少数据库大小并优化连接这两个表的查找(以及同样的操作),还是(大多数/一般/主要) SQL数据库实现自动执行这些优化?
从技术上讲,使用(String)ProductName作为Product
中的主键,数据库应该能够在Order
中实现ProductName列,只是指向Product
中的行的指针,并且如同将整数作为外键一样快速执行JOIN
,这是实现SQL的标准方法。
更新的 这个问题是关于SQL服务器如何处理外键,而不是产品表是否需要序列号,或者我如何处理数据库中的产品名称更改。
答案 0 :(得分:2)
字符串主键是一个坏主意,因此将其更改为INT将有助于提高性能。大多数数据库使用主键索引进行查找和比较,如果可能,请选择一个简短的主键 - 一列。您可以使用主键列进行连接(根据连接列中的公共值组合来自两个或多个表的数据),查询检索以及对查询结果集进行分组或排序。索引条目越简短,数据库执行查找和比较的速度就越快。
更不用说,如果产品名称发生变化,您如何处理?将包含产品名称的所有行更新为外键?
我不能说得更好,所以看看这个答案:Should I design a table with a primary key of varchar or int,引用那个答案:
使用VARCHAR(10)或(20)只是使用 太多空间 - 10或20个字节 而不是4,而且很多人 不知道 - 聚类键值 将在每个索引上重复 每个非群集上的条目 表上的索引,所以可能, 你浪费了很多空间(不是 只是在磁盘上 - 这很便宜 - 但也 在SQL Server的主内存中)。也, 因为它是可变的(可能是4,可能 是20个字符)SQL服务器更难 妥善保持良好的指数 结构
答案 1 :(得分:0)
整数列比连接中的字符串更好
整数autoinc列作为主要聚类键适用于插入
答案 2 :(得分:0)
我不会减少数据库大小(可能你会保留产品名称字段),但绝对应该提高查找性能。
答案 3 :(得分:0)
大多数实现中的整数数据类型的大小将小于字符串(CHAR
,VARCHAR
等),这将使您的索引的大小更小。
此外,比较字符串还存在一些问题:
某些数据库,即MySQL
,会压缩字符串键,这会降低搜索效率。
使用自然语言标识符的字符串B-Trees
往往比整数B-Trees
更少并发平衡。由于自然语言单词不会在字母表中均匀分布,因此更多更新和插入将转到同一个块,从而增加了页面拆分的数量并最终增加了索引大小。要解决此问题,Oracle
支持索引中的REVERSE
子句。
比较两个字符串时,应考虑整理。通常情况下,这并不重要,但它会增加一些开销。
答案 4 :(得分:0)
主键应该是唯一的,在创建行时存在并且尽可能不可变。 IMO,关于是否使用代理密钥的讨论应该是数据完整性问题的次要问题。
例如,如果某个产品在该项目上标记了序列号,该序列号在输入数据库中的行时必须存在且保证是唯一的,那么IMO将会生成一把好的主键。原因是此值将用作其他表中的外键,它可以节省额外查找的费用以获取产品的序列号。在您进入数百万行之前,额外的存储空间是无关紧要的。但是,如果序列号是由其他一些制造商盖章的,那么你不能保证其独特性(“它可能是唯一的”还不够好),那么代理就是合适的。事实上,如果不是大多数“产品”表使用代理键,我甚至会说很好的部分,因为没有保证在进入时可用的值,保证是唯一的并且相对不可变的可用作为一把钥匙。
但是,许多使用代理键的开发人员忽略了每个具有代理键的表的需要还还有另一个键(即一个独特的约束)。因此,在您使用产品的情况下,即使添加整数主键,您仍应对产品名称具有唯一约束。产品名称的唯一约束创建了所谓的候选键,其中整数值是主键。
代理键意味着幕后花絮。虽然整数键表现最好并且易于创建,但它们有一个缺点:应用程序开发人员向用户显示关键价值很容易,甚至很诱人。这是IMO的错误。用户永远不应该看到键值,否则他们将依赖于值本身,如果您需要重新排序值(例如,使用数据库合并)或者如果您使用在由身份价值,他们依赖于连续的价值观。只要您从未向用户显示该值,使用整数PK就可以了。