Professional Documents
Culture Documents
taGrid, 99,975 records would be discarded on each request (assuming a page size
of 25). As the number of records grows, the performance of the application will
suffer as more and more data must be sent on each request.
One good approach to writing better paging code is to use stored procedures. Fig
ure 2 shows a sample stored procedure that pages through the Orders table in the
Northwind database. In a nutshell, all you're doing here is passing in the page
index and the page size. The appropriate resultset is calculated and then retur
ned.
Figure 2 Paging Through the Orders Table
CREATE PROCEDURE northwind_OrdersPaged
(
@PageIndex int,
@PageSize int
)
AS
BEGIN
DECLARE @PageLowerBound int
DECLARE @PageUpperBound int
DECLARE @RowsToReturn int
-- First set the rowcount
SET @RowsToReturn = @PageSize * (@PageIndex + 1)
SET ROWCOUNT @RowsToReturn
-- Set the page bounds
SET @PageLowerBound = @PageSize * @PageIndex
SET @PageUpperBound = @PageLowerBound + @PageSize + 1
-- Create a temp table to store the select results
CREATE TABLE #PageIndex
(
IndexId int IDENTITY (1, 1) NOT NULL,
OrderID int
)
-- Insert into the temp table
INSERT INTO #PageIndex (OrderID)
SELECT
OrderID
FROM
Orders
ORDER BY
OrderID DESC
-- Return total count
SELECT COUNT(OrderID) FROM Orders
-- Return paged results
SELECT
O.*
FROM
Orders O,
#PageIndex PageIndex
WHERE
O.OrderID = PageIndex.OrderID AND
PageIndex.IndexID > @PageLowerBound AND
PageIndex.IndexID < @PageUpperBound
ORDER BY
PageIndex.IndexID
END
In Community Server, we wrote a paging server control to do all the data paging.
You'll see that I am using the ideas discussed in Tip 1, returning two resultse
ts from one stored procedure: the total number of records and the requested data
.
The total number of records returned can vary depending on the query being execu
ted. For example, a WHERE clause can be used to constrain the data returned. The
total number of records to be returned must be known in order to calculate the
total pages to be displayed in the paging UI. For example, if there are 1,000,00
0 total records and a WHERE clause is used that filters this to 1,000 records, t
he paging logic needs to be aware of the total number of records to properly ren
der the paging UI.
Tip 3 Connection Pooling
Setting up the TCP connection between your Web application and SQL Server can be
an expensive operation. Developers at Microsoft have been able to take advantage
of connection pooling for some time now, allowing them to reuse connections to
the database. Rather than setting up a new TCP connection on each request, a new
connection is set up only when one is not available in the connection pool. Whe
n the connection is closed, it is returned to the pool where it remains connecte
d to the database, as opposed to completely tearing down that TCP connection.
Of course you need to watch out for leaking connections. Always close your conne
ctions when you're finished with them. I repeat: no matter what anyone says abou
t garbage collection within the Microsoft .NET Framework, always call Close or Di
spose explicitly on your connection when you are finished with it. Do not trust
the common language runtime (CLR) to clean up and close your connection for you
at a predetermined time. The CLR will eventually destroy the class and force the
connection closed, but you have no guarantee when the garbage collection on the
object will actually happen.
To use connection pooling optimally, there are a couple of rules to live by. Fir
st, open the connection, do the work, and then close the connection. It's okay t
o open and close the connection multiple times on each request if you have to (o
ptimally you apply Tip 1) rather than keeping the connection open and passing it
around through different methods. Second, use the same connection string (and t
he same thread identity if you're using integrated authentication). If you don't
use the same connection string, for example customizing the connection string b
ased on the logged-in user, you won't get the same optimization value provided b
y connection pooling. And if you use integrated authentication while impersonati
ng a large set of users, your pooling will also be much less effective. The .NET
CLR data performance counters can be very useful when attempting to track down
any performance issues that are related to connection pooling.
Whenever your application is connecting to a resource, such as a database, runni
ng in another process, you should optimize by focusing on the time spent connect
ing to the resource, the time spent sending or retrieving data, and the number o
f round-trips. Optimizing any kind of process hop in your application is the fir
st place to start to achieve better performance.
The application tier contains the logic that connects to your data layer and tra
nsforms data into meaningful class instances and business processes. For example
, in Community Server, this is where you populate a Forums or Threads collection
, and apply business rules such as permissions; most importantly it is where the
Caching logic is performed.
Tip 4 ASP.NET Cache API
One of the very first things you should do before writing a line of application
code is architect the application tier to maximize and exploit the ASP.NET Cache
feature.
If your components are running within an ASP.NET application, you simply need to
include a reference to System.Web.dll in your application project. When you nee
d access to the Cache, use the HttpRuntime.Cache property (the same object is al
so accessible through Page.Cache and HttpContext.Cache).
There are several rules for caching data. First, if data can be used more than o
nce it's a good candidate for caching. Second, if data is general rather than sp
ecific to a given request or user, it's a great candidate for the cache. If the
data is user- or request-specific, but is long lived, it can still be cached, bu
t may not be used as frequently. Third, an often overlooked rule is that sometim
es you can cache too much. Generally on an x86 machine,