網站連結

最新回應

點部落 是使用 SubText 1.96 版,而很榮幸可以看到一個寫的不錯的 ASP.NET 的系統,
在 SubText 有許多不錯的觀念及實做,Dotjum 希望能夠慢慢的將這些整理出來,
分享給大家,並且自己做一個記錄。

第一篇就先介紹在 SubText ASP.NET 的分頁方法,
1.一般ASP.NET分頁
一般來說在ASP.NET透過GridView等相關控制項做分頁,如果資料是 1000 筆,GirdView 一頁10筆,
在你按分頁的時候,後端SQL會查去1000筆出來 傳給 IIS Server 再傳給前端的IE。
image 

所以對整個效能及傳輸來看,是有點浪費了一些,
或許你ASP.NET 2.0 使用了 xxxxDataSource 裡面 CacheDuration 等相關選項,
但在每次用戶端分頁還是向IIS主機要了1000筆資料。
而GridView的分頁需透過PostBack方式,在SEO(搜尋引擎最佳化)比較不友善,
因為Google可能不會觸發doPostBack。
而這方面就不特別實做出來,相信大家平常都常使用這種分頁方式。

2.將資料先查到Cache再透過定義超連結控制項自訂分頁

而在還沒有看到SubText TSQL的時候,Dotjum 是用另一種作法,
這種作法是參考 Maximizing ASP.NET: Real World, Object-Oriented Development 章節中取出。

在取資料表資料前,先判斷是否有存取過,沒有存取過則加入Cache ,有則取用Cache

//
    public DataTable GetListI(ItemName ItemName)
    {
        HttpContext context = HttpContext.Current;
        //當查詢的區塊編號的編號cache不存在
        if (context.Cache[ItemName.ToString()] == null)
        {
              // 與資料庫相連取資料的程式
              取資料();
              //將資料放入設定名稱的Cache
              CreateCache( ItemName.ToString(), dtData); 
         }
         else
        {
            //將目前已經查詢過的區塊號碼 Cache 轉為 DataTable
            dtData = (DataTable)context.Cache[ItemName.ToString()];
        }
        return dtData;
   }
   //建立Cache的副程式
    private void CreateCache(string inCacheName, DataTable inDataTable)
    {
        HttpContext context = HttpContext.Current;
        context.Cache.Insert(inCacheName, inDataTable, null, DateTime.Now.AddMinutes(30), TimeSpan.Zero);
    }

而在符合 SEO  的分頁這邊ASPX 則以超連結方式來做分頁功能
.aspx

<table border="0" align="center" cellpadding="5" cellspacing="0" class="basic">
    <tbody>
        <tr>
            <td>
                頁次
                <asp:Label ID="lblCurPage" runat="server"></asp:Label>/<asp:Label ID="lblTotalPage"
                    runat="server"></asp:Label></td>
            <td>
            </td>
            <td>
                (共有<asp:Label ID="lblRowsCount" runat="server"></asp:Label>筆資料)
            </td>
            <td>
                <asp:HyperLink ID="lnkFirst" runat="server">第一頁</asp:HyperLink></td>
            <td>
                |
            </td>
            <td>
                <asp:HyperLink ID="lnkPrev" runat="server">上一頁</asp:HyperLink>
            </td>
            <td>
                |
            </td>
            <td>
                <asp:HyperLink ID="lnkNext" runat="server">下一頁</asp:HyperLink>
            </td>
            <td>
                |
            </td>
            <td>
                <asp:HyperLink ID="lnkLast" runat="server">末頁</asp:HyperLink>
            </td>
            <td>
                |
            </td>
            <td>
                &nbsp;<asp:HyperLink ID="lnkRss" runat="server" ImageUrl="~/images/rss.gif" NavigateUrl="~/Rss.ashx">lnkRss</asp:HyperLink></td>
        </tr>
    </tbody>
</table>

而在頁面 .cs 這邊則使用 PagedDataSource 來做分頁功能,再透過程式來產生符合SEO的分頁方式。
.cs
PagedDataSource objPage = new PagedDataSource();

