什么是MySQL主要(key1,key2)

时间:2009-11-27 22:48:51

标签: mysql performance indexing primary-key

我正在处理现有数据库并尝试对其进行优化。我看到一个表没有一个主键,但有两个外键作为主键。我知道它会起作用。但是,为了获得更好的性能,使用一个主键和两个外键是否更好?或者主键(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中),即使您将复合键设置为主键。您仍然必须为所有键显式设置索引。然后你会喜欢索引。

4 个答案:

答案 0 :(得分:4)

在您显示的第二个示例中,xidyid已编入索引,但没有任何内容阻止您的应用输入同一对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”的所有人,则必须搜索每一页。电话簿就像(ABCCREATE 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)

关于主键还有一个很酷的事情是,数据实际上是由磁盘上的主键排序的。因此,在性能方面,即使是唯一索引和主键之间也存在细微差别。但是,它可能不会产生很大的性能差异,只需要花多少时间从磁盘上获取数据。