在工作中,我们有一个具有唯一索引而不是主键的大型数据库,并且一切正常。
我正在为一个新项目设计新的数据库,但有一个难题:
在数据库理论中,主键是基本元素,没关系,但是在REAL项目中,两者的优点和缺点是什么?
您在项目中使用什么?
编辑: ...以及MS SQL服务器上的主键和复制呢?
在工作中,我们有一个具有唯一索引而不是主键的大型数据库,并且一切正常。
我正在为一个新项目设计新的数据库,但有一个难题:
在数据库理论中,主键是基本元素,没关系,但是在REAL项目中,两者的优点和缺点是什么?
您在项目中使用什么?
编辑: ...以及MS SQL服务器上的主键和复制呢?
Answers:
什么是唯一索引?
列上的唯一索引是该列上的索引,该索引还强制执行以下约束:在该列中不能在两个不同的行中具有两个相等的值。例:
创建表table1(foo int,bar int); 创建唯一索引ux_table1_foo ON table1(foo); -在foo上创建唯一索引。 INSERT INTO table1(foo,bar)VALUES(1、2); - 好 INSERT INTO table1(foo,bar)VALUES(2,2); - 好 INSERT INTO table1(foo,bar)VALUES(3,1); - 好 INSERT INTO table1(foo,bar)VALUES(1、4); -失败! 键“ ux_table1_foo”的条目“ 1”重复
最后一次插入失败,因为foo
在第二次尝试将值1插入此列时,它违反了列上的唯一索引。
在MySQL中,唯一约束允许多个NULL。
可以在多个列上创建唯一索引。
主键与唯一索引
相同的东西:
不同之处:
您可以这样看:
主键是唯一的
唯一值不必是元素的表示形式
含义?; 好吧,主键用来标识元素,如果您有一个“ Person”,您希望拥有一个对您的Person来说是主要的Personal Identification Number(SSN等)。
另一方面,此人可能会收到一封唯一的电子邮件,但却无法识别该人。
我总是有主键,即使在关系表(中间表/连接表)中,我也可能拥有主键。为什么?好吧,我喜欢在编码时遵循一个标准,如果“人”有一个标识符,那么汽车也有一个标识符,那么“人->汽车”也应该有一个标识符!
外键和主键都具有唯一约束。从在线书籍:
一个FOREIGN KEY约束不必仅链接到另一个表中的PRIMARY KEY约束。也可以定义它引用另一个表中UNIQUE约束的列
对于事务复制,您需要主键。从在线书籍:
发布用于事务复制的表必须具有主键。如果表在事务复制发布中,则不能禁用与主键列关联的任何索引。这些索引是复制所必需的。若要禁用索引,必须首先从发布中删除表。
这两个答案都是针对SQL Server 2005的。
选择何时使用代理主键而不是自然键是很棘手的。诸如总是或永不这样的答案很少有用。我发现这取决于情况。
例如,我有以下表格:
CREATE TABLE toll_booths (
id INTEGER NOT NULL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
...
UNIQUE(name)
)
CREATE TABLE cars (
vin VARCHAR(17) NOT NULL PRIMARY KEY,
license_plate VARCHAR(10) NOT NULL,
...
UNIQUE(license_plate)
)
CREATE TABLE drive_through (
id INTEGER NOT NULL PRIMARY KEY,
toll_booth_id INTEGER NOT NULL REFERENCES toll_booths(id),
vin VARCHAR(17) NOT NULL REFERENCES cars(vin),
at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
amount NUMERIC(10,4) NOT NULL,
...
UNIQUE(toll_booth_id, vin)
)
我们有两个实体表(toll_booths
和cars
)和一个事务表(drive_through
)。该toll_booth
表使用代理键,因为它没有不保证更改的自然属性(名称可以轻松更改)。该cars
表使用自然主键,因为它具有不变的唯一标识符(vin
)。该drive_through
交易表使用便于标识的代理键,但也有对保证是在记录插入了时间的独特属性的唯一约束。
http://database-programmer.blogspot.com在此特定主题上有一些很棒的文章。
如果某件事是主键,则取决于您的数据库引擎,整个表将按主键排序。这意味着在主键上的查找要快得多,因为它不需要进行任何取消引用,因为它与任何其他类型的索引都必须进行。除此之外,这只是理论上的。
只要您不允许使用NULL值,就应该对它们进行相同的处理,但是在数据库上对NULL值的处理方式有所不同(AFAIK MS-SQL不允许使用多个(1)NULL值,mySQL和Oracle允许这样做,如果列是UNIQUE),则必须定义此列NOT NULL UNIQUE INDEX
关系数据理论中没有主键之类的东西,因此您的问题必须在实践层面上得到解答。
唯一索引不是SQL标准的一部分。DBMS的特定实现将确定声明唯一索引的后果。
在Oracle中,声明主键将导致代表您创建唯一索引,因此问题几乎没有意义。我不能告诉您其他DBMS产品。
我赞成声明主键。这具有禁止键列中的NULL以及禁止重复项的效果。我也赞成声明REFERENCES约束以强制实体完整性。在许多情况下,在外键的同伴上声明索引将加快连接速度。这种索引通常不应唯一。
聚集索引与唯一索引相比有一些缺点。
如前所述,CLUSTERED INDEX对表中的数据进行物理排序。
这意味着,如果在包含聚簇索引的表上有大量插入或删除操作,那么每次更改数据时(实际上,几乎取决于填充因子),都需要更新物理表以保持排序。
在相对较小的表中,这很好,但是当进入具有GB数据值的表,并且插入器/删除器影响排序时,就会遇到问题。
我几乎从来没有创建没有数字主键的表。如果还有一个自然键应该是唯一的,我还要在其上放一个唯一的索引。整数上的联接比多列自然键更快,数据只需要在一个地方更改(自然键往往需要更新,这在主键-外键关系中是一件坏事)。如果您需要复制,请使用GUID而不是整数,但是在大多数情况下,我更喜欢用户可读的键,尤其是当他们需要看到它以区分John Smith和John Smith时。
几次不创建代理键是当我有一个涉及多对多关系的联接表时。在这种情况下,我将两个字段都声明为主键。
我的理解是,主键和具有非null约束的唯一索引是相同的(*);我想根据规范明确声明或暗示的内容(取决于您要表达和明确执行的内容)选择一个或另一个。如果它要求唯一性且不为null,则将其设为主键。如果发生这种情况,唯一索引的所有部分都不为空,并且没有任何要求,那么就使其成为唯一索引。
唯一的区别是,您可能有多个非空的唯一索引,而您没有多个主键。
(*)除了实际差异外,主键可以是某些操作(例如定义外键)的默认唯一键。例如 如果定义了引用表的外键而不提供列名,则如果引用的表具有主键,则主键将是被引用的列。否则,被引用的列将必须显式命名。
这里的其他人提到数据库复制,但是我不知道。
如果由我决定...
您需要满足数据库和应用程序的要求。
在每个表中添加一个自动递增的整数或long id列作为主键,可以满足数据库的需求。
然后,您将至少一个其他唯一索引添加到表中,以供您的应用程序使用。这将是employee_id,account_id或customer_id等的索引。如果可能,此索引不应为复合索引。
与综合索引相比,我更倾向于在多个字段上单独使用索引。只要where子句包含这些字段,数据库将使用单个字段索引,但是只有在您以完全正确的顺序提供字段时,数据库才会使用复合字段-这意味着除非您提供以下信息,否则数据库将无法使用复合索引中的第二个字段where子句中的第一和第二。
我全都使用计算索引或函数类型索引-并建议在复合索引上使用它们。通过在where子句中使用相同的函数,可以非常轻松地使用函数索引。
这样可以满足您的应用程序要求。
很有可能其他非主索引实际上是该索引键值到主键值而不是rowid()的映射。这允许进行物理排序操作和删除操作,而不必重新创建这些索引。