直方圖是一種統(tǒng)計(jì)報(bào)告,它可以顯示在某個(gè)最小值和最大值之間的值的等級(jí)或范圍內(nèi)值出現(xiàn)的頻率。讓我們以學(xué)生的考試成績(jī)結(jié)果為例來進(jìn)行說明。假定有 30 個(gè)學(xué)生參加考試,最低分為 51,最高分為 100。您希望在最低分和最高分之間生成若干個(gè)等級(jí),并計(jì)算每個(gè)等級(jí)內(nèi)的結(jié)果數(shù)目,從而了解整個(gè)班級(jí)的分?jǐn)?shù)分布情況。如果您希望生成五個(gè)范圍大小相似的連續(xù)等級(jí),則可得到如下的等級(jí)和范圍:50 到 60、60 到 70、70 到 80、80 到 90、90 到 100(下限不包括在內(nèi),但包括上限)。該直方圖包括各個(gè)等級(jí)以及每個(gè)等級(jí)內(nèi)的結(jié)果數(shù)目。 同樣,利用直方圖,您可以分析網(wǎng)絡(luò)中在服務(wù)器上設(shè)置的性能計(jì)數(shù)器(例如,CPU 利用率、內(nèi)存)的值的采樣。例如,假設(shè)您每隔五分鐘就記錄某一網(wǎng)絡(luò)服務(wù)器的 CPU 利用率,某天測(cè)得的值在 21% 到 100% 之間變動(dòng)。您可以生成有四個(gè)等級(jí)的直方圖 — 20 到 40、40 到 60、60 到 80、80 到 100 — 從而得出屬于每個(gè)等級(jí)的樣本數(shù)。如果您的服務(wù)器在那一天超負(fù)荷地工作,那么大多數(shù)樣本會(huì)屬于第四個(gè)等級(jí)。 生成性能計(jì)數(shù)器直方圖 下面是一個(gè)涉及直方圖的問題;您可以看看自己是否能在讀到我的解決方案之前就解決它。一個(gè)已調(diào)度的 SQL Server 代理作業(yè)將在一個(gè)名為 Samples 的表中定期記錄某網(wǎng)絡(luò)服務(wù)器的性能計(jì)數(shù)器的采樣。運(yùn)行 清單 1 顯示的代碼,創(chuàng)建 Samples 表并向其中填充數(shù)據(jù)。采樣 (dt) 后,該表的每一行都包含度量 ID (measid)、度量值 (value) 和表示表中其他列的篩選列(100 字節(jié))。(例如,該表通常包括一個(gè) serverid 列,這樣您可以記錄多個(gè)服務(wù)器的度量樣本。考慮到這個(gè)問題,在此示例中,讓該表只包含一個(gè)服務(wù)器的數(shù)據(jù)。) 假設(shè) measid 1 是 CPU 利用率百分比,measid 2 是以兆字節(jié)為單位的內(nèi)存使用量。您的用戶需要直方圖來幫助他們分析在一段時(shí)期內(nèi)某個(gè)度量的性能數(shù)據(jù)。用戶提供了以下參數(shù):等級(jí)數(shù) (@numsteps)、度量 ID (@measid) 和日期范圍(@fromdt — 包括起始日期,@todt — 不包括終止日期)。您的任務(wù)是生成這些給定參數(shù)的直方圖。請(qǐng)注意,您不必在結(jié)果中包括樣本數(shù)為 0 的等級(jí)。例如,假設(shè)用戶提供了以下參數(shù): DECLARE @numsteps int, @measid int, @fromdt datetime, @todt datetime SELECT @numsteps=5, @measid=1, @fromdt='20030101', @todt='20030102' 在 Samples 表中,在給定期間內(nèi),measid 1 的最小度量值是 26,最大度量值是 50。在 @numsteps 參數(shù)中請(qǐng)求的等級(jí)數(shù)為 5。首先,您需要計(jì)算五個(gè)等級(jí)內(nèi)各范圍的下限和上限。因?yàn)榉秶南孪薏话ㄔ趦?nèi),所以經(jīng)過計(jì)算可得到以下范圍:25 到 30、30 到 35、35 到 40、40 到 45、45 到 50。 您需要編寫能告訴您每個(gè)等級(jí)有多少度量的代碼 — 在本例中,您的代碼應(yīng)產(chǎn)生與等級(jí) 1 相匹配的一個(gè)度量 (26)、與等級(jí) 2 相匹配的兩個(gè)度量(33、35)以及與等級(jí) 5 相匹配的兩個(gè)度量(47、50)。 以下是我針對(duì)此問題提供的一些解決方案。 解決方案 1:使用等級(jí)表 第一個(gè)解決方案涉及到編寫一個(gè)生成派生表 Steps 的查詢,該表包含等級(jí)號(hào)和每個(gè)等級(jí)的值的范圍。生成這樣一個(gè)表后,該解決方案就顯得簡(jiǎn)單了。您需要完成的操作是:根據(jù)屬于等級(jí)范圍內(nèi)的 value 列將派生表 Steps 聯(lián)接到 Samples 表、根據(jù)等級(jí)號(hào)對(duì)結(jié)果進(jìn)行分組、計(jì)算每組內(nèi)的行數(shù)。這個(gè)解決方案中比較困難的地方就是編寫生成派生表的查詢。要生成等級(jí)號(hào),可以使用一個(gè)名為 Nums 的輔助表,在該表中填充有一個(gè)范圍為 1 到 的整數(shù)序列。運(yùn)行 清單 2 中的腳本可創(chuàng)建 Nums 輔助表,并向其中填充 1000 個(gè)整數(shù)。 要計(jì)算每個(gè)等級(jí)范圍的下限和上限,需要交叉連接兩個(gè)查詢的結(jié)果:一個(gè)是針對(duì) Nums 的查詢,以返回等級(jí)號(hào),另一個(gè)是針對(duì) Samples 的查詢,以返回最小度量值和最大度量值。產(chǎn)生的查詢可能如 清單3 所示。該查詢對(duì)每個(gè)等級(jí)號(hào)返回相同的常規(guī)最小度量值和最大度量值。這只是該解決方案中的中間結(jié)果;稍后您會(huì)將常規(guī)最小值和最大值與等級(jí)號(hào)一起使用,以便計(jì)算等級(jí)的最小值和最大值。 現(xiàn)在,您需要用返回的表達(dá)式替換 SELECT 列表中的星號(hào),此外,還需要替換等級(jí)號(hào)以及等級(jí)范圍的下限(不包括)和上限(包括)。等級(jí)號(hào)很簡(jiǎn)單,是 n。 以下代碼是構(gòu)建計(jì)算下限的表達(dá)式的基礎(chǔ): mn + *(n-1) - 1 其中,mn 是常規(guī)最小度量值,n 是等級(jí)號(hào),step_size 是每個(gè)等級(jí)所覆蓋范圍的大小。用于計(jì)算 step_size 的表達(dá)式如下所示: (mx-mn+1)/@numsteps 通過將這兩個(gè)表達(dá)式結(jié)合在一起,您可以得到 mn + (mx-mn+1)/@numsteps*(n-1) - 1 如果您得到的值范圍總是能用等級(jí)數(shù)來整除,那么,使用上面這個(gè)表達(dá)式就可以了,但在實(shí)際應(yīng)用中,情況卻并不總是如此。下面的表達(dá)式使用數(shù)值除法和舍入法,適用于不能用等級(jí)數(shù)整除的值范圍: mn + CAST(round(1.0*(mx-mn+1)/@numsteps*(n-1), 0) AS int) - 1 您可以通過將除法運(yùn)算的第一個(gè)操作數(shù)與數(shù)值 1.0(讀法是一點(diǎn)零)相乘來進(jìn)行分?jǐn)?shù)除法(而非整數(shù)除法),這意味著 SQL Server 不會(huì)截?cái)嘈?shù)部分。然后,您需要對(duì)結(jié)果進(jìn)行舍入,以便得到整個(gè)范圍的上限和下限。之后,SQL Server 將經(jīng)過舍入的結(jié)果轉(zhuǎn)換為整數(shù),以便去掉小數(shù)點(diǎn)后沒有意義的零。您可以用相似的方式來計(jì)算上限: mn + CAST(round(1.0* (mx-mn+1)/@numsteps*n, 0) AS int) - 1 上述表達(dá)式與前面的表達(dá)式之間的唯一區(qū)別是它將等級(jí)大小與等級(jí)號(hào) (n) 相乘,而不是與 n-1 相乘。要測(cè)試計(jì)算派生的 Steps 表的完整查詢,請(qǐng)運(yùn)行 清單 4 中的代碼;請(qǐng)注意,得到的結(jié)果與圖 1 相同。 請(qǐng)隨便試用此解決方案的代碼中的參數(shù),以便測(cè)試一下更改等級(jí)數(shù)對(duì)結(jié)果會(huì)有什么影響,等等。請(qǐng)記住,返回等級(jí)表的查詢只是該解決方案的一部分。現(xiàn)在,您可以在下面的偽代碼中看到缺少的、被表示為 的查詢部分: SELECT step, count(*) AS cnt FROM Samples JOIN () AS Steps ON value > f AND value = @fromdt AND dt 如果您像我一樣喜歡使用模塊化的開發(fā)方法來簡(jiǎn)化代碼及其維護(hù),則可以編寫一個(gè)用戶定義函數(shù) (UDF),該函數(shù)將等級(jí)數(shù)、度量 ID 和日期范圍作為參數(shù),并返回表 Steps。運(yùn)行 清單 6 顯示的代碼來創(chuàng)建 fn_steps 函數(shù)。 要測(cè)試該函數(shù),請(qǐng)運(yùn)行下面的代碼: SELECT * FROM fn_steps(1, 5, '20030101', '20030102') 現(xiàn)在,您可以使用 fn_steps 表,而不是派生表 Steps,如 清單 7 中的代碼所示。 解決方案 2:實(shí)時(shí)計(jì)算等級(jí)號(hào) 這個(gè)難題還有另一個(gè)解決方案,該方案不生成等級(jí)表,而是實(shí)時(shí)計(jì)算等級(jí)號(hào)。利用此解決方案時(shí),您無需使用等級(jí)號(hào)輔助表。請(qǐng)注意 清單 8 (第 18 頁)的標(biāo)注 A 中的 FROM 子句。您將交叉連接兩個(gè)派生表 — 一個(gè)表名為 S,包含來自 Samples 的、與提供的參數(shù)相匹配的行?硪桓霰礱??R,包含最小度量值和整個(gè)范圍的大小。下面的表達(dá)式(在 SELECT 列表中進(jìn)行編寫)用于計(jì)算等級(jí)號(hào): floor((value-mn) / ([url=mailto:1.0*range/@numsteps]1.0*range/@numsteps[/url])) + 1 AS step 此表達(dá)式使用的邏輯與您在前面的解決方案中用于計(jì)算上限和下限的邏輯很相似。表達(dá)式 (value-mn) 可計(jì)算出值在范圍內(nèi)的位置,而 ([url=mailto:1.0*range/@numsteps]1.0*range/@numsteps[/url]) 可計(jì)算出等級(jí)大小。用第二個(gè)操作數(shù)除以第一個(gè)操作數(shù),在結(jié)果的基礎(chǔ)上再加上 1,就可以得出等級(jí)號(hào)。既然您已經(jīng)向每行附加了一個(gè)等級(jí)號(hào)(匹配來自 Samples 表的條件),那么您就可以在名為 RS 的派生表中使用此查詢,從而能夠按計(jì)算出的等級(jí)號(hào)對(duì)結(jié)果進(jìn)行分組。清單 8 顯示了完整的解決方案,在該解決方案中,外部查詢按等級(jí)號(hào)對(duì)結(jié)果進(jìn)行分組,并計(jì)算每個(gè)等級(jí)的行數(shù)。 |
|站長(zhǎng)郵箱|小黑屋|手機(jī)版|Office中國/Access中國
( 粵ICP備10043721號(hào)-1 )
GMT+8, 2025-7-13 08:08 , Processed in 0.077197 second(s), 16 queries .
Powered by Discuz! X3.3
© 2001-2017 Comsenz Inc.