Thursday, December 6, 2007

optimize table printing in asp

Optimized Table Printing in ASP

Microsoft's ASP technology enables beginners to write dynamic web pages with little effort. The ADO object model hides the complexity of obtaining data from the database. However, hiding complexity under a simple interface also allows unsuspecting programmers to write wildly inefficient code. Consider the common task of querying the database and displaying the results in an HTML table.

Outline

  • Concatenating Database Output Into a String
  • Eliminating Concatenation From the Loop
  • Better Performance with Recordset Field References
  • Improving Browser Rendering Speed Using Fixed Size Tables
  • Using Minimal Formatting with the PRE tag
  • Using the GetString Recordset Function
  • Using the GetRows Recordset Function
  • Using a Native OLE DB Provider Instead of ODBC
  • Summary of Simple Table Techniques

Concatenating Database Output Into a String

One of the slowest methods is to loop through the recordset, and concatenate each row into a string. Once the loop is complete, the string is written to the response. Many novices may apply this technique due to its logical simplicity, or by following the bad example of others. However, for anything but very small data sets, this technique is highly innefficient. The next code example shows how this technique might be used. The table being printed contains two integer columns and two short text columns, and is described fully in ASP Speed Tricks Appendix.

simpletable1.asp
<%@ Language=VBScript %>

<% Option Explicit %>
<% Dim StartTime, EndTime StartTime = Timer Dim objCN ' ADO Connection object
Dim objRS ' ADO Recordset object
Dim strsql ' SQL query string
Dim strTemp ' a temporary string

' Create a connection object
Set objCN = Server.CreateObject("ADODB.Connection")

' Connect to the data source
objCN.ConnectionString = "DSN=datasource"
objCN.Open

' Prepare a SQL query string
strsql = "SELECT * FROM tblData"

' Execute the SQL query and set the implicitly created recordset
Set objRS = objCN.Execute(strsql)

' Write out the results in a table by concatenating into a string
Response.write ""

Do While Not objRS.EOF
strTemp = strTemp & ""
strTemp = strTemp & ""
strTemp = strTemp & ""
strTemp = strTemp & ""
objRS.MoveNext
Loop
Response.write strTemp
Response.write "
" & objRS("field1") & "" & objRS("field2") & "" & objRS("field3") & "" & objRS("field4") & "
"

Set objCN = Nothing
Set objRS = Nothing

EndTime = Timer
Response.write "

processing took "&(EndTime-StartTime)&" seconds

"
%>

Test Results
RecordsTime
10003.5 seconds
200018.4 seconds
100007.5 minutes (est.)
2000030 minutes (est.)

The server processing time to display 1000 records from the table is about 3.5 seconds. Doubling the number of records to 2000 more than quadruples the time to 18.4 seconds. The script times out for the other tests, but some time estimates are given. In the code, the '&' concatenation operator is used heavily within the loop.

Concatenation in VBScript requires new memory to be allocated and the entire string to be copied. If the concatenation is accumulating in a single string, then an increasingly long string must be copied on each iteration. This is why the time increases as the square of the number of records. Therefore, the first optimization technique is to avoid accumulating the database results into a string.

Eliminating Concatenation From the Loop

Concatenation may be removed easily by using Response.write directly in the loop. (In ASP.Net, the StringBuilder class can be used for creating long strings, but Response.write is fastest.) By eliminating accumulation, the processing time becomes proportional to the number of records being printed, rather than being exponential.

Each use of the concatenation operator results in unnecessary memory copying. With larger recordsets or high-load servers, this time can become significant. Therefore, instead of concatenating, programmers should simply write out the data with liberal use of Response.write. The code snippet below shows that even a few non-accumulative concatenations cause a noticeable time difference when run repeatedly.

' Using concatenation in a loop takes 1.93 seconds.

For i = 0 To 500000
Response.write vbTab & "foo" & vbCrLf
Next
' Using multiple Response.write calls takes 1.62 seconds.

For i = 0 To 500000
Response.write vbTab
Response.write "foo"
Response.write vbCrLf
Next

The following example eliminates accumulative concatenation from the loop and replaces it with direct calls to Response.write.

simpletable2.asp
<%@ Language=VBScript %>

<% Option Explicit %>
<% Dim StartTime, EndTime StartTime = Timer Dim objCN ' ADO Connection object
Dim objRS ' ADO Recordset object
Dim strsql ' SQL query string

' Create a connection object
Set objCN = Server.CreateObject("ADODB.Connection")

' Connect to the data source
objCN.ConnectionString = "DSN=datasource"
objCN.Open

' Prepare a SQL query string
strsql = "SELECT * FROM tblData"

' Execute the SQL query and set the implicitly created recordset
Set objRS = objCN.Execute(strsql)

' Write out the results directly without using concatenation operator
Response.write ""
Do While Not objRS.EOF
Response.write ""
objRS.MoveNext
Loop
Response.write "
"
Response.write objRS("field1")
Response.write "
"
Response.write objRS("field2")
Response.write "
"
Response.write objRS("field3")
Response.write "
"
Response.write objRS("field4")
Response.write "
"

