堆
创建一个没有任何索引的表并向其中插入数据的时候,SQL Server会搜索未被使用的页来存储这些数据。为了追踪哪些页保存了这个表的数据,SQL Server会为每一个表设立一个或多个IAM (索引分配映射)页。这些IAM页指向保存表数据的页。这个表的数据以无索引的方式存储在页上,并且只是通过IAM页联系在一起,所以这个表被称作堆
表扫描
SQL Server必须通过阅读这个表的IAM页并且通过扫描IAM页指向的所有页来访问一个堆的数据。这种操作称为表扫描。
在表没有索引的时候,SQL Server会使用表扫描来访问表。这种扫描迫使SQL Server扫描所有的数据
聚集索引
是一种特殊的平衡树。这种平衡树与前面的平衡树相比,差别在于索引的叶子级。在聚集索引中,叶子级并不包括索引键和指针;它们就是数据本身。这个差异意味着数据并不存储在堆结构中。它们存储在索引的叶子级,并按索引键进行排序。这种设计具有两个优点:
SQL Server不需要依据指针来访问数据。数据直接存储在索引中。
数据依据索引键排序,这是主要的优点。无论什么时候,只要SQL Server需要依据索引键排序数据,都不必再执行排序操作,因为数据已经排好序了。
由于数据包含在聚集索引之中,因此只能为每个表定义一个聚集索引。
非聚集索引
并不在索引的叶子级包含所有数据行。相反,它在叶子级包含所有键列和指向表中行的指针。指针的编写及使用方式取决于表是一个堆还是一个有聚集索引的表。
a)堆
如果表没有聚集索引,SQL Server将在非聚集索引的叶子级存储一个指向物理行的指针(文件id、页id合页中的行id)。在这种情况下,SQL Server通过查询索引进而依据指针指向来获取行的方式查找一个特定的行。
b)聚集索引
当一个聚集索引存在的时候,SQL Server会在非聚集索引的叶子级将此行的聚集索引的键存储为指针。如果SQL Server要根据非聚集索引获取一行,会在非聚集索引中进行查找,找出合适的聚集键,然后再通过聚集索引来获取行。
索引扫描
读取表中的所有数据,通过索引的叶子级所进行的扫描。由于第一个SELECT语句没有WHERE子句,因此SQL Server知道需要获取所有数据,这些数据存储在索引的叶子级上。
索引查找
SQL Server查找特定值的一个操作。这个操作起始于索引的根并将查询值传递给索引的分支以进行查询。
这两个操作同样可以组合起来获取一个特定范围的数据。在这种局部扫描操作中,SQL Server会首先找到范围的起始值,然后持续扫描到范围的终点值结束。
对于经常需要进行排序的列,最好为其定义聚集索引
包含性索引
在使用非聚集索引的时候,SQL Server并不总是需要在第二个步骤获取整个数据行。这种情形发生在非聚集索引包括SQL Server执行操作所需的所有表数据(所有投影相关的列都在聚焦索引或非聚焦索引当中)的时候。此时,便将这个索引称为包含性索引,因为它包含整个查询。包含索引可以极大地加速查询,正如前一个示例的两个执行计划中一样。在这些查询中,获取实际数据行的操作占有整个查询开销的97%。换一句话说,如果没有这个操作,查询速度将提高32倍。
当查询中的所有列都作为键列或非键列包含在索引中时,带有包含性非键列的索引可以显著提高查询性能。这样可以实现性能提升,因为查询优化器可以在索引中找到所有列值;不访问表或聚集索引数据,从而减少磁盘 I/O 操作。
1、 详明说明在堆结构、聚焦索引和非聚焦索引之上的检索的差异:20分
答: (从定义/索引构建方式,检索过程,效率上进行分别分析比较)
1) 所谓堆,是指数据以无索引的方式存储在页上,并且只是通过指向保存表数据页的IAM(索引分配映射)页联系在一起的数据表。
SQL Server在堆结构上的检索必须通过阅读这个表的IAM页,并且扫描IAM页指向的所有页来访问一个堆的数据。这种操作称为表扫描。表扫描以无序的方式读取所有数据。如果一个查询要搜索一个特定的行,那么一个堆的表扫描必须读取表中的所有行来找到它。
在非常大的表中,表扫描会花费很长的时间,此时的堆结构的检索是效率非常低下的操作。
2) 聚焦索引是一种特殊的平衡树,这种平衡树的叶子级并不包括索引键和指针,它们就是数据本身。也就是说,数据本身并不存储在堆结构中,而是存储在索引叶子级上,并按索引键进行排序,对于经常需要进行排序的列,最好为其定义聚集索引。
所以,SQL Server在聚焦索引上检索不需要依据指针来访问数据,而且,无论什么时候,SQL Server需要依据索引键排序,都不必再执行排序操作。
由于数据不再存储在堆结构中,因此SQL Server执行了索引操作,执行计划表将使用索引扫描和索引查找这两上主要的索引操作。
由于数据包含在聚焦索引中,因此只能为每个表定义一个聚焦索引。
3) 非聚焦索引也是一种特殊的平衡树,但是,与聚焦索引相比,非聚焦索引并不索引的叶子级包含所有数据行。相反,它在叶子级包含所有键列和指向表中行的指针。指针的编写及指用方式取决于表是一个堆还是一个有聚焦索引的表。
如果表没有聚集索引,SQL Server会在非聚集索引的叶子级存储一个指向物理行的指针。SQL Server通过查询索引进而依据指针指向来获取行的方式查找一个特定的行。
如果表有聚集索引,SQL Server会在非聚集索引的叶子级将此行的聚集索引的键存储为指针。若SQL Server要根据非聚集索引获取一行,则会在非聚集索引中进行查找,找出合适的聚集键,然后再通过聚集索引来获取行。
由于非聚焦索引并不包括整个数据行,因此在一个表上可以建立多达249个的非聚焦索引。
聚焦索引和非聚焦索引是SQL Server的两种类型地索引,由于数据不再存储在堆结构中,因此执行了索引操作,而不再使用表扫描,可以快速地查找指定的数据,大大的提高数据访问的性能。
2、 索引扫描和索引查找两者之间的差异:10分
答:[ 扫描与查找操作均是SQL Server从表或索引中读取数据采用的迭代器,这些也是SQL Server支持的最基本的运算。索引是整个页级上进行处理,扫描是在整张表上进行处理,而查找则返回特定谓词上一个或多个范围内的数据行。]
索引扫描 读取表中的所有数据,因为这些数据存储在索引的叶子级上,所以索引扫描是通过索引的叶子级所进行的扫描。
索引查找 SQL Server查找特定值的一个操作。这个操作起始于索引的根并将查询值传递给索引的分支进行查询。
3、 在 ms sqlserver中有一订单表定义如下:20分
CREATE TABLE dbo.Orders(
SalesOrderID int not NULL
OrderDate datetime not NULL
ShipDate datetime NULL
Status tinyint not NULL
PurchaseOrderNumber dbo.OrderNumber NULL
CustomerID int not NULL
ContactID int not NULL
SalesPersonID int NULL
);
假设 SalesOrderID 为主键,则下列(A)和(B)两个查询语句的估计执行计划会有什么不同,为什么?
(A) SELECT DISTINCT SalesOrderID, CarrierTrackingNumber FROM dbo.OrderDetails WHERE ProductID = 776
(B) SELECT DISTINCT SalesOrderID FROM dbo.OrderDetails WHERE ProductID = 776
答:(如果没有建非聚焦索引,两种查询的估计执行计划差不多)
因为对于A查询,SQL Server需要SalesOrderID,CarrierTrackingNumber和ProductID列。由于以前创建的非聚集索引NCLIX_OrderDetails_ProductID创建在ProductID列上,因此它包括了这个列。同时,由于SalesOrderID列是聚集索引的键,因此它还包括了SalesOrderID列。所以,SalesOrderID是SQL Server在非聚集索引上使用的指针。因此SQL Server只能通过查找聚集索引获取数据的方式获取CarrierTrackingNumber。
对于B查询, TrackingNumber列没有被选择,由于索引包含查询,因此SQL Server不需要访问聚集索引来获取数据。而为每一个行访问聚集索引的开销很大,因此B查询只占用了这一批整个开销的极小部分(1%)。与第一个查询所需的(709次)页读操作相比,对于包含性查询,SQL Server只进行了极少的(两页)读操作。
在堆结构 聚焦和非聚焦索引差异 4,5,6章
索引扫描和索引查找两者之间的差异 6.2.2 http://book.csdn.net/bookfiles/121/1001214195.shtml
salesOrderID 最后例子6
两个估计执行之间的区别 包含性索引
案例,理由,E-R图,表结构