SQL Server 2005从入门到精通

本文介绍了SQLServer数据库中堆结构的基本概念,包括数据文件的分页机制、堆表的存储方式及其对查询性能的影响。通过具体示例展示了如何创建堆表、执行查询以及观察其执行计划。
SQL Server数据库中的一个数据文件会以8KB大小分页。每一页可以包括数据、索引、或者其他SQL Server需要为其维护数据文件的数据类型。然而,大多数的页是数据页或者索引页。页是SQL Server读、写数据文件的单元。每一页只包括一个数据对象的数据或索引信息。所以,在每一个数据页上,只能找到一个对象的数据。同样地,在一个索引页上,也只能找到一个索引的信息。在SQL Server 2000中,将一个数据行分别存储在不同页上是不可能的,这意味着一个数据行必须在一页上,这会导致数据行有8 060字节的大小限制(大型对象数据除外)。在SQL Server 2005中,对于变长数据类型,例如nvarchar,varbinary,CLR等,这个限制不复存在。对于变长数据类型,数据行可以跨越几个页,但是对于定长数据类型,一个数据行依然必须存储在一页上。
创建一个没有任何索引的表并向其中插入数据的时候,SQL Server会搜索未被使用的页来存储这些数据。为了追踪哪些页保存了这个表的数据,SQL Server会为每一个表设立一个或多个IAM (索引分配映射)页。这些IAM页指向保存表数据的页。这个表的数据以无索引的方式存储在页上,并且只是通过IAM联系在一起,所以这个表被称作堆。SQL Server必须通过阅读这个表的IAM并且通过扫描IAM指向的所有页来访问一个堆的数据。这种操作称为表扫描。表扫描以无序的方式读取所有数据。如果一个查询要搜索一个特定的行,那么一个堆的表扫描必须读取表中的所有行来找到它,这是一种非常低效的操作。
Ø       检验结构
1.    打开SQL Server Management Studio。打开一个“新建查询”窗口并更改数据库上下文为“AdventureWorks”。
2.    在以下示例中,将创建两个表,分别为dbo.Orders 和 dbo.OrderDetails。键入并执行以下语句来创建表并为其添加数据。此示例的完整代码包含在示例文件Examining Heap Structures.sql中。
 
USE AdventureWorks
GO
 
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
    );
 
CREATE TABLE dbo.OrderDetails(
    SalesOrderID int NOT NULL,
    SalesOrderDetailID int NOT NULL,
    CarrierTrackingNumber nvarchar(25),
    OrderQty smallint NOT NULL,
    ProductID int NOT NULL,
    UnitPrice money NOT NULL,
    UnitPriceDiscount money NOT NULL,
    LineTotal AS (isnull((UnitPrice*((1.0)-UnitPriceDiscount))*OrderQty,(0.0)))
    );
 
INSERT INTO dbo.Orders
SELECT SalesOrderID, OrderDate, ShipDate, Status, PurchaseOrderNumber,
    CustomerID, ContactID, SalesPersonID
FROM Sales.SalesOrderHeader;
 
INSERT INTO dbo.OrderDetails(SalesOrderID, SalesOrderDetailID, CarrierTrackingNumber,
OrderQty,
    ProductID, UnitPrice, UnitPriceDiscount)
SELECT SalesOrderID, SalesOrderDetailID, CarrierTrackingNumber,OrderQty,
    ProductID, UnitPrice, UnitPriceDiscount
FROM Sales.SalesOrderDetail;
 
3.    现在创建了两张堆结构的表。键入以下语句来查询dbo.Orders表。在执行之前按“Ctrl+M”或在“查询”菜单中选择“包括实际的执行计划”来包括实际的执行计划。然后执行这个查询。
 
SET STATISTICS IO ON;
 
SELECT * FROM dbo.Orders
 
SET STATISTICS IO OFF
 
       SET STATISTICS IO选项会打开一个特性,使SQL Server将语句执行期间I/O操作的有关信息发回给用户。这是一个用于判断查询I/O开销的极好特性。
4.    切换到“消息”选项卡。您会看到与图6.3相似的信息。
       输出信息表明SQL Server需要对表中的数据进行一次扫描并需要为此操作执行178页的读操作(逻辑读)。输出信息同样表明,为了执行此操作没有用到物理读(物理读或者物理先读)。没有物理读的原因是,在此例中,数据已经保存在缓存中。如果您的信息窗口表明对于这个查询进行了物理读,那么在再次执行此查询之后您会看到物理读的数量会比上次执行时少了。因为SQL Server会将最近访问的数据页保存在缓冲中以提高性能。
图6.3  “消息”选项卡
5.    切换到“执行计划”选项卡。在执行计划中,如图6.4所示,可以看出,SQL Server使用一次表扫描操作来访问数据,这是惟一的选择。
图6.4  使用表扫描操作来访问数据
6.    现在对这个查询稍作修改以获取特定的行。
 
SET STATISTICS IO ON;
 
SELECT * FROM dbo.Orders
WHERE SalesOrderID =46699;
 
SET STATISTICS IO OFF;
 
7.    检查输出的消息和图形化的执行计划。,可以看出SQL Server仍然需要为此查询读取178页并使用表扫描。使用表扫描是因为SQL Server没有索引可用,因此只能在表中扫描所有的数据来找到需要查找的行。
       可以看出,在表没有索引的时候,SQL Server会使用表扫描来访问表。这种扫描迫使SQL Server扫描所有的数据,全然不顾表的大小。在非常大的表中,表扫描会花费很长的时间。
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值