SQL Server性能调优之缓存
在执行任何查询时,sql server都会将数据读取到内存,数据使用之后,不会立即释放,而是会缓存在内存buffer中,当再次执行相同的查询时,如果所需数据全部缓存在内存中,那么sql server不会产生disk io操作,立即返回查询结果,这是sql server的性能优化机制。
一,主要的内存消费者(memory consumer)
1,数据缓存(data cache)
data cache是存储数据页(data page)的缓冲区,当sql server需要读取数据文件(file)中的数据页(data page)时,sql server会把整个page都调入内存(内存中的一个page叫做buffer),page是数据访问的最小单元。
当用户修改了某个page上的数据时,sql server 会先在内存中修改buffer,但是不会立即将这个数据叶写回硬盘,而是等到checkpoint或lazy writer进程运行时集中处理。当用户读取某个page后,如果sql server没有内存压力,它不会在内存中删除这个page,因为内存中的数据页始终存放着数据的最新状态,如果有其他用户使用这个page,sql server 不需要从硬盘中读取一次,节省语句执行的时间。理想情况是sql server将用户需要访问的所有数据都缓存在内存中,sql server 永远不需要去硬盘读取数据,只需要在checkpoint 或 lazy write运行时把修改过的页面写回硬盘即可
2,查询计划缓存(query plan cache)
存储查询语句和存储过程的执行计划,以供重用,而不需要重新编译(compile),因为编译查询语句产生执行计划是一个非常耗费资源的过程。
二,查看内存消耗
在sql server中,只有内存书记员(memory clerk)能够分配内存,memory clerk会记录已经分配内存的数量,任何一个需要使用内存的对象,必须创建自己的memory clerk,并使用该memory clerk来分配内存。
1,查看memory clerk分配的内存量
select memory_node_id, type, pages_kb, virtual_memory_reserved_kb, virtual_memory_committed_kb, shared_memory_reserved_kb, shared_memory_committed_kb, page_size_in_bytes from sys.dm_os_memory_clerks where type = 'memoryclerk_sqlqereservations'
对于内存结点64,只在dac中使用。
2,统计memory clerk分配的内存总量
select mc.type,mc.name, sum(mc.pages_kb) as allocatedpages_kb, sum(mc.virtual_memory_reserved_kb) as vm_reserved_kb, sum(mc.virtual_memory_committed_kb) as vm_committed_kb, --sum(mc.shared_memory_reserved_kb) as sharemem_reserved_kb, --sum(mc.shared_memory_committed_kb) as sharemem_committed_kb, max(mc.page_size_in_bytes)/1024 as singlepagesize_kb from sys.dm_os_memory_clerks mc group by mc.type,mc.name order by allocatedpages_kb desc,mc.type,mc.name
消耗内存较大的clerk是:
- memoryclerk_sqlbufferpool:基本是buffer pool中page的大小
- objectstore_lock_manager:锁结构使用的内存,当发生严重的锁阻塞时,这表明系统中,存储大量锁,造成锁管理占用大量的内存;
- cachestore_objcp:触发器和存储过程等模块(module)的执行计划占用的缓存空间;
- cachestore_sqlcp:动态tsql语句,即席(adhoc)查询和预编译(prepared) tsql的执行计划缓存;
- cachestore_columnstoreobjectpool:列存储索引(columnstore index)占用的缓存
3,查看缓存中的数据页
当数据页从硬盘读取到内存之后,该数据页被复制到缓冲池(buffer pool),供sql server重用。每个缓存的数据页都有一个缓存描述器(buffer descriptor),用户唯一标识内存中的数据页,在sql server实例中缓存的每一个数据页,都能从 sys.dm_os_buffer_descriptors 查看缓存描述的信息。
select db_name(bd.database_id) as dbname, object_name(p.object_id) as objectname, i.name as indexname, count(0) as buffercounts, sum(bd.free_space_in_bytes)/1024 as totalfreespace_kb, cast(sum(bd.free_space_in_bytes)/(8*1024.0)/count(0) as decimal(10,4))*100 as freespaceratio, sum(cast(bd.is_modified as int)) as totaldirtypages, sum(bd.row_count) as totalrowcounts from sys.allocation_units au inner join sys.dm_os_buffer_descriptors bd on au.allocation_unit_id=bd.allocation_unit_id inner join sys.partitions p on au.container_id=p.hobt_id inner join sys.indexes i on p.object_id=i.object_id and p.index_id=p.index_id inner join sys.objects o on p.object_id=o.object_id where bd.database_id=db_id(n'database_name') and o.type<>n's' group by bd.database_id,p.object_id,i.name order by buffercounts desc,dbname,objectname
4,查看计划缓存
产生执行计划是十分消耗cpu资源的,sql server会在内存的plan cache中存储每个查询计划(query plan),及其占用的内存空间,重用次数等信息。
select cp.objtype,cp.cacheobjtype, sum(cp.size_in_bytes) as totalsize_b, count(cp.bucketid) as cachecounts, sum(cp.refcounts) as totalrefcounts, sum(cp.usecounts) as totalusecounts from sys.dm_exec_cached_plans cp group by cp.objtype,cp.cacheobjtype order by totalsize_b desc
三,清空缓存
在调优存储过程性能时,清空缓存是必需的,缓冲池(buffer pool)是sql server的缓存管理器,包含了sql server的绝大部分缓存数据(cache),例如,执行计划缓存(plan cache),数据缓存(data cache)等。
清空缓存常用的命令有如下三个:
checkpoint dbcc dropcleanbuffers dbcc freeproccache
checkpoint和dbcc dropcleanbuffers 用于清理数据缓存(data cache)中的脏页(dirty pages)和干净页(clean pages),而dbcc freeproccache 用于清空所有的计划缓存(plan cache)。
1,清空数据缓存
checkpoint 用于将脏页(dirty pages)写入硬盘,脏页(dirty pages)是指数据页读入缓存后,被修改过,导致内存中数据页和硬盘中的数据页中的内容不同;干净页(clean pages)是指数据页被读入缓存后,没有被修改过,所以,内存中的数据页和硬盘中的数据页中的内容相同。不管是dirty pages 还是 clean pages 都是data cache,在性能调优时,都必须从内存中清理掉,否则,查询性能将忽略掉数据从硬盘加载到内存的io消耗,影响查询语句的执行情况。
checkpoint 命令用于产生冷缓存(cold buffer cache),该命令将当前数据库产生的所有脏页写入到硬盘,并清理内存buffer;在执行checkpoint命令之后,执行 dbcc dropcleanbuffers 用于从缓冲池中清空所有的干净页。
在性能测试时,使用dbcc dropcleanbuffers从sqlserver的数据缓存池中清除所有的clean缓存数据,需要注意的是该命令只移走干净的缓存,不移走脏缓存。因此,在执行这个命令前,应该先执行checkpoint,将所有脏页写入磁盘,这样在运行dbcc rropcleanbuffers 时,可以保证所有的数据缓存被清理,而不是其中的一部分。
2,清空计划缓存
计划缓存(plan cache)用于缓存查询语句的执行计划,每一条查询语句在执行之后,其查询计划都会缓存plan cache中。在产品环境中,不要轻易清理掉plan cache。如果检测到某个plan cache产生参数嗅探问题,导致性能十分低下,推荐修改查询语句,重新编译存储过程,以单独刷新该sp的计划缓存。
dbcc freeproccache [ ( { plan_handle | sql_handle} ) ]
计划缓存,之前叫做过程缓存(procedure cache),执行dbcc freeproccache 命令,释放所有的计划缓存,这回导致存储过程,adhoc 查询等查询必须重新编译,产生新的计划缓存。
四,强制重新编译执行计划
修改存储过程,触发器等模块(module)能够使其执行计划重新编译,除此之外,还有其他方法,能够强制重新编译执行计划
1,标记,下次重新编译
使用该存储过程,标记一个执行模块(sp,trigger,user-defined function)在下次执行时,重新编译执行计划
sys.sp_recompile [ @objname = ] 'object'
2,不复用执行计划
在创建存储过程时,使用with recompile 选项,在每次执行sp时,都重新编译,使用新的执行计划。
create procedure dbo.usp_procname @parameter_name varchar(30) = 'parameter_default_value' with recompile
3,执行时重新编译
在执行存储过程时,重新编译存储过程的执行计划
exec dbo.usp_procname @parameter_name='parameter_value' with recompile
4,语句级别的重新编译
在sp中,使用查询选项 option(recompile),只重新编译该语句级别的执行计划
select column_name_list from dbo.tablename option(recompile)
sql server在执行查询之后,查询提示(recompile)指示存储引擎将计划缓存抛弃,在下次执行存储过程时,强制查询优化器重新编译,生成新的执行计划。在重新编译时,sql server 优化器使用当前的变量值生成新的计划缓存。
附:
冷缓存,热缓存,脏缓存和干净缓存名词解释:
- 净缓存页(clean buffer) 是指内存中未被修改的数据页,dbcc dropcleanbuffers 用于从缓冲池(buffer pool)移除干净页,释放buffer。
- 脏缓存页(dirty buffer)是指数据页在内存中被修改,但是还没有写入到硬盘中,导致硬盘中的数据不同于内存,通常情况下,脏页通过checkpoint进程来自动同步,checkpoint 将脏页数据写入到硬盘中,使内存和硬盘文件中的数据保持一致,能够减少数据还原的时间。
- 冷缓存页(cold buffer)是指,在数据处理阶段,最近没有被使用的缓存页。
- 热缓存页(hot buffer)是指,在数据处理阶段,最近经常被使用的缓存页。
参考文档:
what is a cold, dirty or clean buffer
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!