[SubText心得]ASP.NET TSQL 效能較佳分頁方法及友善 SEO 的分頁

[SubText心得]ASP.NET TSQL 效能較佳分頁方法及友善 SEO 的分頁

點部落 是使用 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

    <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();

    {        
        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才瞭解。