最好的wordpress网站,做良心网站,易点科技网站建设,网站运营托管协议【译注#xff1a;此文为翻译#xff0c;由于本人水平所限#xff0c;疏漏在所难免#xff0c;欢迎探讨指正】 原文链接#xff1a;传送门。 在之前的章节中#xff0c;我们在有索引和没有索引的情况下执行同一个查询#xff0c;比较了各自需要的工作。我们的最主要的评… 【译注此文为翻译由于本人水平所限疏漏在所难免欢迎探讨指正】 原文链接传送门。 在之前的章节中我们在有索引和没有索引的情况下执行同一个查询比较了各自需要的工作。我们的最主要的评判标准是“逻辑读”。我们总是比较查询聚集索引表所需要的读与查询无索引表所需要的逻辑读。现在是时候解释为什么逻辑读是比较合适的标准同时我们也会解释实际上读了什么。 当你向SQL SERVER提交一个请求信息的申请它知道通过扫描整张表总是能够满足那个查询SQL SERVER理解仅当如果使用索引比表扫描做更少的工作时索引才对查询是有益的。如果你问SQL SERVER是什么工作它的回答首先便是磁盘IO。一个查询所需要的磁盘IO是这个查询消耗的良好体现最主要的原因在于IO消耗了两种关键资源时间和内存。 扫描整张表所需要的IO是一个总是被误解的标准其原因在于SQL SERVER并不是按行读取它读取的是页。而读取页和读取行是完全不同的工作单元。 这个章节会尽可能的短因为我们只关注于SQL SERVER如何执行IO。理解SQL SERVER IO对于我们理解为什么一些索引有益于查询而另一些并没有益处是很有必要的也可以理解为什么一些数据更新会比其他的执行得更快些以及为什么一些索引维护任务比其他会需要更少的时间。简而言之对于SQL SERVER IO的基本理解对于理解本系列的后续章节是很有必要的。 页 当你创建一个数据库时你指定了你的数据库被定位的文件SQL SERVER把各个文件看做是长长的字节字符串它在逻辑上而不是物理上将文件分割成8K大小的块。这些8K大小的块成为页。因此文件的第一个8K大小的字节块就是页#0下一个8K是页#1如此等等页是最小的IO单元每次IOSQL SERVER只是读写一个页如果多个连续的页需要读或者写SQL SERVER选择在一个单独的IO中来处理它们。 页不仅仅是IO的最小单位它还是所有关系的最小单位也就是说如果一个页包含了表A的行那么它将只包含表A的行反之如果它包含了非聚集索引B的一个条目它将只会包含非聚集索引B的条目除了数据之外每个页都包含了一些头信息及偏移指针用以帮助SQL SERVER来定位到页中的各个行数据或者条目。 在前面的章节中我们展示了几张图片来演示索引条目的顺序而没有管它是聚集索引或者非聚集索引接下来我们对其中的一个图片进行扩展展示SalesOrderDetail 表的聚集索引来反映页的概念。 SalesOrderID SalesOrderDetailID ProductID OrderQty UnitPricePage n-1:
43668 106 722 3 178.58
43668 107 708 1 20.19Page n:
43668 108 733 3 356.90
43668 109 763 3 419.46
43669 110 747 1 714.70
43670 111 710 1 5.70
43670 112 709 2 5.70
43670 113 773 2 2,039.99
43670 114 776 1 2,024.99
43671 115 753 1 2,146.96
43671 116 714 2 28.84
43671 117 756 1 874.79Page n1:
43671 118 768 2 419.46
43671 119 732 2 356.90
43671 120 763 2 419.46
43671 121 755 2 874.79
43671 122 764 2 419.46
43671 123 716 1 28.84
43671 124 711 1 20.19
43671 125 708 1 20.19
43672 126 709 6 5.70
43672 127 776 2 2,024.99Page n2:
43672 128 774 1 2,039.99
43673 129 754 1 874.79
43673 130 715 3 28.84
43673 131 729 1 183.94 页的逻辑顺序和物理顺序没有必要是一样的。上图展示的示例数据是第nn1n2页但实际上可能是nn9n-5 and n2。这种逻辑顺序和物理顺序的偏差称为外部碎片。一个页内空闲容量的百分比称为页的内部碎片。在后续章节中我们会详细查看两种类型碎片的原因影响及防范。 同样也没有要求每个页包含一样的行数通常在聚集索引表上常规的添加及删除操作会导致每个页包含类似的行数更正确的说各个页大约包含相同的字节数如果数据行或者属于条目包含可变长的列那么每页的行数可能会变化尽管每页的字节数保持稳定。 一个数据行的大小等于它的列的大小加上行开销。行开销的数据取决于好多个因素可总结 如下 每行6个字节存储状态信息和长度信息。 每个确定宽度的列一个bit包括进最近的字节。 如果存在任何可变长度的列第一个四个字节其他可变长度的列每个占用两个字节。 在页的末尾每行两个额外的字节用来存储偏移指针。 因为SalesOrderDetail 表包含可变长度列它们的大小不是预先设定的但是平均每行95字节因为一个页的大小是8KSalesOrderDetail表每页包含的行数大约是75超过了我们例子中的每页10行在后续章节我们将讨论SQL SERVER管理工具你可以用它来决定这些数字。 尽管我们常常说SQL SERVER读取数据行但这么说常常会造成误解SQL SERVER不会读取行它最少读取一个页。在说“给定一个索引键值SQL SERVER能够快速访问到一行”时候我们已经造成了误解更正确的说法是给定一个索引键一个索引允许SQL SERVER快速访问一个页而不是一个数据行一旦SQL SERVER将一个或者多个页载入内存它会检查内存中的页并定位到所请求的数据行。 区 SQL SERVER在页上做了另一个逻辑分组它将8个连续的页分成一个逻辑单元称为区。 通常区和页一样是所有关系的单位如果区中的一个页从属于表A或者索引B那么区中的所有8个页都会从属于一个相同的对象。对于很小的表或者索引来说情况会有所不同它们不能充满整个区在这种情况下 超过一个表或者索引会被定位到一个相同的区中但对于大部分对象来说区仍是所有关系的单位。 因此SQL SERVER并不认为表扫描是读取表的所有行它认为表扫描是读取表的所有页或者区它知道它将很可能并发的处理8K64K的IO请求来读取整个表这将使得表扫描变得不至于像每行读取那样吓人。 读取页和区不仅意味着做一个表扫描比我们期望的具有更少的工作它还意味着为了从非聚集索引受益一个查询应该比我们期望的更具有选择性。 考虑如下假设性的查询查询了SalesOrderDetail 表大约4%的数据行。 既然每25行数据就会有一行被选中既然在ProductID 非聚集索引中条目被分组放置在一起使用ProductID 非聚集索引来定位表中的数据行看起来似乎是个好主意。但是再认真想一想。 由于表的聚集索引是SalesOrderID / SalesOrderDetailID而不是ProductID顺序因此如果平均每页包含75行我们的歘查询从25行中选择一行那么平均每个页变会包含3个请求行那么平均每个页都包含了至少一个请求行换句话说几乎每个页都 需要被读取来满足这个查询那么用表扫描来读取它们是最好的选择一次读取一个区平均每次都装在24个请求行进入内存3*8。 SQL SERVER新手常常问的一个问题是对于非聚集索引的使用来说一个查询应该具有何种可选择性在本章你现在知道了这个问题的一个答案应该比每页一行更具有选择性后续章节提供的信息会使你变得更精确于决定哪个索引是有益的而哪些毫无益处。 结论 SQL SERVER不会读取数据行它读取一页或者多个页的数据作为最小的IO单元它的大小是8K区是数据文件中8个连续的页正常情况下一个区以及它们的页包含一个单独对象的行或者条目不管它是一个堆还是一个聚集索引由于大的IO单元提供的高效性一个查询必须更具有选择性才能从非聚集索引中受益。 在第五章我们将看下你能做的一些事来增加聚集索引有益于查询的可能性使索引变成一个包含索引index becomes a covering index 。 换句话说下一章是关于给索引添加包含列 included columns。 转载于:https://www.cnblogs.com/qianxingmu/p/10411942.html