objRS.Close
objCN.Close
Set objCN = Nothing
Set objRS = Nothing

EndTime = Timer
Response.write "

processing took "&(EndTime-StartTime)&" seconds

"
%>

Test Results
RecordsSeconds
10000.145
20000.260
100000.980
200001.950

For 1000 records, this method runs an incredible 23 times faster. For more records, the difference is even greater. The processing time is now roughly proportional to the number of records being printed. This property is essential for large record sets.

Better Performance with Recordset Field References

In the previous examples, the value of the field was retrieved from the Recordset object by specifying the field name directly. The Recordset's Fields collection supports this useful property to provide easy access to the fields. However, referencing the field value by using the textual field name causes a relatively slow string lookup to be performed in the Fields collection.

To avoid the string lookup, we could instead use a numeric index into the Fields collection, such as objRS(0), objRS(1), objRS(2), etc. But even better performance can be gained by saving a pointer to each field in the Recordset right after it is opened. This way, instead of looking up the field value using a string or number, direct access to the field value is obtained. When VBScript sees the pointer in the string context of the Response.write, it can quickly obtain the data from the field and convert it to a string. The next example shows how this can be done.

simpletable3.asp
<%@ Language=VBScript %>

<% Option Explicit %>
<% Dim StartTime, EndTime StartTime = Timer Dim objCN ' ADO Connection object
Dim objRS ' ADO Recordset object
Dim strsql ' SQL query string
Dim objField1, objField2, objField3, objField4

' Create a connection object
Set objCN = Server.CreateObject("ADODB.Connection")

' Connect to the data source
objCN.ConnectionString = "DSN=datasource"
objCN.Open

' Prepare a SQL query string
strsql = "SELECT Field1,Field2,Field3,Field4 FROM tblData"

' Execute the SQL query and set the implicitly created recordset
Set objRS = objCN.Execute(strsql)

' Set up field references after opening recordset
Set objField1 = objRS("Field1")
Set objField2 = objRS("Field2")
Set objField3 = objRS("Field3")
Set objField4 = objRS("Field4")

' Write out the results using the field references
Response.write ""
Do While Not objRS.EOF
Response.write ""
objRS.MoveNext
Loop
Response.write "
"
Response.write objField1
Response.write "
"
Response.write objField2
Response.write "
"
Response.write objField3
Response.write "
"
Response.write objField4
Response.write "
"

objRS.Close
objCN.Close
Set objCN = Nothing
Set objRS = Nothing

EndTime = Timer
Response.write "

processing took "&(EndTime-StartTime)&" seconds

"
%>

Test Results
RecordsSeconds
10000.105
20000.190
100000.665
200001.350

This technique requires declaring each field as a variable, and then setting the pointers after the Recordset is opened. The need for these additional lines of code is a drawback to this technique. The benefit is a 30-40% speedup on this test. Note that the references are set using the actual names of the fields, and the references are named with "obj" prefixed to the field name. This convention is to improve maintainability and readibility.

Improving Browser Rendering Speed Using Fixed Size Tables

While running the above example on Internet Explorer for 20,000 records, one may notice that the server finishes processing within two seconds, but the page does not display until much later. On the test system, the page displayed 12 seconds after the refresh button was pressed. For those 12 seconds, the browser window remained blank.

This delay is not due to the server, but it is due to the browser rendering speed on the client machine. When a web browser receives this huge data set, it must figure out a way to display it on the user's screen. This means calculating the width of the table columns and height of its rows. In fact, the browser has to receive and process all the data before it can finalize the layout of the table. On low bandwidth connections, the problem is compounded because the user must additionally wait for the data to be transferred.

Every browser takes a different amount of time to render a given page, but there are techniques that can be used to help the browser along. The goal is to give the browser as few calculations as possible. One minor technique is to print a new line (vbCrLf) after every 256 characters or so. This seems to help older browsers in particular.

The major technique is to make the table's columns fixed width, thereby eliminating the need for the browser to calculate the table's column widths. In fact, by making the table fixed width, the browser can begin displaying the table before all the data has been received. First, set the table style to "table-layout: fixed;". Second, right after the

tag, add a tag and define the column widths for each column with tags. The next example shows this method.
simpletable4.asp

<%@ Language=VBScript %>

<% Option Explicit %>
<% Dim StartTime, EndTime StartTime = Timer Dim objCN ' ADO Connection object
Dim objRS ' ADO Recordset object
Dim strsql ' SQL query string
Dim objField1, objField2, objField3, objField4

' Create a connection object
Set objCN = Server.CreateObject("ADODB.Connection")

' Connect to the data source
objCN.ConnectionString = "DSN=datasource"
objCN.Open

' Prepare a SQL query string
strsql = "SELECT Field1,Field2,Field3,Field4 FROM tblData"

