如果我按顺序在 [lastName] 和 [firstName] 两列上创建了一个索引。如果我然后进行查询以查找名字为 daniel 的人数:
SELECT count(*)
FROM people
WHERE firstName = N'daniel'
此搜索是否会在第一个索引 (lastname) 的每个部分中搜索并使用二级索引 (firstName) 快速搜索 LastName 条目的每个块?
这似乎是一件显而易见的事情,我认为这就是发生的事情,但你知道他们对假设的看法。
如果我按顺序在 [lastName] 和 [firstName] 两列上创建了一个索引。如果我然后进行查询以查找名字为 daniel 的人数:
SELECT count(*)
FROM people
WHERE firstName = N'daniel'
此搜索是否会在第一个索引 (lastname) 的每个部分中搜索并使用二级索引 (firstName) 快速搜索 LastName 条目的每个块?
这似乎是一件显而易见的事情,我认为这就是发生的事情,但你知道他们对假设的看法。
是的,如果查询优化器认为“快速搜索 LastName 条目的每个块”比(执行Full Scan ) 的表。
虽然对于这个特定的查询,一个索引(firstName)
会更有效,所以如果有这样一个索引,SQL-Server 将使用那个索引(并做一个Index Seek)。
在 SQL-Server 2008 R2,Express 版中测试:
CREATE TABLE Test.dbo.people
( lastName NVARCHAR(30) NOT NULL
, firstName NVARCHAR(30) NOT NULL
) ;
INSERT INTO people
VALUES
('Johnes', 'Alex'),
... --- about 300 rows
('Johnes', 'Bill'),
('Brown', 'Bill') ;
查询没有任何索引,表扫描:
SELECT count(*)
FROM people
WHERE firstName = N'Bill' ;
使用索引查询(lastName, firstName)
,索引扫描:
CREATE INDEX last_first_idx
ON people (lastName, firstName) ;
SELECT ...
使用 index on 查询(firstName)
,Index Seek:
CREATE INDEX first_idx
ON people (firstName) ;
SELECT ...
如果您按此顺序在(姓氏,名字)上有索引,则查询如下
WHERE firstname = 'daniel'
只要您不在WHERE
子句中包含复合索引的第一列(即姓氏),就不会使用索引。为了有效地仅搜索名字,您需要在该列上建立一个单独的索引。
如果您经常在两列上搜索,请执行 2 个单独的单列索引。但请记住,每个索引都会在插入/更新时更新,因此会影响性能。
此外,如果复合索引没有同时覆盖索引,请避免使用它们。有关复合索引的提示,请参阅 sql-server-performance.com 上的以下文章:
更新(以解决反对者):
在这种特定情况下,SELECT Count(*)
索引是一个覆盖索引(正如@ypercube 在评论中指出的那样),因此优化器可以选择它来执行。在这种情况下使用索引意味着一个Index Scan
而不是一个Index Seek
。
做一个Index Scan
意味着扫描索引中的每一行。如果索引包含的行数少于整个表,这将更快。因此,如果您有一个高度选择性的索引(具有许多唯一值),您将获得一个包含与表本身一样多的行的索引。Clustered Index Scan
在这种情况下,执行 a (意味着表上的 PK,迭代 PK)或 a Non-Clustered Index Scan
(迭代索引)通常不会有太大区别。A Table Scan
(如@ypercube 答案的屏幕截图所示)意味着表上没有 PK,这导致执行速度比 a 还要慢Clustered Index Scan
,因为它不具有 PK 给出的磁盘上顺序数据对齐的优势.