3

如果我按顺序在 [lastName] 和 [firstName] 两列上创建了一个索引。如果我然后进行查询以查找名字为 daniel 的人数:

SELECT count(*)
FROM people
WHERE firstName = N'daniel'

此搜索是否会在第一个索引 (lastname) 的每个部分中搜索并使用二级索引 (firstName) 快速搜索 LastName 条目的每个块?

这似乎是一件显而易见的事情,我认为这就是发生的事情,但你知道他们对假设的看法。

4

2 回答 2

4

是的,如果查询优化器认为“快速搜索 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 ...

在此处输入图像描述

于 2012-08-02T08:58:00.313 回答
2

如果您按此顺序在(姓氏,名字)上有索引,则查询如下

WHERE firstname = 'daniel'

只要您不在WHERE子句中包含复合索引的第一列(即姓氏),就不会使用索引。为了有效地仅搜索名字,您需要在该列上建立一个单独的索引。

如果您经常在两列上搜索,请执行 2 个单独的单列索引。但请记住,每个索引都会在插入/更新时更新,因此会影响性能。

此外,如果复合索引没有同时覆盖索引,请避免使用它们。有关复合索引的提示,请参阅 sql-server-performance.com 上的以下文章:

优化 SQL Server 复合索引的技巧

更新(以解决反对者):

在这种特定情况下,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 给出的磁盘上顺序数据对齐的优势.

于 2012-08-02T08:31:51.193 回答