创建索引时如何选择列?
How to choose columns when creating index?
这似乎是一个奇怪的问题。我知道 sql 服务器中的不同类型的索引(集群的、非集群的、唯一的、过滤的、包含列的索引...等)并且我知道如何创建它们。我也知道索引取决于查询,但我不知道是谁在创建索引时选择列。例如,假设一个简单的网站允许用户 post 文本和图像。该网站有一个简单的两个 table 如图所示:
在网站中获取用户的查询是:
Select UserID,UserName from User where Email='something' and Password='something'
假设我想为此 table 创建索引,我应该在创建索引时包含哪些列?我知道不同类型的索引可能包含不同的列,但是在创建聚集或非聚集时我可以决定应该选择哪些列。我看到一些索引示例几乎总是选择 where 子句之后的列。这是真的吗?
获取用户 posts 的查询是:
Select * from Posts where UserID='something'
此查询与第一个查询不同。此查询可能 return 多行,而第一个查询始终 return 一行。现在同样的问题,如何选择列?
我想说的是:
时如何选择列
- 正在创建聚簇索引。
- 正在创建非聚集索引。
- 创建包含列的非集群。
上面的例子只是为了说明题意。目标不是为示例中的两个查询找到一个好的索引,而是想出一个可以用来帮助创建索引时选择列的基础。
在完美世界中,您希望索引出现在 WHERE
子句或 JOIN
条件中的列。在您的情况下,它将是 Email
和 Password
列。
因此您可以在用户 table 以及电子邮件和密码上使用非聚集索引。
差不多这个索引:
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,它们不包含在您的索引中,因此,您的查询将执行 Key Lookup(它将在创建的索引中查找记录并回头查看您的 dbo.User
table 来查找 SELECT 语句(用户 ID 和用户名)的匹配值。为避免这种情况,您可以使用 INCLUDED
列创建索引以删除键查找(您会想要这样做)。
CREATE NONCLUSTERED INDEX idx_User_Email_Password
ON dbo.User (Email, Password)
INCLUDE (UserID, UserName);
使用这个索引,您将在您的执行计划中有一个很好的 NON CLUSTERED INDEX 查找。
此外,选择索引列的顺序很重要。比方说,您的 table 将包含 UserTypeID(数量不多)。因此,您将传递一些特定的 UserTypeID 和 UserID 列表,然后 SQL 服务器可能想要选择一个索引,该索引将 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,它将查找您的聚簇索引(我们将 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';
正如我所说,它使用创建的索引并进行密钥查找,它找到匹配的电子邮件和密码,并找到 table 中的其余列以输出它们(P.S。如果您要输出,比方说,只有电子邮件,它不会进行密钥查找,也不需要):
现在让我们使用包含的用户名和上面的 运行 查询创建索引。正如我之前告诉您的那样,它将使用普通的非聚集索引查找生成这个很好的执行计划:
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/
我更愿意
在电子邮件上创建非聚集索引,密码可以是包含的列
并在 UserId 上创建聚集索引,这可能是一个自动增量列
这似乎是一个奇怪的问题。我知道 sql 服务器中的不同类型的索引(集群的、非集群的、唯一的、过滤的、包含列的索引...等)并且我知道如何创建它们。我也知道索引取决于查询,但我不知道是谁在创建索引时选择列。例如,假设一个简单的网站允许用户 post 文本和图像。该网站有一个简单的两个 table 如图所示:
在网站中获取用户的查询是:
Select UserID,UserName from User where Email='something' and Password='something'
假设我想为此 table 创建索引,我应该在创建索引时包含哪些列?我知道不同类型的索引可能包含不同的列,但是在创建聚集或非聚集时我可以决定应该选择哪些列。我看到一些索引示例几乎总是选择 where 子句之后的列。这是真的吗?
获取用户 posts 的查询是:
Select * from Posts where UserID='something'
此查询与第一个查询不同。此查询可能 return 多行,而第一个查询始终 return 一行。现在同样的问题,如何选择列?
我想说的是:
时如何选择列- 正在创建聚簇索引。
- 正在创建非聚集索引。
- 创建包含列的非集群。
上面的例子只是为了说明题意。目标不是为示例中的两个查询找到一个好的索引,而是想出一个可以用来帮助创建索引时选择列的基础。
在完美世界中,您希望索引出现在 WHERE
子句或 JOIN
条件中的列。在您的情况下,它将是 Email
和 Password
列。
因此您可以在用户 table 以及电子邮件和密码上使用非聚集索引。
差不多这个索引:
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,它们不包含在您的索引中,因此,您的查询将执行 Key Lookup(它将在创建的索引中查找记录并回头查看您的 dbo.User
table 来查找 SELECT 语句(用户 ID 和用户名)的匹配值。为避免这种情况,您可以使用 INCLUDED
列创建索引以删除键查找(您会想要这样做)。
CREATE NONCLUSTERED INDEX idx_User_Email_Password
ON dbo.User (Email, Password)
INCLUDE (UserID, UserName);
使用这个索引,您将在您的执行计划中有一个很好的 NON CLUSTERED INDEX 查找。
此外,选择索引列的顺序很重要。比方说,您的 table 将包含 UserTypeID(数量不多)。因此,您将传递一些特定的 UserTypeID 和 UserID 列表,然后 SQL 服务器可能想要选择一个索引,该索引将 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,它将查找您的聚簇索引(我们将 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';
正如我所说,它使用创建的索引并进行密钥查找,它找到匹配的电子邮件和密码,并找到 table 中的其余列以输出它们(P.S。如果您要输出,比方说,只有电子邮件,它不会进行密钥查找,也不需要):
现在让我们使用包含的用户名和上面的 运行 查询创建索引。正如我之前告诉您的那样,它将使用普通的非聚集索引查找生成这个很好的执行计划:
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/
我更愿意 在电子邮件上创建非聚集索引,密码可以是包含的列 并在 UserId 上创建聚集索引,这可能是一个自动增量列