select * from GLENN.LOTSOFRECORDS這種做法應當避免,而應力求只檢索需要的字段。可以在SQL 語句中定義要檢索的字段,例如: select KEYCOL, COL1, COL2, COL7 from GLENN.LOTSOFRECORDS |
在本文附帶的源程序中,有兩個ASP.NET頁面:一個是RetrievingAllFields.aspx,它執行第一個查詢;另一個是RetrievingLimitedFields.aspx ,它執行第二個查詢,即只檢索需要的字段。 用TimeDiff類進行檢測,執行第一個查詢用了1.622 秒,執行第二個查詢用了1.311秒。后者用時只是前者的80%,不僅用時少,而且還減少了Web應用程序和數據庫服務器之間的網絡數據堵塞。 這個例子只限制了檢索的字段,你還可以使用WHERE語句限制檢索的記錄數。WHERE 語句可以限制服務器返回的記錄數(見程序清單3)。要記住,通過網絡發送的記錄數據越少,對應用程序、數據庫、用戶和網絡越有好處。 規則2:優化數據庫 有時候你的Web應用程序可能運行得不錯,但你想讓它更好。一個簡單的減少搜索時間的方法是為特定字段創建索引。如果有一個查詢是要搜索某個價格范圍內的產品(見程序清單3),但你沒有為價格字段定義索引,那么返回數據就會多花一些時間。而一旦建立了索引,DB2會很快返回你想要的結果。 程序清單3. 利用索引進行數據庫搜索 SELECT PRODUCTCODE, PRODUCTNAME, DESCRIPTION, UNITPRICEFROM GLENN.PRODUCTLIST WHERE UNITPRICE > 20.00 |
優化數據庫不只是為搜索字段創建索引這么一條,你應當盡可能多地搜集相關的DB2信息以使應用程序運行得更好。經常訪問IBM發者園地(IBM DB2 Developer Domain)和comp.databases.ibm-db2(comp.databases.ibm-db2)等一些相關的Web站點或新聞組,對于保持DB2開發技巧不斷更新是一個很好的辦法。 你還應當努力熟悉DB2附帶的工具,例如DB2索引建議器(Index Advisor)。DB2索引建議器可以根據你遞交的查詢和所連接的數據庫返回最佳索引列表。 規則3:使用DB2 UDB的OLAP功能改善分頁 在ASP.NET中,一個最常見的操作是表格分頁顯示。ASP.NET中DataGrid組件的默認設置是將表格需要的所有記錄都返回客戶端,然后再根據選擇的頁顯示相應記錄. 程序清單4 使用DataGrid 內建分頁機制 TimeDiff diff = new TimeDiff();private DataSet GetProductsDataSet() {diff.Start();string connString = ConfigurationSettings.AppSettings["database"];BdpConnection conn = new BdpConnection(connString);BdpDataAdapter da = new BdpDataAdapter("select KEYCOL, " +"COL1, COL2, COL7 FROM GLENN.LOTSOFRECORDS "+"ORDER BY KEYCOL ASC", conn);DataSet ds = new DataSet();da.Fill(ds, "Table1");diff.Stop();return ds;}private void BindToTheData(){dataGrid1.DataSource = GetProductsDataSet();dataGrid1.DataMember = "Table1";dataGrid1.DataBind();label1.Text = diff.TimeDifferenceText;}private void Page_Load(object sender, System.EventArgs e){if (!IsPostBack) {BindToTheData();}}private void dataGrid1_PageIndexChanged(object source, System.Web.UI.WebControls.DataGridPageChangedEventArgs e){//Change the active page of the datadataGrid1.CurrentPageIndex = e.NewPageIndex;BindToTheData();} |
如果以LOTSOFRECORDS表為例,從數據庫中檢索1萬條記錄很快就會占盡網絡帶寬,尤其是一次只需要查看10條或20條記錄時。用戶會發現加載ASP.NET頁面的時間太長,而且很可能會超時。試想,如果數據庫有數百萬條記錄,那你的應用程序就會運行緩慢只至停止執行。因此,需要采取更好的方法來檢索數據。 還好,DataGrid組件允許定制分頁。你可以計算哪些記錄需要顯示,然后只從服務器檢索出相應的記錄。 后來版本的DB2 UDB都具有一個很大的特點,那就是OLAP函數,它允許你進行各種記錄檢索。例如,只檢索某些記錄可以執行如下的查詢: SELECT * FROM (SELECT KEYCOL, COL1, COL2, COL7, rownumber() over(ORDER BY KEYCOL ASC) AS rn FROM GLENN.LOTSOFRECORDS ORDER BY KEYCOL ASC) AS a1 WHERE a1.rn BETWEEN 100 AND 120 |
使用DataGrid定制分頁時,需要獲得特定頁的DataSet。GetDataByPage方法可以檢索結果集而不管分頁數和分頁大小: private DataSet GetDataByPage(int PageNo, int PageSize, out int NumberOfPages){int startRecord = (PageNo - 1) * PageSize + 1;int endRecord = startRecord + PageSize - 1;string connString = ConfigurationSettings.AppSettings["database"];BdpConnection conn = new BdpConnection(connString);conn.Open();//Get the number of Pagesstring sRecordCount = "select count(*) from GLENN.LOTSOFRECORDS";BdpCommand cmdGetRecordCount = new BdpCommand(sRecordCount, conn);int intRecordCount = (int)cmdGetRecordCount.ExecuteScalar();NumberOfPages = intRecordCount / PageSize;if (intRecordCount % PageSize > 0)NumberOfPages++;//Get the data specifically for the pagestring sSQL ="SELECT * FROM " +" (SELECT KEYCOL, COL1, COL2, COL7, rownumber() " +" over(ORDER BY KEYCOL ASC) AS rn " +" FROM GLENN.LOTSOFRECORDS " +" ORDER BY KEYCOL ASC) AS a1 " +" WHERE a1.rn BETWEEN ? AND ?";BdpCommand cmdSel = new BdpCommand(sSQL, conn);BdpParameter prmStart =cmdSel.Parameters.Add("StartRecord", BdpType.Int32);prmStart.Value = startRecord;BdpParameter prmEnd =cmdSel.Parameters.Add("EndRecord", BdpType.Int32);prmEnd.Value = endRecord;BdpDataAdapter da = new BdpDataAdapter(cmdSel, conn);DataSet ds = newDataSet();da.Fill(ds, "Table1");diff.Stop();return ds;}private void LoadSingleDataPage(int pageNo){//Display the Page contentsint PageCount;DataSet dsData = GetDataByPage(pageNo+1,dataGrid1.PageSize, out PageCount);dataGrid1.VirtualItemCount = PageCount * dataGrid1.PageSize;dataGrid1.CurrentPageIndex = pageNo;dataGrid1.DataSource = dsData;dataGrid1.DataBind();}private void Page_Load(object sender, System.EventArgs e){if (!IsPostBack){LoadSingleDataPage(0);}}private void dataGrid1_PageIndexChanged(object source, System.Web.UI.WebControls.DataGridPageChangedEventArgs e){LoadSingleDataPage(e.NewPageIndex);} |
通過定制分頁,將檢索記錄數從1萬條限制到20條,占用的網絡資源約為最初的0.2%。在我的本機用TimeDiff 類檢測,使用定制分頁時用時0.5~0.7秒,而使用默認分頁機制時用時為0.9~1.5秒。 規則4:使用存儲過程 如果發送一條SQL語句到DB2服務器,其執行過程如下: (1)DB2 UDB Server對SQL語句進行語法檢查; (2)生成存儲過程執行計劃; (3)數據返回應用程序。 當使用存儲過程時,前兩步過程已經完成。存儲過程經編譯后,調用時只將存儲過程名和參數傳遞給數據庫服務器。因此,執行時間的減少贏得了性能上的優勢。但這種優勢只有當返回的結果集非常大時才有所體現。 下面舉一個例子。先建立一個PRODUCTLIST表: CREATE TABLE "GLENN "."PRODUCTLIST" ("PRODUCTCODE" VARCHAR(20) NOT NULL , "PRODUCTNAME" VARCHAR(50) NOT NULL , "DESCRIPTION" VARCHAR(255) , "UNITPRICE" DOUBLE NOT NULL , "CATEGORYCODE" INTEGER , "IMAGEURL" CHAR(150) ) IN "USERSPACE1" ; COMMENT ON TABLE "GLENN "."PRODUCTLIST" IS 'A list of Products in the Shopping Cart';-- DDL Statements for primary key on Table "GLENN "."PRODUCTLIST"ALTER TABLE "GLENN "."PRODUCTLIST" ADD CONSTRAINT "CC1053568050795" PRIMARY KEY("PRODUCTCODE"); |
然后進行如下查詢: SELECT PRODUCTLIST.PRODUCTCODE, PRODUCTLIST.PRODUCTNAME, PRODUCTLIST.DESCRIPTION, PRODUCTLIST.UNITPRICE, PRODUCTLIST.IMAGEURLFROM GLENN.PRODUCTLIST AS PRODUCTLISTWHERE PRODUCTLIST.CATEGORYCODE = 2; |
以上查詢很容易轉為存儲過程。DB2開發中心(DB2 Development Center)包含一個優秀的存儲過程向導,它可以讓你輕松生成存儲過程。 存儲過程向導啟動后,你只需要選擇相應的表、字段和規則,存儲過程的創建過程由向導來完成。 存儲過程向導的一個極為有用之處是可以利用它輕松創建存儲過程的輸入參數。創建一個SQL 存儲過程(DB2 還能創建Java存儲過程),可以選擇“Category Code”作為存儲過程的輸入參數。 完成后,所創建的存儲過程如下: CREATE PROCEDURE GLENN.GETPRODUCTSINCATEGORY ( IN CATCODE INTEGER )DYNAMIC RESULT SETS 1-------------------------------------------------------------------------- SQL Stored Procedure ------------------------------------------------------------------------P1: BEGIN-- Declare cursorDECLARE cursor1 CURSOR WITH RETURN FORSELECT PRODUCTLIST.PRODUCTCODE, PRODUCTLIST.PRODUCTNAME, PRODUCTLIST.DESCRIPTION, PRODUCTLIST.UNITPRICE, PRODUCTLIST.IMAGEURLFROM GLENN.PRODUCTLIST AS PRODUCTLISTWHERE PRODUCTLIST.CATEGORYCODE = CATCODE;-- Cursor left open for client applicationOPEN cursor1;END P1 |
使用存儲過程向導時,可以讓存儲過程返回不止一條查詢的結果。通過這種方法,可以發揮存儲過程的最大優勢。如果結果集很小,使用存儲過程可能要慢于使用查詢。你應當不斷對數據訪問作性能測試。 使用Borland Data Provider調用存儲過程與調用查詢有所不同,主要是BdpDataAdapter的BdpCommand對象必須要將CommandType設為CommandType.StoredProcedure 并將CommandText設為存儲過程名。此外,還需要在BdpCommand對象的參數集合中定義存儲過程參數。 一旦定義好參數,只需使用BdpDataAdapter的Fill 方法填充DataSet: private void GetProductsViaStoredProcedure(int CategoryCode) {cmdGetDataViaStoredProc.Parameters[0].Value = CategoryCode;BdpDataAdapter da = new BdpDataAdapter(cmdGetDataViaStoredProc);da.Fill(dsProducts, "Products");dataGrid1.DataBind();} |
規則5:盡可能使用緩存 ASP.NET最大的特點之一是緩存。緩存的原理很簡單,將經常訪問的內容儲存在內存中,訪問時不需要再到數據庫或通過網絡去檢索數據。訪問內存中的信息總是要比通過其它過程或網絡訪問資源要快。 那么如何使用緩存呢?在ASP.NET中有幾種方法。一種方法是在ASP.NET頁面頭部定義一個頁面指示標識,讓其自動管理頁面緩存。如果你讀過我的上一篇文章《利用IBM DB2 UDB建立ASP.NET站點》(Build ASP.NET Web Sites with IBM DB2 Universal Database),應當很熟悉這種技術。通過包含OutputCache指令,可以緩存整頁: 另一種方法是使用Pages對象內建的Cache 對象。將內容放入緩存時,使用Cache 對象的Insert方法;從緩存取出內容時,使用Cache對象的默認集合。 private void Page_Load(object sender, System.EventArgs e){TimeDiff diff = new TimeDiff();diff.Start();string retrievalMethod;DataSet CategoriesDataSet;if (Cache["Categories"] == null) {retrievalMethod = "Database";connShopping.Open();CategoriesDataSet = new DataSet();daCategories.Fill(CategoriesDataSet, "Categories");Cache.Insert("Categories", CategoriesDataSet);connShopping.Close();} else {retrievalMethod = "Cache";CategoriesDataSet = (DataSet)Cache["Categories"];}diff.Stop();lblDetails.Text = "Retrieval from the " + retrievalMethod +" in " + diff.TimeDifferenceText + " seconds";dataGrid1.DataSource = CategoriesDataSet;dataGrid1.DataMember = "Categories";dataGrid1.DataBind();} |
當頁面第一次被請求時,我在本機測試的數據檢索用時為0.9秒,但從緩存中檢索數據幾乎沒用什么時間,因為TimeDiff類的檢測結果為00:00:00。可見,使用緩存是加速Web應用簡單而有效的方法。 如果需要定時更新數據,還以使用緩存對象的過期策略。只需要使用Insert 方法的重載版本,指定過期時間即可。下面是每隔6小時自動刷新“Categories”緩存的一種方法: Cache.Insert("Categories", CategoriesDataSet, null,System.Web.Caching.Cache.NoAbsoluteExpiration,TimeSpan.FromHours(6)); |
總結 在完美的世界里,應用程序總是執行快速,支持無限用戶,而且不占任何網絡資源。但我們并非置身其中,因此你應當很好地利用本文所概括的有效規則,努力提高Web應用程序的性能。
作者:http://www.zhujiangroad.com
來源:http://www.zhujiangroad.com
※以上資訊由網路資料整理而成,若有遺誤概以來源為準,本站不負任何相關責任。
※如果您認為網站上資訊侵犯了您的版權,請告訴我們 按這裡,我們將即時將您的版權資料移除。
|