private void RepeaterDataBind(iNetItemName Item)
    {        
        dtData = sysFacade.GetiNetBoardListInBlock(Item);
        //來源
        objPage.DataSource = dtData.DefaultView;
        //允許分頁
        objPage.AllowPaging = true;
        //可以顯示一頁的項目
        objPage.PageSize = 10;
        //判斷是否有要分頁的動作
        int CurPage;
        if (Request.QueryString["Page"] != null)
        {
            if (Regex.IsMatch(Request.QueryString["Page"], "^(\\d)?\\d*$") == true)
            {
                CurPage = Convert.ToInt32(Request.QueryString["Page"]);
            }
            else
            {
                CurPage = 1;
            }
            if (objPage.PageCount < CurPage || CurPage < 1)
            {
                CurPage = 1;
            }
        }
        else
        {
            CurPage = 1;
        }
        //設為目前頁的索引
        objPage.CurrentPageIndex = CurPage - 1;
        //顯示訊息
        lblCurPage.Text = CurPage.ToString();
        lblTotalPage.Text = objPage.PageCount.ToString();
        lblRowsCount.Text = objPage.DataSourceCount.ToString();      
        //如果目前頁不是第一頁
        if (!objPage.IsFirstPage)
        {
            //定義上一頁的超連結為 目前頁 -1
            lnkPrev.NavigateUrl = Request.CurrentExecutionFilePath + "?Page=" + Convert.ToString(CurPage - 1);
        }
        //如果目前頁不是最後一頁
        if (!objPage.IsLastPage)
        {            //定義下一頁的超連結為 目前頁 +1
            lnkNext.NavigateUrl = Request.CurrentExecutionFilePath + "?Page=" + Convert.ToString(CurPage + 1);
        }
        lnkFirst.NavigateUrl = Request.CurrentExecutionFilePath + "?Page=1";
        lnkLast.NavigateUrl = Request.CurrentExecutionFilePath + "?Page=" + objPage.PageCount.ToString();
        rptList.DataSource = objPage;
        rptList.DataBind();
    }


而我們第二個自訂分頁的方式,主要解決的是在資料的傳輸當中,第一次在查詢的時候傳送1000筆資料,
而在Cache有效的時間內,則不會在到SQL主機在多做查詢,頁面分頁將與IIS主機互動。節省了往後查的時間。
image
當然在頁面分頁的按鈕,也不是透過PostBack的方式,在SEO方面也做了改善。
***  補充  ***
1.當然你可能會遇到,那快取時間內,若有新增資料怎麼辦?
  可以在新增資料的時候,將目前我們透過傳參數方式定義的Cache時清空為null,這樣在分頁存取讀取時,
  就會在往後端SQL再查詢資料。
2.是不是只能分 上一頁 下一頁 ?
  是可以再做跳頁的功能,多拉一個 DropDownList 加上一些程式碼來判斷。

當然這還不是最好的方式,目前Dotjum看到SubText的方法更不錯,為了讓大家能夠感受這段TSQL的威力,
Dotjum 這邊以 Northwind 資料庫為例。
SELECT * FROM Orders  可以看到總共有830 筆資料
image

而Dotjum將介紹透過TSQL則可輕鬆製造出分頁功能
首先是先透過 目前頁次 * 分頁顯示數量 + 1 來求出要取得哪一個欄位的比較值
透過 SET ROWCOUNT 取得第 x 欄位比較值
(這個地方可能比較模糊,引用SQL 文件來做說明,說明寫到)
使 SQL Server 在傳回指定的資料列數之後,停止處理查詢。
透過與關鍵值比較,就能求出所要顯示的值

-- 判斷依據 (時間) 也可以用其他
DECLARE @FirstDate DateTime
DECLARE @StartRow int
DECLARE @StartRowIndex int
-- 要顯示第幾頁
DECLARE    @PageIndex INT 
--一頁顯示幾個
DECLARE    @PageSize INT
-- 頁次
SET @PageIndex = 0
-- 數量
SET @PageSize = 10
SET @StartRowIndex = @PageIndex * @PageSize + 1
-- 取得要關鍵比較的欄位 選到第幾個
SET ROWCOUNT @StartRowIndex
SELECT @FirstDate = OrderDate FROM Orders
ORDER BY OrderDate,ORDERID DESC
 