' Execute the SQL query and set the implicitly created recordset
Set objRS = objCN.Execute(strsql)

' Set up field references after opening recordset
Set objField1 = objRS("Field1")
Set objField2 = objRS("Field2")
Set objField3 = objRS("Field3")
Set objField4 = objRS("Field4")

' Write out the results in a fixed size table
Response.write ""
Response.write ""
Response.write ""
Response.write ""
Do While Not objRS.EOF
Response.write ""
Response.write vbCrLf
objRS.MoveNext
Loop
Response.write "
"
Response.write objField1
Response.write "
"
Response.write objField2
Response.write "
"
Response.write objField3
Response.write "
"
Response.write objField4
Response.write "
"

objRS.Close
objCN.Close
Set objCN = Nothing
Set objRS = Nothing

EndTime = Timer
Response.write "

processing took "&(EndTime-StartTime)&" seconds

"
%>

When this version of the code is refreshed, the top part of the table displays in about 3 seconds. The page is not scrollable, and the browser is still receiving and rendering the remaining data, but at least the user can begin reading the first part of table. The page completes loading in the same amount of time as before, about 12 seconds. While the actual speed is not faster, the perceived speed is significantly faster.

Note that different browsers render tables in different ways. For example, Mozilla actually renders the top part of the table before receiving the entire table, even if the table is not fixed in size. The Mozilla Layout Engine, on which Netscape 6+ is based, then resizes the columns again on the fly once all the data has been received. Rendering time is highly dependent upon browser choice, processor speed, memory speed and amount, and graphics card speed, which are aspects of the client's system. A web page programmer generally has no direct control over the client's system, but can generate HTML which requires less power to render.

Using Minimal Formatting with the PRE tag

Rendering time can be drastically improved by eliminating the table and using pre-formatted text. Along the same lines as before, the trade-off is some loss in formatting flexibility for a gain in raw speed. The

 tag can be used for text that displays in a fixed-width font using the formatting of the source code, like all the code examples in this document. Because there is no text wrapping, column sizing, or variable character sizes, the browser has minimal amounts of calculations to make for rendering. 

To implement this, simply replace the table tags with the pre-formatted text tag, and then replace the table cell bounding tags with tabs and new lines. An additional benefit of this technique is that the raw amount of data is less because tabs and new lines are shorter than table cell bounding tags like and . (It would be possible to do better formatting by using the VBScript Space and Len functions to place text in padded, fixed character width columns, but this is beyond the scope of this article.) With 20,000 records, the code example below rendered entirely within three seconds, which is at least four times faster than the fixed-width table formatted data.

simpletable5.asp
<%@ Language=VBScript %>

<% Option Explicit %>

Dim StartTime, EndTime

StartTime = Timer

Dim objCN ' ADO Connection object
Dim objRS ' ADO Recordset object
Dim strsql ' SQL query string
Dim objField1, objField2, objField3, objField4

' Create a connection object
Set objCN = Server.CreateObject("ADODB.Connection")

' Connect to the data source
objCN.ConnectionString = "DSN=datasource"
objCN.Open

' Prepare a SQL query string
strsql = "SELECT Field1,Field2,Field3,Field4 FROM tblData"

' Execute the SQL query and set the implicitly created recordset
Set objRS = objCN.Execute(strsql)

' Set up field references after opening recordset
Set objField1 = objRS("Field1")
Set objField2 = objRS("Field2")
Set objField3 = objRS("Field3")
Set objField4 = objRS("Field4")

' Write out the results as pre-formatted text
Response.write "
"

Do While Not objRS.EOF
Response.write objField1
Response.write vbTab
Response.write objField2
Response.write vbTab
Response.write objField3
Response.write vbTab
Response.write objField4
Response.write vbTab
Response.write vbCrLf
objRS.MoveNext
Loop
Response.write "
"

objRS.Close
objCN.Close
Set objCN = Nothing
Set objRS = Nothing

EndTime = Timer
Response.write "

processing took "&(EndTime-StartTime)&" seconds

"
%>

As an aside, another way to reduce raw data size of the HTML is to simply eliminate the table row and column ending tags, and This technique saves a signficant amount of space in a long query, and is also valid HTML according to the W3C specification. On the other hand, some older browsers choke if these ending tags are excluded. For newer applications in controlled settings, the end tags can be safely excluded. Removing these tags saves bandwidth and transfer time, but otherwise does not affect rendering time versus an ordinary table.

Using the GetString Recordset Function

The Recordset object has two methods that allow retrieving data quickly, without requiring any looping. GetString returns a string from the Recordset, while GetRows returns an array.

Both functions can be used to quickly copy the RecordSet data into the web server's memory and then disconnect from the database server. This can improve performance where database scalability is an issue. GetString is considered first in order to develop a fast technique for using these functions.

