我正在处理现有数据库并尝试对其进行优化。我看到一个表没有一个主键,但有两个外键作为主键。我知道它会起作用。但是,为了获得更好的性能,使用一个主键和两个外键是否更好?或者主键(key1,key2)的效果会更好?
例如:
CREATE TABLE ABC (
'xid' int(11),
'yid' int (11),
PRIMAY KEY (xid, yid)
)
does it perform the same (in terms of indexing) as:
CREATE TABLE ABC (
'id' int(11),
'yid' int (11),
'xid', int (11),
PRIMARY KEY (id),
KEY (xid, yid)
)
那里有一些更新
所以,我做了一些测试..在三个不同的表上使用简单查询
表myA,有10,000多条记录。只有userid作为主索引。
SELECT * FROM myA where userid = 12345
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE myA const PRIMARY PRIMARY 4 const 1
表myB是一个多对多表,具有主id,而userid是两个外键之一。超过50,000条记录
SELECT * FROM myB where userid = 12345
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE myB ref userid userid 4 const 53
表myC,也是一个多对多表,但是使用复合主键,userid是其中之一。超过100,000条记录
SELECT * FROM myC where userid = 12345
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE myC ALL NULL NULL NULL NULL 101289 Using where
因此,表C实际上检查了所有100,000条记录! (查询只返回50条记录)
有一些我不明白的东西......在我看来,复合初级教育并不能胜任这项工作。
更多..
虽然我正在进行更多测试和“解释”,但我得出结论(在MySQL中),即使您将复合键设置为主键。您仍然必须为所有键显式设置索引。然后你会喜欢索引。
答案 0 :(得分:4)
在您显示的第二个示例中,xid
,yid
列已编入索引,但没有任何内容阻止您的应用输入同一对xid
,{ {1}}表的多行{1}}:
yid
您可以通过这种方式获得无意的重复,并且当您进行连接和计数时,它可能会导致奇怪的效果。此外,如果您需要更新行以更改给定ABC
与其INSERT INTO ABC (xid, yid) VALUES (123, 456), (123, 456); -- NO ERROR
之间的关联,则可以更新一行而不更新其他行。
您至少应该将xid
上的密钥声明为yid
以防止重复。
您展示的第一个示例使用复合主键(有些人说复合主键)。 SQL支持多列索引和多列约束。这样做没有任何缺点,除非你想运行一个查询来选择一行,你需要在标识该行的条件中使用两列而不是一列。
(xid, yid)
同样,如果另一个表包含引用UNIQUE KEY
表的外键,则必须同时包含两列。
足够的程序员发现使用两列是如此繁琐和令人困惑,以至于他们宁愿添加单列代理键。
当不需要时,坚持使用多余的代理键是我认为是SQL反模式的。
重新解决上面的更新问题:您是否知道复合索引仅在搜索包含索引中最左侧的列时才有用?对于任何品牌的RDBMS中的任何复合索引都是如此。例如:
DELETE FROM ABC WHERE xid = 123 AND yid = 456;
此查询无法使用主键索引。
解释复合索引使用的经典示例是电话簿类比:如果我要求您搜索姓氏为“Thomas”的所有人,您可以使用电话簿订购的事实通过姓氏帮助您快速搜索。但如果我要求您搜索名字为“Thomas”的所有人,则必须搜索每一页。电话簿就像(ABC
,CREATE TABLE myC (
somethingid INT,
userid INT,
PRIMARY KEY (somethingid, userid)
);
SELECT * FROM myC WHERE userid = 12345;
)上的复合索引。因此,如果您的搜索不包含last_name
,则必须使用强力搜索。
您还可以为其他列创建额外的索引,因此您可以使用该列作为条件进行搜索。第一列不需要额外的单列索引。复合指数就足够了。
first_name
通常,如果该列声明为外键,则RDBMS 应自动创建索引。但是,在某些RDBMS产品的某些版本中,您必须自己在外键列上创建索引,作为单独的操作。
答案 1 :(得分:1)
如果要将内容公开给用户,则只需添加id
列。无论哪种方式,它都是典型的多对多连接表。
将主键更改为单个列意味着在两个外键列上添加唯一键约束 - 没有必要,因为您将列定义为主键的唯一性,即使它是复合键。复合键是2+列的组合。
如果您没有按id
列进行选择,则无需进行选择。
答案 2 :(得分:1)
您所描述的是复合主键,这是可接受的并且是合理的模式。当已经存在完全可接受的候选键时,许多应用程序使用人工主键(通常是int或guid)。这增加了数据库的工作,但在某些情况下使应用程序更容易编写。
没有真正的理由在已经有候选人时添加额外的主键。我倾向于不这样做。
在某些情况下,您还可以通过不添加不必要的自动生成的主键列来获得性能,并且它会减少数据库的空间使用量(尽管只是略微)
答案 3 :(得分:0)
关于主键还有一个很酷的事情是,数据实际上是由磁盘上的主键排序的。因此,在性能方面,即使是唯一索引和主键之间也存在细微差别。但是,它可能不会产生很大的性能差异,只需要花多少时间从磁盘上获取数据。