2009-11-27 428 views
2

我正在使用现有的数据库并尝试优化它。我看到没有单个主键的表,但有两个外键用作主键。我知道它会起作用。然而,为了获得更好的性能,使用两个外键的主键(key1,key2)能够像单键一样工作更好吗?什么是MySQL主键(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) 
) 

一些更新有

所以,我做了一些测试使用简单的查询,在三个不同的表

表妙..,有10000条记录。只有userid作为主要索引。

SELECT * FROM MYA其中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两个外键中的一个。超过50000记录

SELECT * FROM MYB其中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,也是许多一对多表,但与复合主键,用户ID是两个中的一个。超过10万的记录

SELECT * FROM MYC其中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中居然检查所有10万条记录! (查询只返回50条记录)

有些东西我不明白......在我看来,复合材料主要是不做这项工作。


更多..

虽然我做更多的测试和“解释”,我的结论是(在MySQL),即使你设置组合键作为主键。您仍然必须为所有键明确设置索引。然后你会喜欢索引。

回答

1

添加id列只有在向用户公开内容时才值得。无论哪种方式,这是一个典型的多对多连接表。

要将主键更改为单列意味着将唯一键约束添加到两个外键列上 - 因为您将列定义为主键时获得唯一性,即使它是组合键。组合键是2+列的组合。

如果您未选择该id列,则不需要该列。

1

你所描述的是一个复合主键,它是可以接受的和合理的模式。当有一个完全可以接受的候选键时,许多应用程序使用人工主键(通常是int或guid)。这为数据库添加了工作,但在某些情况下使应用程序更易于编写。

当已有候选人时,没有真正的理由添加额外的主键。我倾向于不这样做。

您还没有加入不必要的自动生成的主键列获得性能在某些情况下,它降低了数据库的空间使用情况(虽然只是轻微)

4

在告诉你第二个例子中,xidyid索引但没有什么能阻止你的应用程序进入同一对xidyidABC表的多个行:

INSERT INTO ABC (xid, yid) VALUES (123, 456), (123, 456); -- NO ERROR 

您可以GE无意的重复这种方式,并且当你进行连接和计数时它可能会造成奇怪的效果。此外,如果您需要更新行以更改给定的xid和其yid之间的关联,则可以更新一行而不更新其他行。

您至少应该将(xid, yid)的密钥声明为UNIQUE KEY以防止重复。

您显示的第一个示例使用复合主键(有人说复合主键)。 SQL支持多列索引和多列约束。这样做没有任何缺点,除了如果你想运行一个查询来选择一行,你需要使用两列而不是一个标识行的条件。

DELETE FROM ABC WHERE xid = 123 AND yid = 456; 

同样,如果另一个表包含外键引用ABC表,它必须有两列。

有足够的程序员发现使用两列是如此繁重和混乱,他们宁愿添加一列代理键。

当不需要任何东西时,坚持使用多余的代理键是我认为是SQL反模式的东西。


重新上述更新的问题:你知道,当你的搜索包括索引最左边的列的复合索引不仅可以帮助?任何品牌的RDBMS中的任何复合索引都是如此。示例:

CREATE TABLE myC (
    somethingid INT, 
    userid  INT, 
    PRIMARY KEY (somethingid, userid) 
); 

SELECT * FROM myC WHERE userid = 12345; 

此查询不能使用主键索引。

经典的例子来解释复合索引的使用是电话簿比喻:如果我问你要搜索的每个人的姓氏是“托马斯”你可以用事实电话簿按姓氏有序帮助快速进行搜索。但是如果我要求你搜索名字是“Thomas”的所有人,你必须搜索每一页。电话簿就像是一个复合索引(last_namefirst_name)。所以如果你的搜索不包括last_name,你必须诉诸暴力搜索。

您也可以为其他列创建额外的索引,因此您可以使用该索引作为标准进行搜索。第一列不需要额外的单列索引。复合指数是足够的。

CREATE TABLE myC (
    somethingid INT, 
    userid  INT, 
    PRIMARY KEY (somethingid, userid), 
    KEY (userid) 
); 

通常如果该列被声明为外键,则RDBMS 应该自动创建索引。但是,在某些RDBMS产品的某些版本中,您必须自己创建一个外键列的索引,作为单独的操作。

0

还有一个关于主键的很酷的事情,那就是数据实际上是由磁盘上的主键来排序的。因此,就性能而言,即使是唯一索引和主键之间也存在细微差别。虽然这可能不会有太大的性能差异,但实际上需要多少时间才能从磁盘中获取数据。

相关问题