The code snippets below show three ways of generating the same information. The first method is the "Optimized Looping" method used in the previous example. "Optimized Looping" is defined simply as looping with field references and eschewing the concatenation operator. The second method, "Full GetString", uses a single call to GetString to return and print the entire Recordset at once. The third method, "Partial GetString" uses a loop with multiple calls to GetString that return and print a small part of the Recordset on each iteration. Shown below are the code snippets and test results. The fastest times are highlighted.

' Optimized Looping (field references, no concatenation)

Response.write "
"

Do While Not objRS.EOF
Response.write objField1
Response.write vbTab
Response.write objField2
Response.write vbTab
Response.write objField3
Response.write vbTab
Response.write objField4
Response.write vbTab
Response.write vbCrLf
objRS.MoveNext
Loop
Response.write "
"
' Full GetString

Response.write "
"

Response.write objRS.GetString(,,vbTab,vbCrLf)
Response.write "
"
' Looping with Partial GetString (30 records per iteration)

Response.write "
"

Do While Not objRS.EOF
Response.write objRS.GetString(2,30,vbTab,vbCrLf)
Loop
Response.write "
"

Test Results
Records KBytes Optimized Looping (s.) Full GetString (s.) Partial GetString (s.)
1000 25 0.10 0.08 0.08
2000 52 0.17 0.13 0.12
10000 262 0.67 0.50 0.39
20000 536 1.25 2.13 0.74

KBytes is the length of the generated HTML file, which is almost entirely the data from the Recordset.

First, the bad news. GetString is a non-intuitive way to print a table of data, requiring remembering the usage and order of the five parameters. The code for GetString is also much more condensed, making it harder to read. And finally, GetString joins every row and column using a fixed format, making customized formatting of the results difficult to impossible. Therefore, the downsides of GetString are that it decreases code maintainability, and it reduces the flexibility of formatting the data in HTML.

The upside, as you might have guessed, is that GetString is about 20-40% faster than "Optimized Looping". Using a single call to GetString is faster than "Optimized Looping" up until 20,000 records, at which point this method takes a significant performance hit. This hit could be explained by the need for the server to allocate additional memory for the lengthy 536KB string. The Pentium III processor that ran these tests has a 256 KB cache, and this is possibly why the performance hit occurs after 262 KB, when the processor may be forced to go to slower system memory.

In any case, this performance hit can be avoided and greater performance achieved by issuing multiple calls to GetString, each returning a small part of the Recordset. The second parameter of GetString limits the number of rows returned. By placing such a function call within a loop, the entire Recordset can be printed. The number of records per call in this test was thirty, and setting it to one hundred increased performance slightly. The optimal setting would vary based on the dataset and system specifications. The code using GetString is shown below.

simpletable6.asp
<%@ Language=VBScript %>

<% Option Explicit %>
<% Dim StartTime, EndTime StartTime = Timer Dim objCN ' ADO Connection object
Dim objRS ' ADO Recordset object
Dim strsql ' SQL query string

' Create a connection object
Set objCN = Server.CreateObject("ADODB.Connection")

' Connect to the data source
objCN.ConnectionString = "DSN=datasource"
objCN.Open

' Prepare a SQL query string
strsql = "SELECT Field1,Field2,Field3,Field4 FROM tblData"

' Execute the SQL query and set the implicitly created recordset
Set objRS = objCN.Execute(strsql)

' Write out the results using GetString in a loop
Response.write "
"

Do While Not objRS.EOF
Response.write objRS.GetString(2,30,vbTab,vbCrLf)
Loop
Response.write "
"

objRS.Close
objCN.Close
Set objCN = Nothing
Set objRS = Nothing

EndTime = Timer
Response.write "

processing took "&(EndTime-StartTime)&" seconds

"
%>

Using the GetRows Recordset Function

While GetString is a very fast way to print data from a Recordset, it suffers from a loss of code maintainability and formatting flexibility. It turns out using GetRows in the same way is nearly as fast, but has the added benefit of allowing ease of code maintainance and unlimited formatting flexibility. The following example replaces GetString with GetRows, and retrieves the array into a temporary variable. The array is then printed out in a simple loop.

simpletable7.asp
<%@ Language=VBScript %>

<% Option Explicit %>
<% Dim StartTime, EndTime StartTime = Timer Dim objCN ' ADO Connection object
Dim objRS ' ADO Recordset object
Dim strsql ' SQL query string
Dim RecordsArray ' To hold the Array returned by GetRows
Dim i ' A counter variable

' Create a connection object
Set objCN = Server.CreateObject("ADODB.Connection")

' Connect to the data source
objCN.ConnectionString = "DSN=datasource"
objCN.Open

' Prepare a SQL query string
strsql = "SELECT Field1,Field2,Field3,Field4 FROM tblData"

' Execute the SQL query and set the implicitly created recordset
Set objRS = objCN.Execute(strsql)

' Write out the results using GetRows in a loop
Response.write "
"

Do While Not objRS.EOF
RecordsArray = objRS.GetRows(30)

