2009年3月24日 星期二

Page and Extent In SQL Server

在SQL Server 裡,最基本的儲存單位為 page。當一個新 Table 被建立時,就會在硬碟裡建立一塊以 8K 的連續空間,以便儲存我們想要保留的資料。這 8K 的連續空間,正是 SQL Server 的基本儲存單位: Page。當這 8K 的空間用完時,又會自動再產生一個 8K 的新 page。

如右圖所示,每個 page 最前面會先放一個 96 byte 的 Page header,在 Page header 裡頭紀錄了 page number, page type, page 剩餘空間, 以及配置單位編號。

page number 的分配是由 0 - 7,因為每 8 個 page 在 SQL Server 裡就會被視為一個 Extent。

page type 則是定義了以下格式:Data, Index, Text/Image, Global Allocation Map, Shared Global 
Allocation Map,Page Free Space, Index Allocation Map, Bulk Changed Map, Differential Changed Map。

Data row 則是緊接在 Page header 的後面。而放在最後面的則 Row offsets。Row offsets 它擺放的順序是從頁尾開始,主要是記載著每個 Data row 它離頁首的距離。

雖然 page 是最基本的儲存單位,但 SQL Server 為了在空間管理上更有效率,它將 8 個連續的 page 空間 ( 64 K) 視為一個 Extent。但如果你的資料量很小,則 SQL Server 就不會主動幫你建立一個 Extent。

Extent 因裡面 8 個 page 的型態,而有 Uniform extents 與 Mixed extents。簡言之,如果你的 8 個 page 都是同一個型態,則稱為  Uniform extents ,反之則為  Mixed extents。

以上圖為例, Mixed extent 裡頭 同時包含了 table2, table3, index1, index2, index3 等等的混何型態,所以稱為 Mixed extent。而 Uniform extent 裡面的 8 個 page 則都是 table1。





文獻參考:

2009年3月20日 星期五

動態置換 Master Page

在 .Net 2.0 提供了 Master Page 功能,可以讓我們將事先定義好的樣板快速的套用在各個開發頁面。接下來要介紹的,是讓一個頁面可以透過程式動態的去變更頁面的 Master Page。

舉個例子來說,我們設計了兩個 Master Page,一個叫做 MTeacher.master (專門提供給老師看的樣板),另一個叫 MStudent.master(專門提供給學生看的樣板)。當檢視我們頁面的使用者是老師時,就要選用 MTeacher.master,當視我們頁面的使用者是學生時,就要選用 MStudent.master。

直覺的,很像可以在程式裡直接去設定  MasterPageFile ,如下所示:


protected void Page_Load(object sender, EventArgs e)
{
MasterPageFile = "MTeacher.master";
}

但回傳的結果卻是:
'MasterPageFile' 屬性只能在 'Page_PreInit' 事件內或之前設定。

根據錯誤訊息的提示,如果要設定 MasterPageFile ,必須要在 Page_PreInit 事件執行才可以。所以,改採用 覆寫 Page_PreInit 事件,應該就可以了。動手改一下程式如下:

protected override void OnPreInit(EventArgs e)
{
MasterPageFile = "MStudent.master";
string strType = "" + Request["isTeacher"];

if(strType=="1")
MasterPageFile = "MTeacher.master";


base.OnPreInit(e);
}


為了簡單起見,透過 URL 參數 isTeacher 來決定登入者角色是否為老師。 當 isTeacher 是 1 時,即表示目前是老師在檢視頁面;如果不是 1 ,則為學生。程式修改後,就可以正確的呈現出我們所希望的樣子了。

當你有需要更換 MasterPage 樣板時,記得要覆寫 Page_PreInit 事件,並在這事件裡完成你的程式。

2009年3月16日 星期一

為什麼我的 Button 沒有呼叫 __doPostBack

一如往常所見,檢視網頁原始碼時,可以找到 __doPostBack 的 JavaScript 宣告。同時包含著兩個 hidden 欄位的宣告: __EVENTTARGET, __EVENTARGUMENT。


<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />

function __doPostBack(eventTarget, eventArgument) {
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit();
}
}

__EVENTTARGET 用來儲存是誰觸發了 PostBack。
__EVENTARGUMENT 則是用來儲存這次的 PostBack 是否有其它參數須一併傳遞。

以 DropDownList 為例,在網頁放置一個 DropDownList 後,它的原始碼變為

<select name="DropDownList1" onchange="javascript:setTimeout('__doPostBack(\'DropDownList1\',\'\')', 0)" id="DropDownList1">
<option value="A">A</option>
<option value="B">B</option>
</select>

當你的 DropDownList 的挑選項目被更動之後,就會觸發__doPostBack( )。eventTarget指的是造成發生PostBack的控制項是誰?而 eventArgument則是觸發PostBack同時,是否有其他參數需要傳遞。
在範例中,當發生PostBack時,就可以知道造成PostBack的就是 DropDownList1 ,而此次並沒有其他參數傳遞,所以是空字串。__doPostBack( ) 此時會將2個隱藏欄位(__EVENTTARGET,__EVENTARGUMENT)作一次更新後再將本頁面送出(Submit)。透過這種機制,送出後新載入的頁面,就可以透過
string strTarget = ""+Request.Form["__EVENTTARGET"];
來取得觸發PostBack的物件是誰了。
 

然而,這種機制並不適合 ButtonImageButton 兩個控制項。
現在再拉一個Button控制項並檢視它的原始碼。

<input type="submit" name="Button1" value="WebControl" id="Button1" />

可以看到Button的原始碼並沒有去呼叫__doPostBack( )。而先前提到的兩個隱藏欄位 __EVENTTARGET,__EVENTARGUMENT 也就不會被更新,當頁面送出後,還可以透過 Request.Form["__EVENTTARGET"] 去抓到觸發 PostBack 的控制項是誰嗎?試著測試一下,您會發現得到的是空白。所以,為何 Bubbon 或 ImageButton 在 PostBack 之後的頁面無法透過 Request.Form["__EVENTTARGET"] 抓到值,主要是它產生的程式碼裡並非透過 __doPostBack( )來實作,也沒有留下紀錄到 __EVENTTARGET 隱藏欄位裡頭,所以才會抓不到資料。
 

雖然 Button 或 ImageButton 沒有辦法讓送出後的頁面抓到 __EVENTTARGET 的值,但可以有其他的選擇。捨棄 Sever Control 改用 Html Control。在 VS(Visual Studio) 的工具箱裡,選擇 HTML 的群組,拉一個 HTML Button 控制項出來,同時將這個控制項的屬性設定為【以伺服器控制項執行】(其實就是設定 runat="server"),接著在 HTML Button 快點兩下,以產生 onserverclick 事件。做完這些動作後,檢視程式碼可以發現如下的改變:

<input language="javascript" onclick="__doPostBack('IamHtmlButton','')" name="IamHtmlButton" type="button" id="IamHtmlButton" value="HtmlControlinServer" />

這個HTML Button 使用了 __doPostBack( ) ,不意外的,我們可以在送出後的頁面抓到 __EVENTTARGET 裡面所記錄的值,就是這個 HTML Button。
 

參考資料:
[1]Understanding the JavaScript __doPostBack Function
[2]藍色小舖