在本篇文章,我将向大家介绍三个比较有趣的并且影响查询性能(内存、非阻塞vs.阻塞、动态游标)的迭代器。
内存:
由于所有迭代器需要占用少量内存来存储状态信息等信息,因此执行查询前,我们并不能估算出所需内存的大小。当缓存执行计划时,可以缓存其分配的内存,以不再需要重新为其分配,从而加速该缓存计划的高效执行。
但是,某些需要占用内存的迭代器可能需要额外的内存支持来执行,这些额外内存用于存储行数据。内存的大小通常由处理行的大小决定。为确保服务器运行不溢出内存,那些包含有占用内存的迭代器就可以顺利执行,由此我们可以估算出占用的内存量,从而在执行查询前为其保留内存授权。
消耗内存的迭代器影响性能有以下几种方式:
1) 消耗内存的迭代器查询可能需要一定的内存授权来执行,当服务器执行这样的查询时,若没有可用的内存,将会延迟执行而直接影响性能。
2) 若存在过多争用少量内存资源的查询,则服务器可能面临并发性减少,这对于数据仓库来说并不会受影响,但对于OLTP应用则是不可接受的。
3) 如果消耗内存的迭代器占用太多的少量内存,有可能执行时需要将数据写入(Spill)磁盘。Spilling可能会对查询造成一定的影响,同时系统性能也会由于额外的I/O负载增加而降低。此外,若迭代器写入过多的数据,有可能会溢出tempdb导致运行失败。
消耗内存的迭代器主要有排序、哈希聚合、哈希联接。
非阻塞与阻塞迭代器
多数迭代器可以归纳为两类:
1) 像在GetRows方法中同时使用输入行又产生输出行这样的迭代器,我们常把这类迭代器称为“非阻塞”。
2) 在输出行前使用所有输入行(通常在Open方法)的迭代器,常称这类迭代器为“阻塞”或者说“停下来然后继续”。
标量计算迭代器就是“非阻塞”迭代器的一个很好例子,而“排序”则是“阻塞”迭代器的一个例子。
阻塞迭代器并不是总是消耗内存,例如上面提到的排序。像COUNT(*)、SUM(*)、MIN(*)、MAX(*)等等这类标量迭代器并不消耗内存但是使用的是阻塞,若不扫描完所有的数据并进行统计是不可能获得行数的。
如果一个迭代器有两个子迭代器,该迭代器可能是阻塞也可能是非阻塞的。哈希联接就是这样一种迭代器。
非阻塞迭代器常适用于OLTP查询的优化,尤其是对于TOP N查询或FAST N这样的查询更为适合。当使用EXISTS子查询也是利用“非阻塞”方式工作。
提示:若一个查询需要输出有序,不妨创建索引来让优化器使用索引来快速输出期望的有序数据行,从而替代不必要的阻塞的排序操作,这种方法有助于提高查询的响应时间。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/355374/viewspace-520653/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/355374/viewspace-520653/