' Print out the array
For i = 0 To UBound(RecordsArray, 2)
Response.write RecordsArray(0, i)
Response.write vbTab
Response.write RecordsArray(1, i)
Response.write vbTab
Response.write RecordsArray(2, i)
Response.write vbTab
Response.write RecordsArray(3, i)
Response.write vbTab
Response.write vbCrLf
Next
Loop
Response.write "
"

objRS.Close
objCN.Close
Set objCN = Nothing
Set objRS = Nothing

EndTime = Timer
Response.write "

processing took "&(EndTime-StartTime)&" seconds

"
%>

Test Results of the Three Major Techniques
Records Optimized Looping (s.) Partial GetString (s.) Partial GetRows (s.)
1000 0.10 0.08 0.08
2000 0.17 0.12 0.12
10000 0.67 0.39 0.43
20000 1.25 0.74 0.82

The test results show that the GetRows technique is only about 10% slower than the fastest technique of using GetString. On the other hand, GetRows has the advantage that the code is easier to read and it allows any kind of additional formatting of the returned data. This benefit is achieved without the additional lines of code required by "Optimized Looping" for declaring and setting field references.

Using a Native OLE DB Provider Instead of ODBC

The examples above use the Microsoft Access Driver for ODBC. The ODBC driver is generally slower than using a native OLE DB driver. It also has some differences in capabilities and SQL syntax, which are described in the documentation. In order to use the OLE DB driver, you need to specify the OLE DB Provider for your database in your connection string. The connection string syntax is different for each provider, making it hard to remember. To create a connection string the easy way, follow these steps:

  1. Use Notepad and save an empty file to your desktop called "mydsn.udl".
    (This file may be called anything but must have a .udl extension.)
  2. Double click on the file and use the panels to configure your data source.
  3. Use Notepad to open the "mydsn.udl" file, and copy the connection string to ASP.
  4. Instead of step 3, use "File Name=c:\windows\desktop\mydsn.udl" as your connection string.
Using a native OLE DB Provider is generally faster than going through ODBC.

ADO <--> OLE DB Provider for ODBC <--> ODBC <--> Your Database
ADO <--> Native OLE DB Provider <--> Your Database

The following test uses the previous "Partial GetRows" example and simply replaces "DSN=datasource" with a Native OLE DB connection string for the Jet 4.0 OLE DB Provider. This connects to the identical database file test.mdb. As you can see, the native OLE DB Provider is about 10-20% faster for the simple select query being tested.

simpletable8.asp
<%@ Language=VBScript %>

<% Option Explicit %>
<% Dim StartTime, EndTime StartTime = Timer Dim objCN ' ADO Connection object
Dim objRS ' ADO Recordset object
Dim strsql ' SQL query string
Dim RecordsArray ' To hold the Array returned by GetRows
Dim i ' A counter variable

' Create a connection object
Set objCN = Server.CreateObject("ADODB.Connection")

' Connect to the data source using the native OLE DB Provider for Jet
objCN.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;"&_
"Data Source=C:\Inetpub\wwwroot\data\test.mdb;"&_
"Persist Security Info=False"
objCN.Open

' Prepare a SQL query string
strsql = "SELECT Field1,Field2,Field3,Field4 FROM tblData"

' Execute the SQL query and set the implicitly created recordset
Set objRS = objCN.Execute(strsql)

' Write out the results using GetRows in a loop
Response.write "
"

Do While Not objRS.EOF
RecordsArray = objRS.GetRows(30)

For i = 0 To UBound(RecordsArray, 2)
Response.write RecordsArray(0, i)
Response.write vbTab
Response.write RecordsArray(1, i)
Response.write vbTab
Response.write RecordsArray(2, i)
Response.write vbTab
Response.write RecordsArray(3, i)
Response.write vbTab
Response.write vbCrLf
Next
Loop
Response.write "
"

objRS.Close
objCN.Close
Set objCN = Nothing
Set objRS = Nothing

EndTime = Timer
Response.write "

processing took "&(EndTime-StartTime)&" seconds

"
%>

Test Results
Records ODBC (s.) Jet OLE DB (s.)
1000 0.08 0.07
2000 0.12 0.10
10000 0.43 0.35
20000 0.82 0.65

Summary of Simple Table Techniques

The seven techniques described have reduced the server processing time of the ASP page displaying 1000 records from 3.5 seconds down to 0.07 seconds. The client-side rendering time was also drastically reduced. Each technique increases performance at the cost of coding time, formatting flexibility, and code maintainability. The last method, "Partial GetRows", may cost the least for the amount of performance benefit it yields, because it is simple to code and maintain and has unlimited formatting flexibility. The seven techniques are listed below.

  1. Replace the '&' concatenation operator with liberal use of 'Response.write' within the loop.
  2. Set up pointers or references to the Recordset's fields and use these for printing the record data values.
  3. Make the table and table columns fixed-width. Break lines with 'vbCrLf' after every 256 characters or so.
  4. Eliminate the table completely, and instead use pre-formatted text.
  5. Use GetString in a Loop
  6. Use GetRows in a Loop
  7. Use a Native OLE DB provider instead of ODBC

sql useful things

select @@servername to find the sql server name

select @@version is to find the sql server version

in sql server 2000

net stop mssqlserver
net start mssqlserver

in sql server 2005

net stop sqlbrowser

Querying Multiple Columns

In Microsoft SQL Server 2005, you can use the CONTAINS predicate to query multiple columns by specifying a list of columns to search. The columns must be from the same table.

The following query searches for the term Red in the Name and Color fields of the Production.Product table.

Use AdventureWorks;
GO
SELECT Name, Color FROM Production.Product
WHERE CONTAINS((Name, Color), 'Red');
To find the database information in a sql server

sp_helpdb

To find the row count of each table
---------------------------------------------
DECLARE @TableName SYSNAME
DECLARE count_cur CURSOR READ_ONLY FOR
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE table_type = 'base table'
OPEN count_cur
FETCH NEXT FROM count_cur INTO @TableName
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC ('SELECT ''' + @TableName + ''', COUNT(*)
FROM [' + @TableName + ']')
FETCH NEXT FROM count_cur INTO @TableName
END
CLOSE count_cur
DEALLOCATE count_cur


To change the table rows into columns
---------------------------------------------------------
Create Table #data ([Years] int ,[Amount] bigint ,[GrowthRate] real ,[Share] real ,[Total] bigint ,[Total_GrowthRate] real);

Insert Into #data Values('2005','2751448497','-0.1856','0.3042','904379818171','10.7565');
Insert Into #data Values('2004','180734281','-25.4754','0.3055','59156163765','8.1412');
Insert Into #data Values('2003','2754102244','12.9436','0.3805','723743176992','4.3974');
Insert Into #data Values('2002','186875171','-31.5806','0.3562','52457587465','-15.9544');
Insert Into #data Values('2001','273132144','58.3851','0.4376','62415663014','9.6194');


select * from(select * from (select cast([Years] as real) [Years],cast([Amount] as real) [Amount],[GrowthRate],[Share],
cast([Total] as real) [Total],[Total_GrowthRate] from #data) t1
UNPIVOT
([Value] For Exports in ([Amount],[GrowthRate],[Share],[Total],[Total_GrowthRate])) UPVT) as D
PIVOT
(MIN([Value]) FOR Years IN ([2005], [2004], [2003], [2002], [2001])) AS pvt


To check the action done (inset,delete,update)

select @@rowcount

return '1' if the action done return '0' if the action not done



You can run this code in any database.
Select the rows to determine that data exists.
--------------------------------------------------------------------
SELECT * FROM sysfiles

Execute sp_spaceused to determine that this table uses no space.
----------------------------------------------------------------------------------
EXEC sp_spaceused



To View table columns
------------------------------
Select
A.NAME,B.Name,A.length,A.iscomputed
From
Syscolumns A,Systypes B
where id =
(select id from sysobjects where name='')
and A.XUSERTYPE=B.XUSERTYPE

To View Primary Key tables in a database in sql server 2005
---------------------------------------------------------------------------------
SELECT i.name AS IndexName,
OBJECT_NAME(ic.object_id) AS TableName,
COL_NAME(ic.object_id,ic.column_id) AS ColumnName
FROM sys.indexes AS i
INNER JOIN sys.index_columns AS ic
ON i.object_id = ic.object_id AND i.index_id = ic.index_id
WHERE i.is_primary_key = 1


To View Primary Key tables in a database in sql server 2000
----------------------------------------------------------------------------------
Select
Table_Name,
Constraint_Name
From Information_Schema.Constraint_Table_Usage
Where ObjectProperty(Object_Id(Constraint_Name),
'IsPrimaryKey') = 1
Order By Table_Name Asc


To find the primary key
-----------------------------------
sp_pkeys


sp_special_columns


sql server useful things

sp_depends:

To find the storedprocedures in which a specific table is used.

syntax:

sp_depends

sp_help
(to find the structure of a table)
sp_helptext (to view the stored procedure)
sysobjects (is the table which shows the content of a database)

system stored procedures always starts with 'sp_'

Queries:
-------------
used to check the duplicate count
----------------------------------------------
SELECT email,COUNT(email) AS NumOccurrences FROM users GROUP BY email
HAVING ( COUNT(email) > 1 )


sp_rename

Description

Changes the name of a user-created object or user-defined datatype in the current database.

Syntax

sp_rename objname, newname [,“index” | “column”]

Parameters

objname

is the original name of the user-created object (table, view, column, stored procedure, index, trigger, default, rule, check constraint, referential constraint, or user-defined datatype). If the object to be renamed is a column in a table, objname must be in the form “table.column”. If the object is an index, objname must be in the form “table.indexname”.

newname

is the new name of the object or datatype. The name must conform to the rules for identifiers and must be unique to the current database.

index

specifies that the object you are renaming is an index, not a column. This argument allows you to rename an index that has the same name as a column, without dropping and re-creating the index.

column

specifies that the object you are renaming is a column, not an index. This argument is part of the same option as the index argument.




http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.help.ase_15.0.sprocs/html/sprocs/sprocs185.htm

DTS optimization Tips

DTS Optimization Tips

*****

  • Avoid using DTS if it is possible to use Transact-SQL distributed query such as a SELECT INTO statement to transfer data.
    Using Transact-SQL is the fastest method to move data between SQL Server tables, so try to use Transact-SQL statements to move data whenever possible.


  • *****

  • Try to use BULK INSERT statement instead of bcp or DTS to load data into SQL Server from the text file.
    The BULK INSERT statement is much faster than bcp or the data pump to perform text file import operations, however, the BULK INSERT statement cannot export data from SQL Server to a data file.


  • *****

  • Use the bcp utility instead of DTS when you need to export data from the SQL Server table into a text file.
    The bcp utility is much faster than DTS, so try to use it whenever possible.


  • *****

  • Try to avoid using data pump operations that use ActiveX transformation scripts.
    Because data pump operations that use ActiveX transformation scripts can be up to two to four times slower than copy operations, you should avoid using ActiveX transformation scripts, whenever possible.


  • *****

  • If you cannot avoid using ActiveX scripts in your data pump operations, try to use VBScript instead of JScript or PerlScript.
    Microsoft recommends to use VBScript because scripts written in VBScript run approximately 10 percent faster than scripts written in JScript, which in turn run approximately 10 percent faster than scripts written in PerlScript.


  • *****

  • When the transformation contains many columns (more than 20) and the data pump operations use ActiveX transformation scripts, use ordinal values to refer to columns in ActiveX transformations instead of referring to columns by name.
    Use this tip only when the transformation contains many columns. If the transformation contains less than 20 columns, use columns name to refer to columns in ActiveX transformations to make the script easier to read.


  • *****

  • Try to use many-to-many copy column transformations instead of one-to-one copy column transformations.
    The DTS Import/Export Wizard uses many-to-many column mappings. By default, the DTS Designer assigns one-to-one column mappings to transformations in order to improve readability. Because a single many-to-many copy column transformation is faster then many one-to-one copy column transformations, you can manually set your Transform Data task or Data Driven Query task to use many-to-many column mappings. For example, to set Transform Data task to use many-to-many column mappings in SQL Server 2000 DTS Designer, you can do the following:
    1. Choose appropriate Transform Data task in the DTS Designer.
    2. Right-click this task and select Properties.
    3. On the Transformations tab click 'Select All' button.
    4. Click 'Delete All' button.
    5. Click 'New' button and choose 'Copy Column' in the Create New Transformation window.
    6. Specify the transformation options and click 'OK' button.


  • *****

  • You can increase the DTS package priority.
    To increase the DTS package priority in SQL Server 2000, try the following:
    1. Run SQL Server Enterprise Manager.
    2. Expand a server group; then expand a server.
    3. Expand Data Transformation Services and choose appropriate package.
    4. Right-click package and select 'Design Package'.
    5. From the top menu of the DTS Designer click Package and select Properties.
    6. On the General tab increase the package priority by moving the slider bar to the right one or two steps (the slider bar has three position, and the default setting is at the second setting).


  • *****

  • You can increase the Transform Data task or Data Driven Query task priority.
    To increase the Transform Data task priority in SQL Server 2000 DTS Designer, you can do the following:
    1. Choose appropriate Transform Data task in the DTS Designer.
    2. Right-click this task and select Workflow Properties.
    3. On the Options tab increase the task priority by moving the slider bar to the right one or two steps (the slider bar has five position, and the default setting is at the third setting).


  • *****

  • Try to use 'Microsoft OLE DB Provider for SQL Server' instead of 'Microsoft ODBC Driver for SQL Server' and 'Microsoft OLE DB Provider for Oracle' instead of 'Microsoft ODBC Driver for Oracle'.
    Because native OLE DB provider is faster than ODBC provider, you should use OLE DB provider whenever possible.


  • *****

  • Try to avoid DTS lookups.
    Because DTS lookups slow down performance, try to use the Transact-SQL statements to perform the same functions.


  • *****

  • Check the 'Use fast load' advanced option of the Transform Data task.
    When you enable this option, the high-speed bulk-copy processing will be used. To enable this option in SQL Server 2000 DTS Designer, you can do the following:
    1. Choose appropriate Transform Data task in the DTS Designer.
    2. Right-click this task and select Properties.
    3. On the Options tab check the 'Use fast load' option.


  • *****

  • Increase the ODBC query time-out value to improve query performance on large SQL Server 2000 DTS packages stored in a repository.
    Change this registry setting from the default value (10 seconds): HKEY_LOCALMACHINE\SOFTWARE\Microsoft\Repository\Engine\ODBCQueryTimeout The ODBC query time-out values are measured in seconds.


  • *****

  • When using SQL Server 2000 Transform Data task, try to use 'Copy Column' method to transfer data.
    This is the fastest way to transfer data using Transform Data task, so it should be used whenever possible.


  • *****

    storedprocedure optimization

    Stored Procedures Optimization Tips

    *****

  • Use stored procedures instead of heavy-duty queries.
    This can reduce network traffic, because your client will send to server only stored procedure name (perhaps with some parameters) instead of large heavy-duty queries text. Stored procedures can be used to enhance security and conceal underlying data objects also. For example, you can give the users permission to execute the stored procedure to work with the restricted set of the columns and data.


  • *****

  • Include the SET NOCOUNT ON statement into your stored procedures to stop the message indicating the number of rows affected by a Transact-SQL statement.
    This can reduce network traffic, because your client will not receive the message indicating the number of rows affected by a Transact-SQL statement.


  • *****

  • Call stored procedure using its fully qualified name.
    The complete name of an object consists of four identifiers: the server name, database name, owner name, and object name. An object name that specifies all four parts is known as a fully qualified name. Using fully qualified names eliminates any confusion about which stored procedure you want to run and can boost performance because SQL Server has a better chance to reuse the stored procedures execution plans if they were executed using fully qualified names.


  • *****

  • Consider returning the integer value as an RETURN statement instead of an integer value as part of a recordset.
    The RETURN statement exits unconditionally from a stored procedure, so the statements following RETURN are not executed. Though the RETURN statement is generally used for error checking, you can use this statement to return an integer value for any other reason. Using RETURN statement can boost performance because SQL Server will not create a recordset.


  • *****

  • Don't use the prefix "sp_" in the stored procedure name if you need to create a stored procedure to run in a database other than the master database.
    The prefix "sp_" is used in the system stored procedures names. Microsoft does not recommend to use the prefix "sp_" in the user-created stored procedure name, because SQL Server always looks for a stored procedure beginning with "sp_" in the following order: the master database, the stored procedure based on the fully qualified name provided, the stored procedure using dbo as the owner, if one is not specified. So, when you have the stored procedure with the prefix "sp_" in the database other than master, the master database is always checked first, and if the user-created stored procedure has the same name as a system stored procedure, the user-created stored procedure will never be executed.


  • *****

  • Use the sp_executesql stored procedure instead of the EXECUTE statement.
    The sp_executesql stored procedure supports parameters. So, using the sp_executesql stored procedure instead of the EXECUTE statement improve readability of your code when there are many parameters are used. When you use the sp_executesql stored procedure to executes a Transact-SQL statements that will be reused many times, the SQL Server query optimizer will reuse the execution plan it generates for the first execution when the change in parameter values to the statement is the only variation.


  • *****

  • Use sp_executesql stored procedure instead of temporary stored procedures.
    Microsoft recommends to use the temporary stored procedures when connecting to earlier versions of SQL Server that do not support the reuse of execution plans. Applications connecting to SQL Server 7.0 or SQL Server 2000 should use the sp_executesql system stored procedure instead of temporary stored procedures to have a better chance to reuse the execution plans.


  • *****

  • If you have a very large stored procedure, try to break down this stored procedure into several sub-procedures, and call them from a controlling stored procedure.
    The stored procedure will be recompiled when any structural changes were made to a table or view referenced by the stored procedure (for example, ALTER TABLE statement), or when a large number of INSERTS, UPDATES or DELETES are made to a table referenced by a stored procedure. So, if you break down a very large stored procedure into several sub-procedures, you get chance that only a single sub-procedure will be recompiled, but other sub-procedures will not.


  • *****

  • Try to avoid using temporary tables inside your stored procedure.
    Using temporary tables inside stored procedure reduces the chance to reuse the execution plan.


  • *****

  • Try to avoid using DDL (Data Definition Language) statements inside your stored procedure.
    Using DDL statements inside stored procedure reduces the chance to reuse the execution plan.


  • *****

  • Add the WITH RECOMPILE option to the CREATE PROCEDURE statement if you know that your query will vary each time it is run from the stored procedure.
    The WITH RECOMPILE option prevents reusing the stored procedure execution plan, so SQL Server does not cache a plan for this procedure and the procedure is recompiled at run time. Using the WITH RECOMPILE option can boost performance if your query will vary each time it is run from the stored procedure because in this case the wrong execution plan will not be used.


  • *****

  • Use SQL Server Profiler to determine which stored procedures has been recompiled too often.
    To check the stored procedure has been recompiled, run SQL Server Profiler and choose to trace the event in the "Stored Procedures" category called "SP:Recompile". You can also trace the event "SP:StmtStarting" to see at what point in the procedure it is being recompiled. When you identify these stored procedures, you can take some correction actions to reduce or eliminate the excessive recompilations.


  • *****