-- 設定一頁顯示幾個
SET ROWCOUNT @PageSize
SELECT * FROM Orders 
--與關鍵值比較
WHERE OrderDate >= @FirstDate
ORDER BY OrderDate,ORDERID DESC
這邊用連環圖來說明一下,在執行第一次的時候,第一個SELECT 取@FirstDate
當你傳入 PageIndex =0 給這段 TSQL 時,取得@FirstDate 後,去做比較取10筆,
TSQL 查詢只回傳10筆。


image 

當你傳入 PageIndex =1 (為第二頁)給 TSQL 時,也是只傳回10筆,但這10筆是原本830筆中的11-20
image

就這樣非常的輕鬆,就可以做到效能較佳的分類方式,我們主要解決的是,
讓每一次的分頁都只會有10筆資料的傳送,不管你本身資料有多少千筆,
每次都為我們設定的10筆的方式傳送。

image

相信大家再看了Dotjum的第三個範例後,一定很想試試看,而在 點部落 首頁技術文章的分頁,
就是透過這種方式來處理的。而分頁的控制項是SubText提供,Dotjum還沒把整個程式碼看懂,
等看懂之後,再來分享一篇關於 分頁控制項的程式碼給大家。
在請大家多給予一些指教或分享其他分頁更好的方式。

補充:分頁SQL 已經流傳很久,但Dotjum之前一直沒有很詳細的瞭解原理,直到使用SubText才瞭解。


DotBlogs Tags: ASP.NET Dotjum GetPageable TSQL 分頁

關連文章

[TSQL]模擬 SELECT FROM Stored Procedure

[TSQL]使用TSQL將類特殊符號、,等符號,一列資料轉為多筆(類似split功能)

