Účinné stránkování velkých objemů dat (VB)
Výchozí možnost stránkování ovládacího prvku prezentace dat není vhodná při práci s velkými objemy dat, protože jeho podkladový ovládací prvek zdroje dat načítá všechny záznamy, i když se zobrazuje jenom podmnožina dat. Za takových okolností se musíme obrátit na vlastní stránkování.
Úvod
Jak jsme probrali v předchozím kurzu, stránkování je možné implementovat jedním ze dvou způsobů:
- Výchozí stránkování lze implementovat jednoduše zaškrtnutím povolit stránkování možnost v inteligentní značce webového ovládacího prvku dat; Při každém prohlížení stránky dat však ObjectDataSource načte všechny záznamy, i když se na stránce zobrazí pouze jejich podmnožina.
- Vlastní stránkování zlepšuje výkon výchozího stránkování načtením pouze těch záznamů z databáze, které je třeba zobrazit pro konkrétní stránku dat požadovaných uživatelem; Implementace vlastního stránkování ale vyžaduje trochu větší úsilí než výchozí stránkování.
Vzhledem k snadné implementaci stačí zaškrtnout políčko a máte hotovo! výchozí stránkování je atraktivní možnost. Jeho naivní přístup při načítání všech záznamů však z něj dělá nepůletelnou volbu při stránkování dostatečně velkých objemů dat nebo pro weby s mnoha souběžnými uživateli. Za takových okolností se musíme obrátit na vlastní stránkování, abychom zajistili responzivní systém.
Výzvou vlastního stránkování je schopnost napsat dotaz, který vrátí přesnou sadu záznamů potřebnou pro konkrétní stránku dat. Microsoft SQL Server 2005 naštěstí poskytuje nové klíčové slovo pro hodnocení výsledků, které nám umožňuje napsat dotaz, který dokáže efektivně načíst správnou podmnožinu záznamů. V tomto kurzu uvidíme, jak používat toto nové klíčové slovo SQL Server 2005 k implementaci vlastního stránkování v ovládacím prvku GridView. Uživatelské rozhraní pro vlastní stránkování je stejné jako u výchozího stránkování, ale krokování z jedné stránky na druhou pomocí vlastního stránkování může být o několik řádů rychlejší než výchozí stránkování.
Poznámka
Přesný nárůst výkonu, který vlastní stránkování vykazuje, závisí na celkovém počtu stránkovaných záznamů a zatížení databázového serveru. Na konci tohoto kurzu se podíváme na několik hrubých metrik, které ukazují výhody výkonu dosaženého vlastním stránkováním.
Krok 1: Vysvětlení vlastního procesu stránkování
Při stránkování dat závisí přesné záznamy zobrazené na stránce na stránce požadovaných dat a počtu zobrazených záznamů na stránce. Představte si například, že jsme chtěli procházet 81 produkty a zobrazovat 10 produktů na stránku. Při prohlížení první stránky chceme produkty 1 až 10; při prohlížení druhé stránky by nás zajímaly produkty 11 až 20 atd.
Existují tři proměnné, které určují, jaké záznamy se mají načíst a jak se má stránkovací rozhraní vykreslit:
- Start Row Index index prvního řádku na stránce dat k zobrazení; Tento index lze vypočítat vynásobením indexu stránky záznamy, které se zobrazí na stránce, a přidáním jednoho indexu. Například při stránkování záznamů 10 najednou, pro první stránku (jejíž index stránky je 0) je index počátečního řádku 0 × 10 + 1 nebo 1; pro druhou stránku (jejíž index stránky je 1) je index počátečního řádku 1 × 10 + 1 nebo 11.
- Maximum Rows (Maximální počet řádků ): Maximální počet záznamů, které se mají zobrazit na stránce. Tato proměnná se označuje jako maximální počet řádků, protože na poslední stránce může být vráceno méně záznamů, než je velikost stránky. Například při stránkování 81 produktů s 10 záznamy na stránku bude devátá a poslední stránka obsahovat pouze jeden záznam. Žádná stránka ale nebude zobrazovat více záznamů, než je hodnota Maximální počet řádků.
- Total Record Count Celkový počet záznamů, které jsou stránkovány. I když tato proměnná není potřebná k určení toho, jaké záznamy se mají načíst pro danou stránku, diktuje stránkovací rozhraní. Pokud se například stránkuje 81 produktů, stránkovací rozhraní ví, že v uživatelském rozhraní stránkování zobrazí devět čísel stránek.
Při výchozím stránkování se index počátečního řádku vypočítá jako součin indexu stránky a velikost stránky plus jedna, zatímco maximální počet řádků je jednoduše velikost stránky. Vzhledem k tomu, že výchozí stránkování při vykreslování libovolné stránky dat načte všechny záznamy z databáze, je znám index pro každý řádek, takže přechod na počáteční řádek index řádku je triviální úkol. Celkový počet záznamů je navíc snadno dostupný, protože se jedná jednoduše o počet záznamů v tabulce DataTable (nebo jakýkoli objekt, který se používá k uložení výsledků databáze).
Vzhledem k proměnným Index počátečního řádku a Maximální počet řádků musí vlastní implementace stránkování vracet pouze přesnou podmnožinu záznamů počínaje indexem počátečního řádku a až do maximálního počtu řádků záznamů po této hodnotě. Vlastní stránkování má dva problémy:
- Musíme být schopni efektivně přidružit index řádků ke každému řádku v celých stránkovaných datech, abychom mohli začít vracet záznamy v zadaném indexu počátečního řádku.
- Musíme zadat celkový počet záznamů, které jsou stránkovány.
V dalších dvou krocích prozkoumáme skript SQL, který je potřeba k reakci na tyto dva výzvy. Kromě skriptu SQL budeme také potřebovat implementovat metody v DAL a BLL.
Krok 2: Vrácení celkového počtu stránkovaných záznamů
Než prozkoumáme, jak načíst přesnou podmnožinu záznamů pro zobrazenou stránku, podívejme se nejprve na to, jak vrátit celkový počet záznamů, které jsou stránkovány. Tyto informace jsou potřeba ke správné konfiguraci uživatelského rozhraní stránkování. Celkový počet záznamů vrácených konkrétním dotazem SQL je možné získat pomocí COUNT
agregační funkce. Například k určení celkového počtu záznamů v Products
tabulce můžeme použít následující dotaz:
SELECT COUNT(*)
FROM Products
Pojďme do dal přidat metodu, která vrátí tyto informace. Konkrétně vytvoříme metodu DAL s názvem TotalNumberOfProducts()
, která provede SELECT
výše uvedený příkaz.
Začněte otevřením Northwind.xsd
souboru Typed DataSet ve App_Code/DAL
složce . Potom klikněte pravým tlačítkem na ProductsTableAdapter
položku v Designer a zvolte Přidat dotaz. Jak jsme viděli v předchozích kurzech, umožní nám to přidat novou metodu do DAL, která při vyvolání provede konkrétní příkaz SQL nebo uloženou proceduru. Stejně jako u našich metod TableAdapter v předchozích kurzech se v tomto případě rozhodněte, že použijete příkaz SQL ad hoc.
Obrázek 1: Použití ad hoc příkazu SQL
Na další obrazovce můžeme určit, jaký typ dotazu se má vytvořit. Vzhledem k tomu, že tento dotaz vrátí jednu skalární hodnotu, zvolte SELECT
možnost , která vrátí hodnotu singe, celkový počet záznamů v Products
tabulce.
Obrázek 2: Konfigurace dotazu tak, aby používal příkaz SELECT, který vrací jednu hodnotu
Po určení typu dotazu, který se má použít, musíme dále zadat dotaz.
Obrázek 3: Použití dotazu SELECT COUNT(*) FROM Products
Nakonec zadejte název metody . Jak je uvedeno výše, použádejme .TotalNumberOfProducts
Obrázek 4: Pojmenování metody DAL TotalNumberOfProducts
Po kliknutí na Dokončit průvodce přidá metodu TotalNumberOfProducts
do souboru DAL. Skalární návratové metody v DAL vrací typy s možnou hodnotou null pro případ, že by výsledek dotazu SQL byl NULL
. Náš COUNT
dotaz ale vždy vrátí hodnotu, která neníNULL
. Bez ohledu na to vrátí metoda DAL celé číslo s možnou hodnotou null.
Kromě metody DAL potřebujeme také metodu v BLL. ProductsBLL
Otevřete soubor třídy a přidejte metoduTotalNumberOfProducts
, která jednoduše volá metodu DAL sTotalNumberOfProducts
:
Public Function TotalNumberOfProducts() As Integer
Return Adapter.TotalNumberOfProducts().GetValueOrDefault()
End Function
Metoda DAL s TotalNumberOfProducts
vrátí celé číslo s možnou hodnotou null, ale vytvořili jsme metodu ProductsBLL
třídy s TotalNumberOfProducts
, aby vrátila standardní celé číslo. Proto potřebujeme, aby ProductsBLL
metoda třídy s TotalNumberOfProducts
vrátila část hodnoty celého čísla s možnou hodnotou null vrácenou metodou DAL s TotalNumberOfProducts
. Volání GetValueOrDefault()
vrátí hodnotu celého čísla s možnou hodnotou null, pokud existuje. Pokud je null
celé číslo s možnou hodnotou null , vrátí výchozí celočíselnou hodnotu 0.
Krok 3: Vrácení přesné podmnožině záznamů
Naším dalším úkolem je vytvořit metody v DAL a BLL, které přijímají proměnné Index počátečního řádku a Maximální počet řádků uvedené výše a vrátí příslušné záznamy. Než to uděláme, podívejme se nejprve na potřebný skript SQL. Problémem, kterému čelíme, je, že musíme být schopni efektivně přiřadit index ke každému řádku v rámci celého stránkování výsledků, abychom mohli vrátit pouze ty záznamy počínaje indexem počátečního řádku (až do maximálního počtu záznamů).
To není problém, pokud už v tabulce databáze existuje sloupec, který slouží jako index řádků. Na první pohled se můžeme domnívat, že Products
pole tabulky ProductID
s bude stačit, protože první produkt má ProductID
hodnotu 1, druhý hodnotu 2 atd. Odstranění produktu však ponechá mezeru v sekvenci, což tento přístup zruší.
K efektivnímu přidružení indexu řádků k datům, která se mají procházet stránkami, se používají dvě obecné techniky, které umožňují načtení přesné podmnožiny záznamů:
Při použití SQL Server 2005 s
ROW_NUMBER()
Klíčové slovo nové pro SQL Server 2005 klíčovéROW_NUMBER()
slovo přidruží ke každému vráceným záznamům hodnocení na základě nějakého pořadí. Toto pořadí lze použít jako index řádku pro každý řádek.Použití proměnné tabulky a
SET ROWCOUNT
SQL Server sSET ROWCOUNT
příkaz lze použít k určení celkového počtu záznamů, které má dotaz zpracovat před ukončením; Proměnné tabulky jsou místní proměnné T-SQL, které mohou obsahovat tabulková data, podobné dočasným tabulkám. Tento přístup funguje stejně dobře s Microsoft SQL Server 2005 a SQL Server 2000 (zatímcoROW_NUMBER()
přístup funguje pouze s SQL Server 2005).Cílem je vytvořit proměnnou tabulky, která obsahuje
IDENTITY
sloupec a sloupce pro primární klíče tabulky, jejíž data jsou stránkována. Dále se obsah tabulky, jejíž data jsou stránkována, vypíše do proměnné tabulky, čímž se přidružuje sekvenční index řádků (prostřednictvímIDENTITY
sloupce) pro každý záznam v tabulce. Jakmile je proměnná tabulky naplněna,SELECT
je možné provést příkaz pro proměnnou tabulky, který je spojený s podkladovou tabulkou, aby se vytáhly konkrétní záznamy. PříkazSET ROWCOUNT
slouží k inteligentnímu omezení počtu záznamů, které je potřeba vypsat do proměnné tabulky.Efektivita tohoto přístupu je založená na požadovaném čísle stránky, protože hodnotě
SET ROWCOUNT
je přiřazena hodnota Index počátečního řádku plus Maximální počet řádků. Tento přístup je velmi efektivní při stránkování na stránkách s nízkým číslem, jako je několik prvních stránek dat. Při načítání stránky blízko konce ale vykazuje výchozí výkon podobný stránkování.
Tento kurz implementuje vlastní stránkování pomocí klíčového ROW_NUMBER()
slova . Další informace o použití tabulkové proměnné a SET ROWCOUNT
techniky najdete v tématu Efektivnější metoda stránkování prostřednictvím velkých sad výsledků.
Klíčové ROW_NUMBER()
slovo přidružuje pořadí ke každému záznamu vráceným pro konkrétní řazení pomocí následující syntaxe:
SELECT columnList,
ROW_NUMBER() OVER(orderByClause)
FROM TableName
ROW_NUMBER()
vrátí číselnou hodnotu, která určuje pořadí pro každý záznam s ohledem na uvedené pořadí. Abychom například viděli pořadí jednotlivých produktů seřazených od nejdražšího po nejnižší, mohli bychom použít následující dotaz:
SELECT ProductName, UnitPrice,
ROW_NUMBER() OVER(ORDER BY UnitPrice DESC) AS PriceRank
FROM Products
Obrázek 5 ukazuje výsledky tohoto dotazu při spuštění okna dotazu v sadě Visual Studio. Všimněte si, že produkty jsou seřazené podle ceny spolu s pořadím cen pro každý řádek.
Obrázek 5: Pořadí cen je zahrnuto pro každý vrácený záznam
Poznámka
ROW_NUMBER()
je jen jednou z mnoha nových funkcí řazení, které jsou k dispozici v SQL Server 2005. Podrobnější diskuzi o nástroji a dalších funkcích ROW_NUMBER()
řazení najdete v dokumentaci ROW_NUMBER.
Při řazení výsledků podle zadaného ORDER BY
sloupce v klauzuli OVER
(UnitPrice
ve výše uvedeném příkladu) musí SQL Server výsledky seřadit. Jedná se o rychlou operaci, pokud existuje skupinový index nad sloupci nebo sloupci, podle kterého jsou výsledky seřazeny, nebo pokud existuje krycí index, ale jinak může být nákladnější. Pokud chcete zlepšit výkon u dostatečně velkých dotazů, zvažte přidání nes clusterovaného indexu pro sloupec, podle kterého jsou výsledky seřazené podle. Podrobnější informace o výkonu najdete v tématu Řazení funkcí a výkonu v SQL Server 2005.
Informace o pořadí vrácené nástrojem ROW_NUMBER()
nelze přímo použít v klauzuli WHERE
. K vrácení výsledku ROW_NUMBER()
však lze použít odvozenou tabulku, která se pak může zobrazit v klauzuli WHERE
. Následující dotaz například používá odvozenou tabulku k vrácení sloupců ProductName a UnitPrice spolu s ROW_NUMBER()
výsledkem a pak použije WHERE
klauzuli, která vrátí pouze produkty, jejichž pořadí cen je mezi 11 a 20:
SELECT PriceRank, ProductName, UnitPrice
FROM
(SELECT ProductName, UnitPrice,
ROW_NUMBER() OVER(ORDER BY UnitPrice DESC) AS PriceRank
FROM Products
) AS ProductsWithRowNumber
WHERE PriceRank BETWEEN 11 AND 20
Když tento koncept ještě trochu rozšíříme, můžeme tento přístup využít k načtení konkrétní stránky dat s požadovanými hodnotami Index počátečního řádku a Maximální počet řádků:
SELECT PriceRank, ProductName, UnitPrice
FROM
(SELECT ProductName, UnitPrice,
ROW_NUMBER() OVER(ORDER BY UnitPrice DESC) AS PriceRank
FROM Products
) AS ProductsWithRowNumber
WHERE PriceRank > <i>StartRowIndex</i> AND
PriceRank <= (<i>StartRowIndex</i> + <i>MaximumRows</i>)
Poznámka
Jak uvidíme později v tomto kurzu, StartRowIndex
hodnota zadaná objektem ObjectDataSource je indexována od nuly, zatímco ROW_NUMBER()
hodnota vrácená SQL Server 2005 je indexována od 1. Proto klauzule WHERE
vrátí záznamy, u kterých PriceRank
je přísně větší než StartRowIndex
a menší než nebo rovno + StartRowIndex
MaximumRows
.
Teď, když jsme probrali, jak ROW_NUMBER()
se dá použít k načtení konkrétní stránky dat vzhledem k hodnotám Spustit index řádků a Maximální počet řádků, teď musíme tuto logiku implementovat jako metody v DAL a BLL.
Při vytváření tohoto dotazu musíme rozhodnout o pořadí, podle kterého budou výsledky seřazeny. nechte produkty seřadit podle jejich názvu v abecedním pořadí. To znamená, že s implementací vlastního stránkování v tomto kurzu nebudeme moct vytvořit vlastní stránkovanou sestavu, kterou lze také seřadit. V dalším kurzu se ale podíváme, jak se takové funkce dají poskytovat.
V předchozí části jsme vytvořili metodu DAL jako ad hoc příkaz SQL. Analyzátor T-SQL v sadě Visual Studio, který používá průvodce TableAdapter, se bohužel nelíbí OVER
syntaxi používané ROW_NUMBER()
funkcí. Proto musíme tuto metodu DAL vytvořit jako uloženou proceduru. V nabídce Zobrazení vyberte Průzkumníka serveru (nebo stiskněte Ctrl+Alt+S) a rozbalte NORTHWND.MDF
uzel. Pokud chcete přidat novou uloženou proceduru, klikněte pravým tlačítkem na uzel Uložené procedury a zvolte Přidat novou uloženou proceduru (viz Obrázek 6).
Obrázek 6: Přidání nové uložené procedury pro stránkování prostřednictvím produktů
Tato uložená procedura by měla přijímat dva celočíselné vstupní parametry – a používat funkci seřazenou podle ProductName
pole, která vrací pouze řádky větší než zadané @startRowIndex
a menší než nebo rovno + @maximumRow
@startRowIndex
s.ROW_NUMBER()
@maximumRows
@startRowIndex
Do nové uložené procedury zadejte následující skript a kliknutím na ikonu Uložit přidejte uloženou proceduru do databáze.
CREATE PROCEDURE dbo.GetProductsPaged
(
@startRowIndex int,
@maximumRows int
)
AS
SELECT ProductID, ProductName, SupplierID, CategoryID, QuantityPerUnit,
UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued,
CategoryName, SupplierName
FROM
(
SELECT ProductID, ProductName, SupplierID, CategoryID, QuantityPerUnit,
UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued,
(SELECT CategoryName
FROM Categories
WHERE Categories.CategoryID = Products.CategoryID) AS CategoryName,
(SELECT CompanyName
FROM Suppliers
WHERE Suppliers.SupplierID = Products.SupplierID) AS SupplierName,
ROW_NUMBER() OVER (ORDER BY ProductName) AS RowRank
FROM Products
) AS ProductsWithRowNumbers
WHERE RowRank > @startRowIndex AND RowRank <= (@startRowIndex + @maximumRows)
Po vytvoření uložené procedury si ji chvíli otestujte. V Průzkumníku GetProductsPaged
serveru klikněte pravým tlačítkem na název uložené procedury a zvolte možnost Execute (Spustit). Visual Studio vás pak vyzve k zadání vstupních parametrů @startRowIndex
a ( @maximumRow
viz Obrázek 7). Zkuste různé hodnoty a prozkoumejte výsledky.
@startRowIndex and @maximumRows Parameters" />
Obrázek 7: Zadejte hodnotu parametrů @startRowIndex a @maximumRows
Po výběru těchto hodnot vstupních parametrů se v okně Výstup zobrazí výsledky. Obrázek 8 ukazuje výsledky při předání hodnoty 10 parametrů a @startRowIndex
@maximumRows
.
Obrázek 8: Vrátí se záznamy, které se zobrazí na druhé stránce dat (kliknutím zobrazíte obrázek v plné velikosti).
Po vytvoření této uložené procedury jsme připraveni vytvořit metodu ProductsTableAdapter
. Northwind.xsd
Otevřete sadu Typed DataSet, klikněte pravým tlačítkem na ProductsTableAdapter
a zvolte možnost Přidat dotaz. Místo vytvoření dotazu pomocí ad hoc příkazu SQL ho vytvořte pomocí existující uložené procedury.
Obrázek 9: Vytvoření metody DAL pomocí existující uložené procedury
Dále se zobrazí výzva k výběru uložené procedury, která se má vyvolat. V rozevíracím seznamu vyberte uloženou GetProductsPaged
proceduru.
Obrázek 10: Výběr uložené procedury GetProductsPaged ze seznamu Drop-Down
Na další obrazovce se zobrazí dotaz, jaký druh dat uložená procedura vrací: tabulková data, jedna hodnota nebo žádná hodnota. Vzhledem k tomu, že uložená procedura GetProductsPaged
může vrátit více záznamů, uveďte, že vrací tabulková data.
Obrázek 11: Označení, že uložená procedura vrací tabulková data
Nakonec uveďte názvy metod, které chcete vytvořit. Stejně jako v předchozích kurzech, pokračujte vytvořením metod pomocí vyplnění tabulky DataTable a Vrácení dataTable. Pojmenujte první metodu FillPaged
a druhou GetProductsPaged
metodu .
Obrázek 12: Pojmenujte metody FillPaged a GetProductsPaged.
Kromě vytvoření metody DAL, která vrací konkrétní stránku produktů, musíme také poskytnout tyto funkce v BLL. Stejně jako metoda DAL musí metoda GetProductsPaged BLL přijímat dva celočíselné vstupy pro určení indexu počátečního řádku a maximálního počtu řádků a musí vracet pouze ty záznamy, které spadají do zadaného rozsahu. Vytvořte takovou metodu BLL ve třídě ProductsBLL, která pouze volá metodu DAL s GetProductsPaged, například takto:
<System.ComponentModel.DataObjectMethodAttribute( _
System.ComponentModel.DataObjectMethodType.Select, False)> _
Public Function GetProductsPaged(startRowIndex As Integer, maximumRows As Integer) _
As Northwind.ProductsDataTable
Return Adapter.GetProductsPaged(startRowIndex, maximumRows)
End Function
Můžete použít libovolný název vstupních parametrů metody BLL, ale jak uvidíme za chvíli, volba použít startRowIndex
a maximumRows
ušetřit nám další část práce při konfiguraci ObjectDataSource pro použití této metody.
Krok 4: Konfigurace objektu ObjectDataSource pro použití vlastního stránkování
Po dokončení metod BLL a DAL pro přístup k určité podmnožině záznamů jsme připraveni vytvořit ovládací prvek GridView, který bude stránkovat jeho podkladové záznamy pomocí vlastního stránkování. Začněte tím, že EfficientPaging.aspx
otevřete stránku ve PagingAndSorting
složce, přidáte na stránku GridView a nakonfigurujete ji tak, aby používala nový ovládací prvek ObjectDataSource. V našich předchozích kurzech jsme často měli ObjectDataSource nakonfigurovaný tak, aby používal metodu ProductsBLL
třídy s GetProducts
. Tentokrát ale chceme místo toho použít metodu GetProductsPaged
, protože GetProducts
metoda vrací všechny produkty v databázi, zatímco GetProductsPaged
vrací jenom určitou podmnožinu záznamů.
Obrázek 13: Konfigurace objektu ObjectDataSource pro použití metody GetProductsPaged třídy ProductsBLL
Vzhledem k tomu, že vytváříme GridView jen pro čtení, chvíli trvá, než nastavíte rozevírací seznam metody na kartách INSERT, UPDATE a DELETE na (Žádné).
Dále nás průvodce ObjectDataSource vyzve k zadání zdrojů GetProductsPaged
hodnot metod s startRowIndex
a maximumRows
vstupních parametrů. Tyto vstupní parametry budou ve skutečnosti nastaveny gridView automaticky, takže jednoduše nechejte zdroj nastavený na Žádný a klikněte na Dokončit.
Obrázek 14: Nechejte zdroje vstupních parametrů jako Žádné
Po dokončení průvodce ObjectDataSource bude GridView obsahovat BoundField nebo CheckBoxField pro každé z datových polí produktu. Nebojte se přizpůsobit vzhled GridView podle potřeby. Rozhodl(a) jsem se zobrazit pouze ProductName
pole , CategoryName
, SupplierName
, QuantityPerUnit
a UnitPrice
BoundFields. Také nakonfigurujte GridView tak, aby podporoval stránkování zaškrtnutím políčka Povolit stránkování v inteligentní značce. Po těchto změnách by deklarativní značky GridView a ObjectDataSource měly vypadat podobně jako následující:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ObjectDataSource1" AllowPaging="True">
<Columns>
<asp:BoundField DataField="ProductName" HeaderText="Product"
SortExpression="ProductName" />
<asp:BoundField DataField="CategoryName" HeaderText="Category"
ReadOnly="True" SortExpression="CategoryName" />
<asp:BoundField DataField="SupplierName" HeaderText="Supplier"
SortExpression="SupplierName" />
<asp:BoundField DataField="QuantityPerUnit" HeaderText="Qty/Unit"
SortExpression="QuantityPerUnit" />
<asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}"
HeaderText="Price" HtmlEncode="False" SortExpression="UnitPrice" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
OldValuesParameterFormatString="original_{0}" SelectMethod="GetProductsPaged"
TypeName="ProductsBLL">
<SelectParameters>
<asp:Parameter Name="startRowIndex" Type="Int32" />
<asp:Parameter Name="maximumRows" Type="Int32" />
</SelectParameters>
</asp:ObjectDataSource>
Pokud ale stránku navštívíte prostřednictvím prohlížeče, GridView není místo, kde se má najít.
Obrázek 15: Zobrazení mřížky se nezobrazuje
Objekt GridView chybí, protože ObjectDataSource aktuálně používá hodnotu 0 jako hodnoty vstupních GetProductsPaged
startRowIndex
parametrů a maximumRows
. Proto výsledný dotaz SQL nevrací žádné záznamy, a proto gridView se nezobrazí.
Abychom tento problém napravili, musíme nakonfigurovat ObjectDataSource tak, aby používal vlastní stránkování. To lze provést v následujících krocích:
- Nastavte vlastnost ObjectDataSource s
EnablePaging
natrue
hodnotu, která značí objektu ObjectDataSource, že musí předatSelectMethod
dva další parametry: jeden pro určení indexu počátečního řádku (StartRowIndexParameterName
) a druhý pro určení maximálního počtu řádků (MaximumRowsParameterName
). - Nastavte ObjectDataSource s
StartRowIndexParameterName
aMaximumRowsParameterName
Properties Podle tohoStartRowIndexParameterName
vlastnosti aMaximumRowsParameterName
označují názvy vstupních parametrů předaných do objektuSelectMethod
pro účely vlastního stránkování. Ve výchozím nastavení jsoustartIndexRow
tyto názvy parametrů amaximumRows
, což je důvod, proč jsem při vytvářeníGetProductsPaged
metody v BLL použil tyto hodnoty pro vstupní parametry. Pokud jste se rozhodli použít jiné názvy parametrů pro metodu BLL sGetProductsPaged
, napříkladstartIndex
amaxRows
, museli byste odpovídajícím způsobem nastavit vlastnosti ObjectDataSource sStartRowIndexParameterName
aMaximumRowsParameterName
(například startIndex proStartRowIndexParameterName
a maxRows proMaximumRowsParameterName
). - Nastavte Vlastnost ObjectDataSource s
SelectCountMethod
na Název metody, která vrací celkový počet záznamů, které jsou stránkovány (TotalNumberOfProducts
), vzpomeňte si, žeProductsBLL
metoda třídy sTotalNumberOfProducts
vrací celkový počet záznamů stránkovaných pomocí metody DAL, která provádíSELECT COUNT(*) FROM Products
dotaz. Tyto informace potřebuje ObjectDataSource, aby bylo možné správně vykreslit stránkovací rozhraní. startRowIndex
Odeberte elementy amaximumRows
<asp:Parameter>
z deklarativních značek ObjectDataSource při konfiguraci ObjectDataSource prostřednictvím průvodce, Visual Studio automaticky přidal dva<asp:Parameter>
prvky proGetProductsPaged
vstupní parametry metody s.EnablePaging
Nastavením natrue
, budou tyto parametry předány automaticky; pokud se zobrazí také v deklarativní syntaxi, ObjectDataSource se pokusí předat čtyři parametryGetProductsPaged
metodě a dva parametry doTotalNumberOfProducts
metody. Pokud zapomenete tyto<asp:Parameter>
prvky odebrat, při návštěvě stránky v prohlížeči se zobrazí chybová zpráva typu ObjectDataSource ObjectDataSource1 nemohl najít negenerovou metodu TotalNumberOfProducts s parametry: startRowIndex, maximumRows.
Po provedení těchto změn by deklarativní syntaxe ObjectDataSource měla vypadat takto:
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
OldValuesParameterFormatString="original_{0}" SelectMethod="GetProductsPaged"
TypeName="ProductsBLL" EnablePaging="True" SelectCountMethod="
TotalNumberOfProducts">
</asp:ObjectDataSource>
Všimněte si EnablePaging
, že vlastnosti a SelectCountMethod
byly nastaveny a <asp:Parameter>
prvky byly odebrány. Obrázek 16 ukazuje snímek obrazovky okno Vlastnosti po provedení těchto změn.
Obrázek 16: Pokud chcete použít vlastní stránkování, nakonfigurujte ovládací prvek ObjectDataSource.
Po provedení těchto změn přejděte na tuto stránku prostřednictvím prohlížeče. Měli byste vidět 10 produktů seřazených abecedně. Chvíli si prohlédněte data po jednotlivých stránkách. I když z pohledu koncového uživatele není žádný vizuální rozdíl mezi výchozím stránkováním a vlastním stránkováním, vlastní stránkování efektivněji stránkuje velké objemy dat, protože načítá pouze ty záznamy, které je potřeba zobrazit pro danou stránku.
Obrázek 17: Data seřazená podle názvu produktu jsou stránkována pomocí vlastního stránkování (kliknutím zobrazíte obrázek v plné velikosti).
Poznámka
Při vlastním stránkování je hodnota počtu stránek vrácená ObjectDataSource SelectCountMethod
uložena ve stavu zobrazení GridView. Jiné proměnné PageIndex
GridView , , EditIndex
SelectedIndex
, DataKeys
kolekce a tak dále jsou uloženy ve stavu ovládacího prvku, který je trvalý bez ohledu na hodnotu vlastnosti GridViewEnableViewState
. Vzhledem k tomu, že PageCount
hodnota je zachována napříč postbacky pomocí stavu zobrazení, při použití stránkovací rozhraní, které obsahuje odkaz, který vás přesměruje na poslední stránku, je nutné, aby stav zobrazení GridView byl povolen. (Pokud vaše stránkovací rozhraní neobsahuje přímý odkaz na poslední stránku, můžete stav zobrazení zakázat.)
Kliknutí na odkaz poslední stránky způsobí zpětné odeslání a dá GridView pokyn k aktualizaci jeho PageIndex
vlastnosti. Pokud kliknete na odkaz poslední stránky, Objekt GridView přiřadí jeho PageIndex
vlastnost k hodnotě o jednu menší, než je jeho PageCount
vlastnost. Když je stav zobrazení zakázaný, PageCount
hodnota se v rámci zpětného odeslání ztratí a PageIndex
místo toho se přiřadí maximální celočíselná hodnota. Dále se Objekt GridView pokusí určit index počátečního řádku vynásobením PageSize
vlastností a PageCount
. Výsledkem je, OverflowException
že produkt překračuje maximální povolenou celočíselnou velikost.
Implementace vlastního stránkování a řazení
Naše aktuální vlastní implementace stránkování vyžaduje, aby pořadí, podle kterého jsou data stránkována, bylo při vytváření GetProductsPaged
uložené procedury zadáno staticky. Možná jste si však všimli, že inteligentní značka GridView obsahuje kromě možnosti Povolit stránkování také zaškrtávací políčko Povolit řazení. Přidání podpory řazení do objektu GridView s naší aktuální vlastní implementací stránkování bohužel seřadí pouze záznamy na aktuálně zobrazené stránce dat. Pokud například gridView nakonfigurujete tak, aby podporoval také stránkování, a pak při zobrazení první stránky dat seřadíte podle názvu produktu v sestupném pořadí, změní se pořadí produktů na stránce 1. Jak ukazuje obrázek 18, takové ukazuje Carnarvon Tigers jako první produkt při řazení v obráceném abecedním pořadí, což ignoruje 71 dalších produktů, které přicházejí po Carnarvon Tigers, abecedně; Při řazení jsou brány v úvahu pouze ty záznamy na první stránce.
Obrázek 18: Seřadí se pouze data zobrazená na aktuální stránce (kliknutím zobrazíte obrázek v plné velikosti).
Řazení se vztahuje pouze na aktuální stránku dat, protože k řazení dochází po načtení dat z metody BLL s GetProductsPaged
a tato metoda vrací pouze tyto záznamy pro konkrétní stránku. Aby bylo možné správně implementovat řazení, musíme předat výraz sort metodě GetProductsPaged
, aby data bylo možné před vrácením konkrétní stránky dat správně seřadit. V dalším kurzu se dozvíme, jak toho dosáhnout.
Implementace vlastního stránkování a odstranění
Pokud povolíte funkci odstranění v objektu GridView, jehož data jsou stránkována pomocí vlastních technik stránkování, zjistíte, že při odstranění posledního záznamu z poslední stránky GridView zmizí místo toho, aby odpovídajícím způsobem zmenšoval GridView s PageIndex
. Pokud chcete tuto chybu reprodukovat, povolte odstranění právě vytvořeného kurzu. Přejděte na poslední stránku (strana 9), kde byste měli vidět jeden produkt, protože jsme se stránkovat přes 81 produktů, 10 produktů najednou. Odstraňte tento produkt.
Po odstranění posledního produktu by gridView měl automaticky přejít na osmou stránku a tato funkce se zobrazí s výchozím stránkováním. S vlastním stránkováním však po odstranění posledního produktu na poslední stránce GridView jednoduše zmizí z obrazovky úplně. Přesný důvod , proč k tomu dochází, je trochu nad rámec tohoto kurzu; Podrobnosti o zdroji tohoto problému najdete v části Odstranění posledního záznamu na poslední stránce z objektu GridView s vlastním stránkováním . V souhrnu je příčinou následující posloupnost kroků, které jsou provedeny GridView při kliknutí na tlačítko Odstranit:
- Odstranění záznamu
- Získání odpovídajících záznamů, které se mají zobrazit pro zadané
PageIndex
aPageSize
- Zkontrolujte, jestli
PageIndex
hodnota nepřekračuje počet stránek dat ve zdroji dat. Pokud ano, automaticky se sníží vlastnost GridView sPageIndex
. - Vytvoření vazby příslušné stránky dat k objektu GridView pomocí záznamů získaných v kroku 2
Problém pramení ze skutečnosti, že v kroku 2 PageIndex
se při načítání zobrazených záznamů stále PageIndex
používá poslední stránka, jejíž jediný záznam byl právě odstraněn. Proto se v kroku 2 nevrátí žádné záznamy, protože poslední stránka dat už neobsahuje žádné záznamy. Potom v kroku 3 GridView zjistí, že jeho PageIndex
vlastnost je větší než celkový počet stránek ve zdroji dat (protože jsme odstranili poslední záznam na poslední stránce), a proto sníží jeho PageIndex
vlastnost. V kroku 4 GridView se pokusí vytvořit vazbu na data načtená v kroku 2; v kroku 2 však nebyly vráceny žádné záznamy, takže výsledkem je prázdný Objekt GridView. Při výchozím stránkování se tento problém neobjeví, protože v kroku 2 jsou všechny záznamy načteny ze zdroje dat.
K vyřešení tohoto problému máme dvě možnosti. Prvním je vytvoření obslužné rutiny události pro obslužnou rutinu události GridView, RowDeleted
která určuje, kolik záznamů bylo zobrazeno na stránce, která byla právě odstraněna. Pokud by existoval pouze jeden záznam, pak právě odstraněný záznam musel být poslední a musíme dekrementovat GridView s PageIndex
. Samozřejmě chceme aktualizovat PageIndex
pouze v případě, že operace odstranění byla skutečně úspěšná, což se dá určit zajištěním, že e.Exception
vlastnost je null
.
Tento přístup funguje, protože aktualizuje PageIndex
následující krok 1, ale před krokem 2. Proto se v kroku 2 vrátí příslušná sada záznamů. K tomu použijte následující kód:
Protected Sub GridView1_RowDeleted(sender As Object, e As GridViewDeletedEventArgs) _
Handles GridView1.RowDeleted
' If we just deleted the last row in the GridView, decrement the PageIndex
If e.Exception Is Nothing AndAlso GridView1.Rows.Count = 1 Then
' we just deleted the last row
GridView1.PageIndex = Math.Max(0, GridView1.PageIndex - 1)
End If
End Sub
Alternativním alternativním řešením je vytvořit obslužnou rutinu události objectDataSource a RowDeleted
nastavit AffectedRows
vlastnost na hodnotu 1. Po odstranění záznamu v kroku 1 (ale před opětovným načtením dat v kroku 2) GridView aktualizuje jeho PageIndex
vlastnost, pokud operace ovlivnila jeden nebo více řádků. AffectedRows
Vlastnost objectDataSource však není nastavena, a proto je tento krok vynechán. Jedním ze způsobů, jak tento krok provést, je nastavit vlastnost ručně AffectedRows
, pokud se operace odstranění úspěšně dokončí. To lze provést pomocí kódu, jako je následující:
Protected Sub ObjectDataSource1_Deleted( _
sender As Object, e As ObjectDataSourceStatusEventArgs) _
Handles ObjectDataSource1.Deleted
' If we get back a Boolean value from the DeleteProduct method and it's true, then
' we successfully deleted the product. Set AffectedRows to 1
If TypeOf e.ReturnValue Is Boolean AndAlso CType(e.ReturnValue, Boolean) = True Then
e.AffectedRows = 1
End If
End Sub
Kód pro obě tyto obslužné rutiny událostí najdete v příkladu EfficientPaging.aspx
ve třídě kódu na pozadí.
Porovnání výkonu výchozího a vlastního stránkování
Vzhledem k tomu, že vlastní stránkování načítá pouze potřebné záznamy, zatímco výchozí stránkování vrací všechny záznamy pro každou zobrazenou stránku, je jasné, že vlastní stránkování je efektivnější než výchozí stránkování. O kolik efektivnější je ale vlastní stránkování? Jaký druh zvýšení výkonu lze dosáhnout přechodem z výchozího stránkování na vlastní stránkování?
Bohužel, neexistuje jedna velikost pro všechny odpovědi. Zvýšení výkonu závisí na několika faktorech. Mezi dva nejvýznamnější patří počet stránkovaných záznamů a zatížení databázového serveru a komunikační kanály mezi webovým serverem a databázovým serverem. U malých tabulek s několika desítkami záznamů může být rozdíl ve výkonu zanedbatelný. U velkých tabulek s tisíci a stovkami tisíc řádků je ale rozdíl ve výkonu akutní.
Můj článek "Vlastní stránkování v ASP.NET 2.0 s SQL Server 2005" obsahuje některé testy výkonnosti, které jsem provedl, abych ukázal rozdíly ve výkonu mezi těmito dvěma technikami stránkování při stránkování v databázové tabulce s 50 000 záznamy. V těchto testech jsem prozkoumal čas spuštění dotazu na úrovni SQL Server (pomocí SQL Profileru) a na stránce ASP.NET pomocí funkcí trasování ASP.NET s. Mějte na paměti, že tyto testy byly spuštěny na vývojovém poli s jedním aktivním uživatelem, a proto jsou nevědecké a nenapodobují typické vzorce zatížení webu. Bez ohledu na to výsledky ukazují relativní rozdíly v době provádění výchozího a vlastního stránkování při práci s dostatečně velkými objemy dat.
Prům. doba trvání (s) | Čte | |
---|---|---|
Výchozí stránkování SQL Profileru | 1.411 | 383 |
Vlastní stránkování SQL Profileru | 0.002 | 29 |
Výchozí trasování stránkování ASP.NET | 2.379 | – |
Trasování vlastního stránkování ASP.NET | 0.029 | – |
Jak vidíte, načtení konkrétní stránky dat vyžadovalo v průměru o 354 čtení méně a dokončení za zlomek času. Na ASP.NET stránce byla vlastní stránka schopna vykreslit téměř 1/100času , který trvalo při použití výchozího stránkování.
Souhrn
K implementaci výchozího stránkování stačí zaškrtnout políčko Povolit stránkování v inteligentní značce webového ovládacího prvku dat, ale taková jednoduchost je za cenu výkonu. Při výchozím stránkování platí, že když uživatel požádá o libovolnou stránku dat, vrátí se všechny záznamy, i když se může zobrazit jen malý zlomek z nich. Pro boj s touto režií na výkon nabízí ObjectDataSource alternativní možnost stránkování vlastní stránkování.
I když se vlastní stránkování zlepšuje při výchozích problémech s výkonem stránkování tím, že načítá pouze ty záznamy, které je potřeba zobrazit, je více zapojené implementovat vlastní stránkování. Nejprve je potřeba napsat dotaz, který správně (a efektivně) přistupuje ke konkrétní podmnožině požadovaných záznamů. Toho lze dosáhnout mnoha způsoby; V tomto kurzu jsme se zabývali použitím nové ROW_NUMBER()
funkce SQL Server 2005 k seřaďte výsledky a pak vrátíte jenom ty výsledky, jejichž pořadí spadá do zadaného rozsahu. Kromě toho musíme přidat prostředky k určení celkového počtu stránkovaných záznamů. Po vytvoření těchto metod DAL a BLL musíme také nakonfigurovat ObjectDataSource tak, aby mohl určit celkový počet záznamů, které jsou stránkovány, a správně předat počáteční index řádku a maximální počet řádků hodnoty BLL.
I když implementace vlastního stránkování vyžaduje několik kroků a není tak jednoduchá jako výchozí stránkování, vlastní stránkování je při stránkování dostatečně velkých objemů dat nezbytné. Jak ukázaly zkoumané výsledky, vlastní stránkování může z doby vykreslování ASP.NET stránky krátit sekundy a může odlehčovat zatížení databázového serveru o jeden nebo více řádů.
Všechno nejlepší na programování!
O autorovi
Scott Mitchell, autor sedmi knih o ASP/ASP.NET a zakladatel 4GuysFromRolla.com, pracuje s webovými technologiemi Microsoftu od roku 1998. Scott pracuje jako nezávislý konzultant, školitel a spisovatel. Jeho nejnovější kniha je Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Můžete ho zastihnout na mitchell@4GuysFromRolla.comadrese . nebo prostřednictvím jeho blogu, který najdete na adrese http://ScottOnWriting.NET.
Váš názor
https://aka.ms/ContentUserFeedback.
Připravujeme: V průběhu roku 2024 budeme postupně vyřazovat problémy z GitHub coby mechanismus zpětné vazby pro obsah a nahrazovat ho novým systémem zpětné vazby. Další informace naleznete v tématu:Odeslat a zobrazit názory pro