1 --內存壓力分析
2
3 --表現特徵
4 --SQL常常觸發lazy writer
5 --SQL須要常常從硬盤裏讀數據,會有不少硬盤讀
6 --執行計劃常常被清除,因此buffer pool裏的stolen內存部分應該不會不少
7 --因爲數據頁常常被清除,因此page life expectancy不會很高,並且會常常降低
8
9 --page life expectancy:緩存頁面生存時間
10
11 --若是數據頁面 buffer pool內存有壓力,SQL會優先清除內存裏的執行計劃
12
13 --解決辦法:
14 --來自外部壓力:Windows內存不夠,SQL會壓縮本身的內存,這時database page首當其衝被壓縮
15 --建議SQL安裝在專用服務器上
16
17
18 -------------------------------------------------------------------
19 --database page自身使用需求的壓力
20 --一、32位服務器開啓AWE
21 --二、增長物理內存
22 --三、若是scale up向上擴展不行,考慮scale out向外擴展,把SQL中的多個數據庫移到其餘服務器上,只留一個應用數據庫或者分庫處理
23 --四、使用表索引,減小沒必要要的讀和表掃描
24
25 --一、二、3都須要新的硬件投資,並且到底加多少內存可以解決問題很差說,最好是最後一種方法
26
27 -----------------------------------------------------------------------
28 --來自buffer pool裏的stolen壓力
29 --若是聲明瞭不少遊標,用完了不關,或者prepare不少執行計劃,不un-prepare,不登出SQL就會佔用
30 --database page的空間
31 --使用sys.dm_os_memory_clerks的single_pages_kb字段查看那個clerk用掉了較多的stolen內存
32
33
34 -----------------------------------------------------------------------------------
35
36
37 --來自multi-page memtoleave的壓力
38 --因爲multi-page的量不大,因此通常這種問題較少
39 --一、32位系統沒有開AWE,使用 /g 參數增大了multi-page的上限值
40 --二、64位系統multi-page沒有上限,若是SQL調用了一些內存泄漏很厲害的第三方代碼,
41 --64位系統就算內存再充裕也有漏完的可能性
42
43 ----使用sys.dm_os_memory_clerks的single_pages_kb字段查看哪一個clerk用掉比較多的內存
44
45
46 ---------------------------------------------------------------------------------
47 --使用內存比較多的語句
48 --有一些語句在不停地調用數據,把讀數據頁面最多的語句找出來,基本就可以找到SQL內存壓力
49 --的地方。分析一下這些語句是否是天生就要返回不少數據,爲什麼讀那麼多數據頁面
50
51
52 --例如:一個表有100W行記錄,查詢要返回70W行記錄。那麼這個語句在SQL使用不少內存是正常的
53 --在SQL上調整的餘地不大,選擇的方案有限:
54 --一、增長物理內存
55 --二、歸檔歷史數據,把表裏的數據降下來
56 --三、調整應用程序設計,避免沒必要要的大數據量查詢
57
58 --由於沒有索引,因此SQL不得不把表裏的數據頁面讀到內存裏,這樣內存消耗是能夠優化的
59 --最好的辦法添加索引
60
61 --分析方法:
62 --使用DMV提取歷史信息
63 --使用SQL Trace
64
65
66 --SQL2005之後有一個動態管理視圖sys.dm_exec_query_stats,返回緩存查詢計劃的性能統計信息
67 --SQL會統計從上次SQL啓動以來,一共作了多少次logical讀寫,多少次physical讀,還記錄執行所用的
68 --CPU時間總量。
69
70 --按照物理讀的頁面數排序 前50名
71 SELECT TOP 50
72 qs.total_physical_reads,qs.execution_count,
73 qs.total_physical_reads/qs.execution_count AS [avg I/O],
74 SUBSTRING(qt.text,qs.statement_start_offset/2,
75 (CASE WHEN qs.statement_end_offset=-1
76 THEN LEN(CONVERT(NVARCHAR(max),qt.text))*2
77 ELSE qs.statement_end_offset END -qs.statement_start_offset)/2) AS query_text,
78 qt.dbid,dbname=DB_NAME(qt.dbid),
79 qt.objectid,
80 qs.sql_handle,
81 qs.plan_handle
82 from sys.dm_exec_query_stats qs
83 CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt
84 ORDER BY qs.total_physical_reads DESC
85
86 --按照邏輯讀的頁面數排序 前50名
87 SELECT TOP 50
88 qs.total_logical_reads,
89 qs.execution_count,
90 qs.total_logical_reads/qs.execution_count AS [AVG IO],
91 SUBSTRING(qt.text,qs.statement_start_offset/2,(CASE WHEN qs.statement_end_offset=-1 THEN LEN(CONVERT(NVARCHAR(max),qt.text))*2 ELSE qs.statement_end_offset END -qs.statement_start_offset)/2) AS query_text,
92 qt.dbid,
93 dbname=DB_NAME(qt.dbid),
94 qt.objectid,
95 qs.sql_handle,
96 qs.plan_handle
97 from sys.dm_exec_query_stats qs
98 CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt
99 ORDER BY qs.total_logical_reads DESC
100
101 --上面語句的缺點是沒有時效性,記錄的生存期與執行計劃自己相關聯
102
103
104
105
106
107 --使用SQL Trace
108
109 --SQL Trace裏面有一個reads字段,記錄了某條語句完成過程當中一共作了多少次讀的動做,找到read最多的語句
110 --每一個SQL Trace裏有成千成萬的語句,可使用fn_trace_gettable 像一張表同樣把trace文件裏的記錄查詢出來
111 --能夠用他將記錄轉入到SQLSERVER裏,而後用查詢語句進行統計分析。
112
113 --例如,在c:\sample目錄下有一個問題時段的trace文件,叫a.trc.
114 --導入到SQLSERVER
115
116 SELECT * INTO #SAMPLE
117 FROM sys.fn_trace_gettable('C:\Users\Administrator\Desktop\1.trc',DEFAULT)
118 WHERE EventClass IN(10,12)
119
120 SELECT TOP 100 * FROM #SAMPLE
121 SELECT TOP 1000 TextData,DatabaseID,HostName,ApplicationName,LoginName,SPID,
122 StartTime,EndTime,Duration,reads,writes,CPU
123 FROM #SAMPLE
124
125
126
127 --(1)找到是哪臺客戶端上的哪一個應用發過來的語句,從總體上講在數據庫上引發的讀最多
128 --獲得這個結果,就能大概知道哪些客戶端要訪問大量的數據頁面,可能形成內存壓力
129 SELECT * INTO #SAMPLE
130 FROM sys.fn_trace_gettable('C:\Users\Administrator\Desktop\1.trc',DEFAULT)
131 WHERE EventClass IN(10,12)
132
133 SELECT DatabaseID,HostName,ApplicationName,SUM(reads) AS reads
134 FROM #SAMPLE
135 GROUP BY DatabaseID,HostName,ApplicationName
136 ORDER BY SUM(reads) DESC
137
138
139
140 --(2)按照reads從大到小排序,最大的1000個語句 用這個方法能夠找出最昂貴的單筆語句
141 SELECT TOP 1000 TextData,DatabaseID,HostName,ApplicationName,LoginName,
142 SPID,StartTime,EndTime,Duration,reads,writes,CPU
143 FROM #SAMPLE
144 ORDER BY Reads DESC
145
146
147
148
149 --利用readtrace這個工具自動分析trace文件,找出使用大量系統資源的語句
150 --若是隻是要找到一段時間內系統資源使用比較多的語句,不用作詳細分析,readtrace這個工具
151 --可以自動完成
152
153
154 --經過以上三種方法,DBA比較快地找到某個SQL上形成不少讀操做的語句。這裏須要說明的是
155 --SQL Trace裏reads字段是邏輯讀,而不必定是物理讀,只有語句訪問的數據不在內存裏時,
156 --纔有物理讀!!!!!!!!
157
158
159
160
161 --stolen內存壓力分析
162 --除了database pages,其餘內存分配基本都是直接從地址空間申請,不是先reserve,後commit的
163 --stolen內存主要以8KB爲單位分配,分佈在buffer pool裏
164
165 --stolen內存不緩存數據頁面,任何一條語句的執行都須要stolen內存來作語句分析,優化,執行計劃的緩存
166 --可能也須要內存來作排序,計算。任何一個鏈接的創建,須要分配stolen內存給他創建數據結構
167 --和輸入輸出緩存區。若是stolen內存申請不到,SQL任何操做都會遇到問題
168
169
170 --stolen內存有緩存:執行計劃,用戶安全上下文(每次執行sql語句以前都不須要從新創建安全上下文)
171 --這些緩存越多越好
172
173
174 --stolen內存沒有緩存:使用完畢馬上釋放,供其餘用戶使用,例如:語義分析,優化,作排序,作Hash等
175 --因此在32位SQL,雖然stolen內存只有不到2GB,可是不多有stolen內存不夠用的狀況
176
177
178
179 --在SQL2005 SP2之後,SQL產品組調小了執行計劃的最高上限。這是由於若是一個SQL可以緩存這麼多不一樣的執行計劃
180 --說明他內部運行的大多數都是動態TSQL,不多可以重用。若是常常有執行計劃重用的現象,SQL也就不須要每次都
181 --生成新的執行計劃,從而緩存這麼多份了。在這樣的SQL裏,就算緩存再多的執行計劃,重用的機會都很小。
182 --因此這麼多的緩存對SQL的性能幫助不是很大,反而增長SQL的維護成本。從經驗上看,SQL緩存1GB~2GB的執行計劃
183 --基本足夠了,更多的緩存基本上對性能幫助不大。在有些狀況下,按期清空執行計劃緩存,反而對SQL的健康起到
184 --幫助做用
185 CHECKPOINT
186 DBCC DROPCLEANBUFFERS
187
188
189
190 --stolen緩存區與數據緩存區相互關係
191 --stolen內存不少是用完就釋放的,不會累積下來。
192 --對於有緩存機制的stolen內存,主要就是執行計劃,也有清理機制,當buffer pool有內存壓力的時候,SQL
193 --會同時清楚執行計劃和database pages ,SQL都會把最久沒有使用的對象清除
194
195 --就算一個查詢一次訪問上百MB的數據,可是他的執行計劃倒是很是小的。可是當lazy writer沒有能清除
196 --正在被使用的stolen內存的時候,會發生stolen內存越積越多,最後侵佔database pages空間的現象
197
198
199
200
201
202 --外部壓力與內部壓力
203 --外部壓力:Windows通知SQL要壓縮內存的時候,整個buffer pool裏的全部內存都面臨着清理
204
205 --內部壓力:
206 --database pages擠壓,當一個查詢須要大量的data page的時候
207 --stolen內存內部一些始終未清理的對象,例如,打開了遊標不關,或者prepare了一些語句沒有unprepare,
208 --那麼只要不logout,SQL就沒法清理和釋放這些對象
209
210
211
212
213
214 --解決辦法:
215 --因爲stolen內存是SQL本身申請使用的,能夠用clerk看到
216 --特徵:
217 --(1)返回錯誤信息701,在SQL 的errorlog裏能看到錯誤信息
218 --(2)在sys.sysprocesses裏的waittype字段不等於0X0000,而和stolen內存相關的等待狀態:
219 SELECT spid,
220 blocked,
221 waittype,
222 DB_NAME(dbid)AS dbname,
223 open_tran,hostname,
224 program_name,
225 hostprocess,
226 cmd,
227 loginame
228 FROM sys.sysprocesses
229 ORDER BY spid ,dbid ASC
230 SELECT @@SPID
231 --waittype代碼:
232
233 --cmemthread(0x00B9)
234 --當多個用戶同時往同一塊緩存區裏申請或釋放內存時,在一個時間點,只有一個鏈接能夠作申請或
235 --釋放內存動做,其餘鏈接必須等待。這些鏈接的等待狀態,就是cmemthread。這種等待狀態發生得
236 --比較少,一般只會發生在併發度很是高的SQL裏。而這些併發鏈接,在大量地使用須要每次作編譯的
237 --動態TSQL語句發生得比較多。
238 --這個等待通常不是由於內存數量少,而是同時申請的人太多。因此解決的方法不是增長內存,而是修改
239 --客戶鏈接的行爲,儘量更多地使用存儲過程,或者是參數化的TSQL語句調用,減小語句的編譯量,
240 --增長執行計劃的重用,避免大量鏈接同時申請內存作語句編譯
241 SELECT spid,
242 blocked,
243 waittype,
244 DB_NAME(dbid)AS dbname,
245 open_tran,hostname,
246 program_name,
247 hostprocess,
248 cmd,
249 loginame
250 FROM sys.sysprocesses
251 WHERE waittype=0x00B9
252 ORDER BY spid ,dbid ASC
253
254 --select * from sys.sysprocesses 的waittype字段顯示0x40或0x0040(resource_semaphore) 等待資源
255
256 --SOS_RESERVEDMEMBLOCKLIST(0x007B)
257 --當用戶發過來的語句內含有大量的參數,或者有一個很長的"in"的子句,他的執行計劃在8KB的single pages
258 --可能會放不下,須要用multi-page來存儲。因此SQL須要在MEMTOLEAVE申請空間。形成的後果是隨着緩存
259 --的執行計劃愈來愈多,不但buffer pool裏的stolen內存不斷增加,memtoleave裏用來存儲執行計劃的stolen
260 --內存也在不斷增加。因爲在32位buffer pool能夠比memtoleave大不少,因此buffer pool尚未壓力,
261 --lazy writer不會被觸發。可是memtoleave裏的內存已經比較緊張了。當用戶要申請這塊內存而暫時不能獲得
262 --知足時,他的等待狀態就是SOS_RESERVEDMEMBLOCKLIST
263 --解決這種等待方法有三種:
264 --(1)避免使用這種帶有大量參數,或者「in」子句的語句。這種語句的運行須要消耗比正常語句多得多的內存
265 --以及CPU資源,不是一種合理的設計。能夠先把參數值存儲到臨時表裏,用join臨時表代替直接引用這些值。
266 --這是一種從根本上解決這種問題的方法
267
268 --(2)擴展memtoleave的大小,推遲SQL遇到瓶頸的時間
269
270
271 --(3)按期運行DBCC freeproccache語句,手工清除緩存的執行計劃,緩解內存瓶頸。雖然沒有第一種理想,
272 --可是在現實使用中,效果還不錯,對SQL總體性能的影響不大
273
274 --type:USERSTORE_SXC:暫時存放正在執行中的語句的參數。例如,客戶調用存儲過程,或者用sp_executesql
275 --調用動態TSQL語句時,須要帶入過程參數。若是參數過長,這部份內存的使用量就會比較大
276
277
278
279
280 --RESOURCE_SEMAPHORE_QUERY_COMPILE(0x011A)
281 --當一個batch或存儲過程很是長和複雜的時候,SQL編譯他所須要的內存可能超過你的想象。
282 --爲了防止太多內存被用來作編譯,SQL爲編譯內存設了一個上限。當有太多複雜的語句同時
283 --在作編譯時,可能編譯內存使用會達到這個上限。後面的語句將不得不進入等待狀態,等前面
284 --的語句編譯完成,把內存釋放出來之後,後面的語句才能繼續編譯。這個等待狀態被稱爲
285 --RESOURCE_SEMAPHORE_QUERY_COMPILE SEMAPHORE(信號量)
286 --解決辦法:
287 --是前兩種的綜合:
288 --(1)修改客戶鏈接的行爲,儘量更多地使用存儲過程,或者是使用參數化的TSQL語句調用,
289 --減小語句編譯量,增長執行計劃的重用,避免大量鏈接同時申請內存作語句編譯的現象
290
291
292 --(2)簡化每次須要編譯的語句的複雜度,下降編譯須要的內存量
293
294 --(3)當stolen內存使用總量比較大的時候,也能夠考慮按期運行DBCC freeproccache語句,
295 --手工清除緩存的執行計劃,保證stolen內存一直處在一個比較富裕的狀態
296
297
298 --* DBCC FREEPROCCACHE
299 --從過程緩衝區刪除全部元素
300
301
302 --雖然stolen內存沒有database pages那麼多,但也是SQL正常運行不可缺乏的重要部分
303
304 --在64位系統,max server memory的設置僅對buffer pool起做用
305 --memtoleave默認是384,若是/g512 啓動參數,那麼memtoleave就是512+0.5*最大線程=640
306
307 --通常SQL根據負載量開啓線程,大部分SQL的線程數目比256要少,若是地址空間被大量佔用,-
308 --SQL可能沒法再建立新線程,其中一個明顯特徵就是,新用戶很難登入SQL
309
310 --使用大量multi-page的緣由,multi-page只有384MB
311 --(1)SQL內部
312 --1大量參數或者長「in」
313
314 --2network packet size設成8KB或更高,而這種鏈接成百上千
315 --SQL默認的network packet size是4KB,這樣每一個鏈接的輸入輸出緩存均可以放在buffer pool裏。
316 --在SSMS登陸窗口,選項》 -》網絡-》網絡數據包大小:4096字節
317 --若是調高到8KB,或更高,每一個網絡包加上包頭、包尾就要超過8KB。SQL只能把他們緩存在multi-pages裏面
318 --若是鏈接很是多,會形成multi-pages大量使用
319
320 --有些應用例如:SAP .NET應用等,須要提升網絡交互效率
321
322
323 --SQL的確提供了比較豐富的XML處理功能,可是相似的功能在應用程序也能夠經過直接調用一些XML的API
324 --解決。那麼是放在SQL裏,仍是放在應用程序裏作呢,須要設計者平衡一下。放在SQL裏作可能比較方便
325 --可是若是處理的XML串比較長,很複雜,那麼處理所要花費的資源是比較昂貴的,內存只是其中一部分,
326 --這個SQL還有其餘用戶要服務,那麼不免會影響到用戶的響應速度。
327
328 --(2)非SQL本身的代碼
329 --SQL CLR
330 --LINKED SERVER
331 --EXEC sys.sp_OACreate 調用COM對象
332 --擴展存儲過程EXEC sys.xp_cmdshell
333
334 --對multi-page來說,只要用戶調用,SQL就只好申請,因此從SQL的角度沒有什麼積極的辦法。
335 --使用/g 參數或者 升級到64位系統
336
337
338 --常見內存錯誤和解決辦法:
339 --主要有三類,這些內存錯誤跟內存瓶頸不一樣,有內存瓶頸SQL會發起不少paging 和lazy writer,可是
340 --內存錯誤輕則某些操做不能完成,重則整個SQL沒有響應,不只僅是性能問題
341
342 --一、OOM
343 --701錯誤:基本在32位機器,跟stolen內存有關,發現地址空間可供申請
344 --一、memtoleave地址段沒有連續空間可供使用
345 --二、第三方代碼申請太多內存沒有釋放掉
346 --SQL CLR
347 --LINKED SERVER
348 --EXEC sys.sp_OACreate 調用COM對象
349 --擴展存儲過程EXEC sys.xp_cmdshell
350 --因爲這些代碼不是SQL自帶的,因此在SQL這裏作調整是很難解決問題的
351
352 --三、buffer pool裏的stolen內存申請不到
353 --常見的會使用不少stolen內存的memory clerk有以下幾個:
354
355
356
357
358 --17803錯誤
359 --解決方法:
360 --使用/g 參數擴大memtoleave的大小,延緩問題發生頻率
361 --按期重啓SQL,延緩問題發生頻率
362 --升級SQL到64位
363 --前兩種不是長久之計
364
365 --memoryclerk_sqloptimizer和cachestore_phdr:語句指令作編譯時使用的內存,若是用戶一次發過來的批指令太長,這段內存使用會較多
366
367 --memoryclerk_sqloreservation:語句運行的時候在內存裏存儲臨時數據的地方
368 --cachestore_sqlcp:緩存動態TSQL語句執行計劃的地方。記得釋放遊標很unprepare語句
369
370 --user_tokenperm:緩存用戶的安全上下文。SQL在buffer pool沒有壓力的時候一般是64位機器能夠漲到上百MB。在SQL2005中
371 --維護這麼大的安全上下文緩存會影響SQL的總體性能
372
373 --objectstore_lock_manager:SQL裏的鎖結構使用的內存。SQL裏有嚴重的阻塞問題,一些用戶申請了大量的鎖卻不釋放
374 --而另外一些用戶想要申請大量的鎖卻拿不到,形成鎖的數目上百萬,這時這段內存的使用量會不少
375
376
377
378
379
380 --二、語句運行時沒能及時申請到內存,最多見的錯誤是8645
381 --這個錯誤一般發生在一個須要申請內存作排序或者hash等操做的查詢裏,在規定時間裏沒有能獲得足夠內存
382 --申請的內存基本都是buffer pool裏的內存
383
384 --SQL內存自己有壓力,如今再發過來哪怕很小的內存申請數也不能知足
385 --用戶忽然發來一個或幾個須要大量內存很是複雜的語句,一會兒把SQL內存資源搞得很是緊張
386
387
388 --現象:
389 --login failed
390 --select * from sys.sysprocesses 的waittype字段顯示0x40或0x0040(resource_semaphore) 等待資源
391 --性能計數器:sql mamager:memory grants pending對象值不爲0
392
393
394 --解決辦法:
395 --避免其餘程序把SQL內存侵佔
396 --收集buffer manager 和memory manager性能計數器
397 --檢查一下SQL內存參數
398 --max server memory
399 --min server memory
400 --awe enabled
401 --min memory per query
402 --lock page in memory
403
404 --檢查各個memory clerk的內存申請
405 --檢查工做負荷,例如:併發會話數,當前執行的查詢,有可能的話開啓sqltrace
406
407 --爲SQL提供更多內存:
408 --移開佔用資源的應用程序到別的服務器
409 --設置max server memory
410 --運行下面DBCC命令釋放SQL內存緩存
411 DBCC freesessioncache
412 DBCC freeproccache
413
414
415
416 --找出使用內存比較多的語句,簡化他們,調整應用程序行爲,減小工做負荷
417 --檢查動態管理視圖,瞭解每一個查詢資源信號量的狀態信息。(SQL裏默認有兩個查詢資源信號量,分別處理複雜度不同
418 --的查詢,這樣的設計有助於防止幾個超大的查詢把整個SQL資源用盡,連一些很簡單的查詢都不能響應的現象發生)
419
420 --檢查語句是:
421 SELECT CONVERT(VARCHAR(30),GETDATE(),121) AS runtime,
422 resource_semaphore_id,
423 target_memory_kb,
424 total_memory_kb,
425 available_memory_kb,
426 granted_memory_kb,
427 used_memory_kb,
428 grantee_count,
429 waiter_count,
430 timeout_error_count
431 from sys.dm_exec_query_resource_semaphores
432
433 --resource_semaphore_id:資源信號量的非惟一ID,0表示常規資源信號量,1表示小型查詢資源信號量
434 --target_memory_kb:該資源信號量可以授予使用的內存目標,也就是當前的使用上限
435 --total_memory_kb:資源信號量如今所持有的總內存,是可用內存和被授予內存的和。若是系統內存不足或頻繁強制縮小內存,該值能夠
436 --大於target_memory_kb值,但意味着這個資源信號量有內存壓力
437 --available_memory_kb:可用於新授予的內存
438 --granted_memory_kb:授予的總內存
439 --used_memory_kb:授予內存中實際使用的部分
440 --grantee_count:內存授予獲得知足的活動查詢數
441 --waiter_count:等待內存授予獲得知足的查詢數,若是不爲0,意味着內存壓力存在
442 --timeout_error_count:自服務器啓動以來的超時錯誤總數,對於小型查詢資源信號量,該值爲null
443
444
445
446 --檢查sys.dm_exec_query_memory_grants,返回已經得到內存授予的查詢的有關信息,或依然在等待內存授予的查詢的
447 --有關信息。無須等待就得到內存授予的查詢將不會出如今此視圖中。因此對一個沒有內存壓力的SQL,這個視圖應該
448 --是空的
449
450 SELECT GETDATE() AS runtime,
451 session_id,
452 scheduler_id,
453 dop,
454 request_time,
455 grant_time,
456 requested_memory_kb,
457 granted_memory_kb,
458 used_memory_kb,
459 timeout_sec,
460 query_cost,
461 resource_semaphore_id,
462 wait_order,
463 is_next_candidate,
464 wait_time_ms,
465 REPLACE(REPLACE(CAST(s2.text AS VARCHAR(4000)),CHAR(10),''),CHAR(13),'') AS sql_statement
466 FROM sys.dm_exec_query_memory_grants
467 CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS s2
468
469 --session_id:正在運行查詢的會話ID(spid)
470 --scheduler_id:正在計劃查詢的SQL Processor調度的ID
471 --dop:查詢的並行度
472 --request_time:查詢請求內存授予的日期和時間
473 --grant_time:向查詢授予內存的日期和時間。若是還沒有授予內存,則此值爲null
474 --requested_memory_kb:請求的內存總量
475 --granted_memory_kb:實際授予的內存總量。若是還沒有授予內存,該值爲null。在典型狀況下,該值應該與requested_memory_kb相同
476 --建立索引時,除了初始授予的內存外,服務器還容許增長按需分配的內存
477 --used_memory_kb:此刻使用的物理內存
478 --query_cost:估計查詢開銷
479 --timeout_sec:查詢放棄內存授予請求前的超時時間
480 --resource_semaphore_id:查詢正在等待的資源信號量的非惟一ID
481 --wait_order:等待查詢在指定的queue_id中的順序,若是其餘查詢得到內存授予或超時,則給定查詢的該值能夠更改。若是已授予內存,則爲null
482 --is_next_candidate:下一個內存授予的候選對象:1:是 0:否 null:已授予內存
483 --wait_time_ms:等待時間。若是已經授予內存,則爲null
484 --plan_handle:查詢計劃的標誌符。使用sys.dm_exec_query_plan可提取實際的xml計劃
485 --sql_handle:查詢的TSQL文本標誌符。查詢中使用他連接sys.dm_exec_sql_text獲取實際的TSQL文本
486
487
488
489 --三、SQL沒法建立新線程供新鏈接使用
490 --當SQLSERVER上全部的進程都被用戶請求佔據,而又有新的客戶端發出鏈接請求時,SQL須要建立一個新的線程
491 --來響應這個請求。若是鏈接建立不出來,會出現SQL斷斷續續地鏈接不上的現象,已經在SQL裏的鏈接還能繼續工做
492 --只要有線程建立不出來的問題發生,SQL errorlog裏就會有記錄
493
494 --17802錯誤
495 --17189錯誤
496
497 --解決辦法:
498 --(1):檢查SQL使用了多少線程,是否是的確到了上限
499 --運行下面的查詢,檢查有多少個KPID<>0的SPID。當一個SPID的KPID不爲0的時候,就說明他正在使用線程
500 --運行中。再加上SQL本身運行所須要的線程(通常10到20個),就差很少是SQL使用的線程數目
501 SELECT COUNT(*) FROM sys.sysprocesses WHERE kpid<>0
502
503 --(2):若是線程的數目遠小於設置的最大數,那就要考慮是否是memtoleave有壓力了
504 --因爲線程使用的是memtoleave的內存,確認SQL還有足夠的memtoleave
505 SELECT type ,
506 SUM(virtual_memory_reserved_kb) AS [vm reserved] ,
507 SUM(virtual_memory_committed_kb) AS [vm commited] ,
508 SUM(awe_allocated_kb) AS [awe allocated] ,
509 SUM(shared_memory_reserved_kb) AS [sm reserved] ,
510 SUM(shared_memory_committed_kb) AS [sm committed] ,
511 SUM(single_pages_kb) AS [singlepage allocator],
512 SUM(multi_pages_kb) AS [multi page allocated]
513 FROM sys.dm_os_memory_clerks
514 GROUP BY type
515 ORDER BY typesql