我正在设计一个会员表来存储网站的用户。每次用户登录网站时都会使用它,偶尔也会访问以更新用户详细信息。
用户将使用电子邮件地址和密码登录,并且每个帐户都将拥有唯一的电子邮件地址。因此,成员表的Email列应该是聚簇索引似乎是合乎逻辑的,因为当用户登录时,此表上的大多数查询都将针对Email列。使电子邮件列唯一且聚簇索引的关键应该在用户快速登录时查询用户数据并提高性能。
但据我了解,将电子邮件列设为主键有两个原因是错误的。一,主键应该是不变的,所以如果用户决定更改他们的电子邮件地址,那么所有外键都必须更新,这将是不好的。其次,电子邮件地址是字符串,这使得连接速度比PK为int时慢。
那么我可以将非聚集索引作为主键吗?因此,该表既有一个带有电子邮件的聚簇索引作为它的唯一键,又有一个int主键作为非聚簇索引?
谢谢, 邓肯
答案 0 :(得分:4)
主键是逻辑数据库设计,只需要是唯一且非NULL(使用索引实现)。
此外,您可以选择单个聚簇索引,该索引应该是窄的,唯一的,增加的和静态的(电子邮件可能对此不利)。
我会在其上创建一个IDENTITY int主键和群集。
我会在电子邮件中添加一个唯一的非聚集索引,并“包含”其他列,以便最常见的重度查询覆盖(即密码哈希)。请注意,您不需要将聚簇键添加到包含的列中,因为它始终作为非聚集索引中的书签包含在内。)
查看执行计划,确保您没有在用户表中看到任何表扫描或聚簇索引扫描。
我想补充一点,通常人们认为查看查询使用聚簇索引是一件好事。我认为在索引覆盖的查询中使用的非聚集索引扫描或搜索在聚簇索引(没有聚簇索引的表)上与聚簇索引一样好,并且优于聚簇索引扫描或搜索。我还认为聚集索引是一个引导人们对事物进行各种假设的名称(首先,它不是表上的索引,它表明表完全存储在索引结构中)和误解关于它的重要性。在非常大的操作中,聚簇索引是最重要的,其中按照聚类的顺序需要大量数据。
典型OLTP查询的实际(读取)查询速度来自于查询中所有表中包含最窄的非聚集索引的查询,每个列都以适当的顺序排列,并为查询/参数指定正确的排序方向。
答案 1 :(得分:3)
您绝对可以在主键中创建非聚集索引。
但是,我认为你有点倒退了。
电子邮件地址将成为一个特别糟糕的聚集索引,因为它本身并不是有序的。随着表的增长,由于页面拆分,重新排序等原因,您将失去INSERT
性能。
正如@Cade Roux所说,我会将autonum作为聚集索引,在电子邮件地址上强制执行唯一性。
编辑:聚集索引表示数据物理存储在磁盘上的方式。非顺序聚簇索引会损害INSERT
性能,因为必须重新排序数据(导致页面拆分)。
对于用户表中扫描单行,您可能会发现群集和非群集索引之间的差异可以忽略不计。但是,根据@gbn发布的优秀链接,您可能在范围选择上具有更好的性能,因为数据是连续的。尽管如此,我个人必须真正思考为聚簇索引使用字符串(或任何固有的无序数据)的决定。
EDIT2:我能想到的一个例外情况是,如果您通常按字母顺序通过电子邮件地址选择用户块...您仍然会有较慢的INSERT
但是你应该能够更快地检索这些分组...正如@Cade Roux在评论中所说的那样:你应该不期望单行SELECT
由于聚集而更高效指数。
答案 2 :(得分:2)
是的,你可以。创建表时,请设置如下列:
CREATE TABLE Members
(
ID INT NOT NULL IDENTITY(10000,1),
Email Varchar(200) NOT NULL CONSTRAINT pk_Members PRIMARY KEY NONCLUSTERED,
Otherstuff ...
)
CREATE CLUSTERED INDEX cdx_Members ON Members(ID)