这似乎是一个奇怪的问题。我知道sql server中的不同类型的索引(集群,非集群,唯一,过滤,包含列的索引......等),我知道如何创建它们。另外我知道索引取决于查询,但我不知道在创建索引时谁选择列。例如,假设一个允许用户发布文本和图像的简单网站。该网站有一个简单的两个表格,如图所示:
获取网站用户的查询是:
Select UserID,UserName from User where Email='something' and Password='something'
假设我想为这个表创建索引,我应该在创建索引时包含哪些列?我知道不同类型的索引可能包含不同的列,但我可以决定何时创建聚簇或非聚簇应选择哪些列。我看到一些索引的例子几乎总是在where子句之后选择列。这是真的吗?
获取用户帖子的查询是:
Select * from Posts where UserID='something'
此查询与第一个查询不同。此查询可能返回多行,而第一行将始终返回一行。现在同样的问题,如何选择列?
我想说的是如何在以下时间选择列:
上面的例子只是为了说明问题的想法。目标不是为示例中的两个查询找到一个好的索引,而是想出一个可以在创建索引时帮助选择列的基础。
答案 0 :(得分:25)
在完美世界中,您希望对列在WHERE
子句或JOIN
条件中的列进行索引。在您的情况下,它将是Email
和Password
列。
因此,你可以在用户表和电子邮件和密码上找到非聚集索引。
这个指数差不多:
CREATE NONCLUSTERED INDEX idx_User_Email_Password
ON dbo.User (Email, Password);
因此,如果您将运行此查询:
SELECT UserID, UserName
FROM User
WHERE Email = 'something'
AND Password = 'something';
您将最终使用刚刚创建的索引(最有可能)或聚集索引,它将寻求通过它。但是,您的查询选择了未包含在索引中的UserID和UserName,因此,您的查询将执行密钥查找(它将在创建的索引中查找记录,并将回顾您的dbo.User
表查找SELECT语句的匹配值(UserID和UserName)。为避免这种情况,您可以使用INCLUDED
列创建索引以删除密钥查找(您可能希望这样做)。
CREATE NONCLUSTERED INDEX idx_User_Email_Password
ON dbo.User (Email, Password)
INCLUDE (UserID, UserName);
使用此索引,您的执行计划中将有一个很好的非聚集索引查找。
此外,选择索引列的顺序。比方说,你的表将包含UserTypeID(它们中没有很多)。因此,您将传递一些特定的UserTypeID和一个UserID列表,然后SQL Server可能希望选择一个索引,其中UserTypeID作为第一个索引列。
所以有些测试:
CREATE TABLE #Users
(
UserId INT
, UserName VARCHAR(500)
, Email VARCHAR(500)
, Password VARCHAR(500)
);
CREATE CLUSTERED INDEX idx_Users_UserID
ON #Users (UserID);
-- Some test data from my DB
INSERT INTO #Users (UserId, UserName, Email, Password)
SELECT TOP (10000) UserId, UserName, Email, 'password'
FROM Users;
所以这是查询:
SELECT *
FROM #Users;
这将执行索引扫描,因为我们没有指定任何细节。
现在,如果我们指定UserId,它将搜索您的Clustered索引(我们将UserId作为键):
SELECT *
FROM #Users
WHERE UserID = 602;
现在让我们创建索引而不包含列并查询:
CREATE NONCLUSTERED INDEX idx_Users_Email_Password
ON #Users (Email, Password);
SELECT *
FROM #Users
WHERE Email = 'k0641088@kingon.a.uk';
正如我所说,它使用创建的索引并执行密钥查找,它找到匹配的电子邮件和密码,并找到表中的其余列以输出它们(PS如果您要输出,请说,只有电子邮件,它不会进行密钥查找,也不需要):
现在让我们使用包含的UserName创建索引并运行上面的查询。正如我之前告诉你的那样,它将使用简单的NonClustered Index搜索产生这个很好的执行计划:
CREATE NONCLUSTERED INDEX idx_Users_Email_Password_iUserName
ON #Users (Email, Password)
INCLUDE (UserName);
这是一篇高质量的文章,我建议阅读它:https://www.simple-talk.com/sql/performance/index-selection-and-the-query-optimizer/
答案 1 :(得分:0)
我更愿意 在电子邮件上创建非聚集索引,密码可以是包含的列 并在UserId上创建一个聚簇索引,这可能是一个自动增量列