回應

  • # re: [SubText心得]ASP.NET TSQL 效能較佳分頁方法及友善 SEO 的分頁 by brian

    大大這範例 真是清楚 謝謝分享

    2008/2/25 下午 04:32 | 回覆

  • # re: [SubText心得]ASP.NET TSQL 效能較佳分頁方法及友善 SEO 的分頁 by platstar

    請問這個與每頁重新建立connection的cost相比,划得來嗎?

    2008/6/4 下午 05:01 | 回覆

  • # re: [SubText心得]ASP.NET TSQL 效能較佳分頁方法及友善 SEO 的分頁 by dotjum

    to platstar:
    我認為對效能是有幫助,如果是一般GridView內建分頁,也是拉全部的資料下來及產生連線。
    目前第三種方法則降低傳回來的資料,至於連線數,我自己的觀察再設定SqlConnection pool 的時候,連線的關閉並沒有及時的關閉,而是等待下一個連線直接串起來,當然超過pool的時候,連線數就會新開。
    所以我認為是划得來,這是我自己認為的啦,不知道大家有什麼看法,也可以給一些指教。

    2008/6/4 下午 10:51 | 回覆

  • # re: [SubText心得]ASP.NET TSQL 效能較佳分頁方法及友善 SEO 的分頁 by antai

    非常棒的作法!
    這篇範例的關鍵是SET ROWCOUNT與[鍵值]比較這兩段觀念,
    因為小弟也是一個熱愛TSQL的人,所以上述的範例若改寫成
    預儲程序,應該效能會更高喔!!

    2008/12/14 上午 11:21 | 回覆

  • # re: [SubText心得]ASP.NET TSQL 效能較佳分頁方法及友善 SEO 的分頁 by dotjum

    to anta :
    謝謝你的回應,最後一個範例 SET ROWCOUNT 的方式,我在使用上也是包裝成 StoreProcedure ,有機會可以一起來分享一下TSQL相關的技術討論。 在資料庫開發團隊還有蠻多大家分享的TSQL相關應用的好文,你可以連過去看看,有沒有興趣要一起加入阿?   http://www.dotblogs.com.tw/Team.aspx?GroupID=504
     

    2008/12/16 上午 10:44 | 回覆

  • # re: [SubText心得]ASP.NET TSQL 效能較佳分頁方法及友善 SEO 的分頁 by grace

    上列程式碼可解說一下嗎?
    iNetItemName 需要宣告命名空間嗎?
    sysFacade 是什物件類別

    -------------------------------------------
    private void RepeaterDataBind(iNetItemName Item)
    {
    sysFacade.GetiNetBoardListInBlock(Item);
    :
    :
    }

    2009/3/4 下午 02:32 | 回覆

  • # re: [SubText心得]ASP.NET TSQL 效能較佳分頁方法及友善 SEO 的分頁 by dotjum

    to grace :
    不好意思,沒注意到把這段說清楚

    1.這段Code 丟入的參數 iNetItemName Item 視依照你的狀況換成你的變數
    private void RepeaterDataBind(iNetItemName Item)

    ex: private void RepeaterDataBind(string youType)

    2.這是我去讀取後端資料庫的程式
    sysFacade.GetiNetBoardListInBlock(Item);
    你就依你的狀況改為你的用法
    ex:
    dtData = 叫資料庫資料的副程式(丟進來的程式 youType);

     

    2009/3/4 下午 02:54 | 回覆

  • # re: [SubText心得]ASP.NET TSQL 效能較佳分頁方法及友善 SEO 的分頁 by kim

    講得很詳細喔 感謝分享

    2009/7/21 上午 09:14 | 回覆

  • # re: [SubText心得]ASP.NET TSQL 效能較佳分頁方法及友善 SEO 的分頁 by AAA

    的確不錯
    但這樣是綁定SQL

    但是遇到很難用SQL語法實作的報表時,這方法會變很複雜吧...但放資料在Cache上...又會爆,看來蠻困難的

    2010/2/10 下午 02:10 | 回覆

  • # re: [SubText心得]ASP.NET TSQL 效能較佳分頁方法及友善 SEO 的分頁 by Dotjum

    to AAA :
    若以報表呈現的話,會讀取全部的資料, 交由報表的分頁來處理,我遇到的案例,報表不是隨時都在執行

    2010/5/2 上午 11:01 | 回覆

  • # re: [SubText心得]ASP.NET TSQL 效能較佳分頁方法及友善 SEO 的分頁 by minelin

    抱歉想請教第三個範例看起來那個關鍵比較欄位是一定要用到的 可是某些情形下沒有這種欄位可供比較的話是否就沒解了?

    2010/6/12 下午 04:39 | 回覆

  • # re: [SubText心得]ASP.NET TSQL 效能較佳分頁方法及友善 SEO 的分頁 by guan

    我雖然還沒試作者的程式,但我猜ORDER BY 的欄位都加進去當比對欄位,或許可以解決

    2010/6/28 下午 04:17 | 回覆

  • # re: [SubText心得]ASP.NET TSQL 效能較佳分頁方法及友善 SEO 的分頁 by Dreamyi

    這個討論有點問題,第一張圖使用 ASP.NET 內建的分頁,以您所提的例子來說,IIS 主機傳給使用者端瀏覽器的資料量是 10 筆不是 1000 筆喔。

    2010/8/14 下午 11:17 | 回覆

  • # re: [SubText心得]ASP.NET TSQL 效能較佳分頁方法及友善 SEO 的分頁 by 姿

    我最近也被這個效能問題搞的團團轉...
    想請問一下....
    "在取資料表資料前,先判斷是否有存取過,沒有存取過則加入Cache ,有則取用Cache"
    "public DataTable GetListI(ItemName ItemName)"

    要怎麼做><""

    (真的很菜...唉...)
    (http://www.blueshop.com.tw/board/FUM20041006161839LRJ/BRD20101011131938N0E.html)

    2010/10/11 下午 04:30 | 回覆

登入後使用進階評論

Please add 5 and 7 and type the answer here: