我们将需要有关您的查询表示例的更多信息来完全解决这个问题,但是:
- DateTime 列本身应该具有高度选择性,因此以
TimeOperation
第一列作为索引的索引应该解决针对TimeOperation
.
- 不要盲目地将所有列添加到索引中,甚至不要添加到包含的索引中 - 这会使索引页面密度变差并且适得其反(您将在索引中复制表)。
- 如果您的数据库中的所有数据都以 为中心
TimeOperation
,您可能会考虑围绕它构建聚集索引。
- 如果您有查询,
field1 = x
那么您需要一个单独的索引field1
(假设它具有适当的选择性),即TimeOperation
如果它不在查询的 WHERE 子句中,则在索引上没有。
- 是的,你是对的,当 SQL 在索引中找到一条记录时,它需要在集群中进行键(或 RID)查找以检索其余列。如果您的非聚集索引在您的语句中包含其他列
select
,则可以避免查找。但由于您使用的是 SELECT(*),因此覆盖索引不太可能有帮助。
编辑
解释 - 选择性和密度在这里详细解释。例如,如果您的查询仅TimeOperation
返回少量行(经验法则是 < 5%,但并非总是如此),是否会使用索引,即您的查询具有足够的选择性,让 SQL 可以在TimeOperation
.
基本出发点是:
CREATE TABLE [MyTable]
(
intID INT ID identity(1,1) NOT NULL,
field1 NVARCHAR(20),
-- .. More columns, which may be selected, but not filtered
TimeOperation DateTime,
CONSTRAINT PK_MyTable PRIMARY KEY (IntId)
);
基本指标为
CREATE NONCLUSTERED INDEX IX_MyTable_1 ON [MyTable](TimeOperation);
CREATE NONCLUSTERED INDEX IX_MyTable_2 ON [MyTable](Field1);
聚类考虑/选项
如果您的大部分记录以“串行”升序 TimeOperation 顺序插入,即 intId 和 TimeOperation 将同时增加,那么我会将集群保留在 intID 上(默认值)(即表 DDL 是PRIMARY KEY CLUSTERED (IntId)
,无论如何这是默认值)。
但是,如果和之间没有相关性,并且如果您的大多数查询都是这种形式,则(并将 PK 更改为将避免书签查找)。更好的是,如果保证 的值是唯一的,那么将提高密度,因为它将避免使用唯一符。IntId
TimeOperation
SELECT * FROM [MyTable] WHERE TimeOperation between xx and yy
CREATE CLUSTERED INDEX CL_MyTable ON MyTable(TimeOperation)
PRIMARY KEY NONCLUSTERED (IntId)
TimeOperation
CREATE UNIQUE CLUSTERED INDEX CL_MyTable ON MyTable(TimeOperation)
注意- 对于这个答案的其余部分,我假设你IntId
和TimeOperations
ARE 高度相关,因此聚类是 by IntId
。
覆盖索引
正如其他人所提到的,您的使用SELECT (*)
是不好的做法,尤其是覆盖索引没有任何用处(例外是COUNT(*)
)。如果您的查询不是 SELECT(*),而是例如
SELECT TimeOperation, field1
FROM
WHERE TimeOperation BETWEEN x and y -- and returns < 5% data.
然后更改您的索引TimeOperation
以包含field1
CREATE NONCLUSTERED INDEX IX_MyTable ON [MyTable](TimeOperation) INCLUDE(Field1);
或将两者都添加到索引中(首先使用最常见的过滤器,或者如果始终存在两个过滤器,则首先使用最有选择性的过滤器)
CREATE NONCLUSTERED INDEX IX_MyTable ON [MyTable](TimeOperation, Field1);
要么将避免摆脱/关键查找。第二个 (,) 选项将解决您在 WHERE 或 HAVING 子句中过滤 TimeOperation 和 Field1 的查询。
Re: (TimeOperation, Field1) 上的索引和单独的索引有什么区别?
例如
CREATE NONCLUSTERED INDEX IX_MyTable ON [MyTable](TimeOperation, Field1);
对查询没有用
SELECT ... FROM MyTable WHERE Field1 = 'xyz';
该索引仅对具有 TimeOperation 的查询有用
SELECT ... FROM MyTable WHERE TimeOperation between x and y;
或者
SELECT ... FROM MyTable WHERE TimeOperation between x and y AND Field1 = 'xyz';
希望这可以帮助?