上面图中红框表示的date_format的值分别为3和1。因此,如果你要使用不同的客户端进行数据库的连接时一定不要忘记指定它们使用相同的SET选项等等被缓存的信息,也不要在执行时改变这些被缓存的属性。从上面的结果你也可以看到sql_handle和plan_handle是1:N的关系。
缓存中保存的是整个批命令的计划,它由每个单独的语句的计划组成。为了能高效的执行每条语句,在执行之前都会判断此语句所引用的对象架构有无变化、统计信息是否过期。如果符合任一条件,即便批已经开始执行,这条语句也会被重新编译。在SQL2000中会导致整个批中的语句都被重新编译,而2005因为有了语句级编译的功能可以减少对CPU和内存的占用。
随着缓存数量的增加,最终会达到上述公式计算所得的最大边界值。这种内存压力可以被分成两类:本地(Local Memory Pressure)和全局内存压力(Global Memory Pressure)。
当某个存储区域,比如SQL Plans存储区域达到了总可用内存的一定比例或是因为缓存计划的数量过多时,SQLSERVER就会对此区域的缓存进行相应的清理。如果你执行一条SQL语句时正好触发了清理过程,因为清理过程是在此线程中执行的,所以你就必须要等待清理结束后才能得到结果。
前面使用DBCC MEMORYSTATUS看到过Target的大小,还有一个Commited。它是当前SQLSERVER已经占用的内存。如果你发现Target和Commited的值相等,但是这时机器并没有任何的数据库操作。原因是因为SQLSERVER一旦占用了这些内存后,只有在外部程序运行时没有可用的物理内存时。SQLSERVER才会释放掉已占用但是当前并不使用的内存,这就是所谓的外部全局内存压力。如果由于对数据进行排序或是聚合等大量占用内存的操作导致可用物理内存用尽,并且虚拟内存也要被消耗完时,这时SQLSERVER也会选择释放掉过程缓冲区中的一些内存,这就是所谓的内部全局内存压力。
每个缓存计划的大小是和批处理中的字符数相关的,在sys.dm_exec_cached_plans中的size_in_bytes字段表示的是缓存占用的字节数。那么为了能让缓存计划少占用些内存,你应该尽量减少批命令中使用过多的参数。比如你执行像SELECT * FROM Sales.SalesOrderHeader WHERE SalesOrderID IN(43697,43698,43699,43700,……)这样的语句。如果上面的语句封装在存储过程中,你把IN里的值当作一个字符串传进来,同样也会使该存储过程占用大量的缓存资源,但是你的注释内容是不被计算在内的。因此你可以随意添加对代码的注释。你可以自己试一下在不同的参数值时,当前缓存的大小是多少。