Jeff explains how to reduce the time it takes to reduce the retrieve a recordset from a large database using an asynchronous call. Read this article to find out how.
Technologies Referenced
- Microsoft Active Server Pages
- Microsoft SQL Server 7.0
- Distributed Management Objects (SQL DMO)
- Data Transformation Services (DTS)
- Visual Basic
The Company
MatureWell Inc. is an organization based in Tucson, AZ, and specializes in web based solutions for the HMO industry. It recently acquired Premier Healthcare of Arizona, which is based in Phoenix. MatureWell is currently in the process of migrating Premier from their existing IT infrastructure, to MatureWell’s Web based solution, which will eventually be marketed to other organizations also.
The Situation
The users wanted to have an html form that allowed them to pass in some parameters, call a stored procedure, and then return a recordset to be displayed in the browser, using Excel. This was all fine and dandy, except we are talking about searching through over a million rows of data, and bringing back about 15 fields for each returned record, which can be time consuming. Our in-house custom system uses Microsoft Web technologies, n-Tiered architecture, and Windows DNA.
Although still being developed and "productized", it is currently being used by Premier Health Care of Arizona, a subsidiary of MatureWell Inc., which has over 80,000 participating members. Because this number of members is actually considered to be quite small for a well-established HMO, our system has to be very scalable to accommodate for growth and meet the needs of larger HMOs. This project was just one of the many issues we had to overcome during the migration process for Premier.
Back to the Development Aspects
After building the user interface, it was time to move on to the stored procedure. Just building the sProc was not enough. It took several minutes to finish executing, and this was not acceptable. Thus, I found myself spending several hours trying to optimize it.
After modifying and adding additional INDEXES, restructuring the SQL and the WHERE clause, I found that it still took about five minutes to run and generate the recordset. When this was moved into our production site, which uses a four processor I386 architecture and two gigabytes of RAM, the user had to wait for what we still consider to be way too long. Imagine staring at a "status bar" for minutes waiting for the results to be returned; not a good thing.
A Better Way
First, in order to fit with the rest of our system architecture, we decided to move the business logic into a server-side COM object. The logic included into this COM object allowed us to make an asynchronous call to an already created DTS package in MS SQL 7. In order to reference the DTS object model, we used SQL Distributed Management Objects or SQL DMO. This is an object model found inside of MS SQL 7.
Here is a snippet of the method that does this.
Public Function AsyncExecute(ByVal PackageName As String, ByVal Server As String, Optional ByVal UserName As String, _
Optional ByVal UserPass As String, Optional ByVal PackagePassword As String, Optional ByVal GlobalVariables As Variant) As Boolean
Dim oPackage As DTS.Package
Dim oJob As SQLDMOUtil.Job
Dim sJobName As String
Dim i As Integer
On Error GoTo ErrorHandler
Set oPackage = CreateObject("DTS.Package")
If Trim(UserName) <> "" Then
oPackage.LoadFromSQLServer Server, UserName, UserPass, DTSSQLStgFlag_Default, PackagePassword, , , PackageName
Else
oPackage.LoadFromSQLServer Server, , , DTSSQLStgFlag_UseTrustedConnection, PackagePassword, , , PackageName
End If
If Not IsMissing(GlobalVariables) Then
For i = 0 To UBound(GlobalVariables)
oPackage.GlobalVariables(GlobalVariables(i, 0)).Value = GlobalVariables(i, 1)
Next
End If
' Save the package with the new global variable values
If Trim(UserName) <> "" Then
oPackage.SaveToSQLServer Server, UserName, UserPass, DTSSQLStgFlag_Default
Else
oPackage.SaveToSQLServer Server, , , DTSSQLStgFlag_UseTrustedConnection
End If
' Create a job object to schedule this DTS packae to run
Set oJob = CreateObject("SQLDMOUtil. Job")
' Generate a semi unique job name based on the package name and the hour minute and seconds
sJobName = PackageName & "_" & CStr(Hour(Time())) & CStr(Minute(Time())) & CStr(Second(Time()))
' Schedule the package to run immediately and delete itself after running whether the job was successfull or not
oJob.ScheduleDTSPackage sJobName, PackageName, Server, Date, Time(), , , , , , SQLDMOComp_Always, True
' Clean up
Set oPackage = Nothing
Set oJob = Nothing
AsyncExecute = True
#If bUseMTS Then
oCtx.SetComplete
#End If
Exit Function
The purpose of the Asynchronous call was to allow the user to regain control of the browser quickly, instead of having to wait until the stored procedure was finished executing, and the recordset was generated. Instead, using our asynchronous method, the process would work like this:
Change the values of the DTS global variables we created to reflect the values of the parameters that were passed into our asynchronous method as a two dimensional array, which we got from the user via the html form. Then we needed to build a dynamic SQL string using these values, and assign it to the "Data Pump Task" property of DTS. This allows us to call the sProc and pass it the dynamic parameters on the "fly"
Create a new SQL "JOB" and attach our dynamically modified DTS package
Schedule the JOB to run immediately.
After completing the process, delete the JOB. We still have the DTS package to use next time, just not the JOB that scheduled it to run for this instance.
The Logic Inside of the ASP
<%
'dim the variants
dim objDTSJOB
dim sPackageName
dim sServerForPackage
'dim the array for storing the parameters
dim arrayGblVars
redim arrayGblVars(13,1)
'name of the DTS Package
sPackageName = "MyDTSPackage"
'name of the database server
sServerForPackage = "MyServer"
'populate the array. The name values in the array must be the same
'name as the global variable in the DTS.
'Use the values from the html form
arrayGblVars(0,0) = "Name0"
arrayGblVars(0,1) = Request.Form("Value")
arrayGblVars(1,0) = "Name1"
arrayGblVars(1,1) = Request.Form("Value")
arrayGblVars(2,0) = "Name2"
arrayGblVars(2,1) = Request.Form("Value")
arrayGblVars(3,0) = "Name3"
arrayGblVars(3,1) = Request.Form("Value")
arrayGblVars(4,0) = "Name4"
arrayGblVars(4,1) = Request.Form("Value")
arrayGblVars(5,0) = "Name5"
arrayGblVars(5,1) = Request.Form("Value")
arrayGblVars(6,0) = "Name6"
arrayGblVars(6,1) = Request.Form("Value")
arrayGblVars(7,0) = "Name7"
arrayGblVars(7,1) = Request.Form("Value")
arrayGblVars(8,0) = "Name8"
arrayGblVars(8,1) = Request.Form("Value")
arrayGblVars(9,0) = "Name9"
arrayGblVars(9,1) = Request.Form("Value")
arrayGblVars(10,0) = "Name10"
arrayGblVars(10,1) = Request.Form("Value")
arrayGblVars(11,0) = "Name11"
arrayGblVars(11,1) = Request.Form("Value")
arrayGblVars(12,0) = "Name12"
arrayGblVars(12,1) = Request.Form("Value")
arrayGblVars(13,0) = "Name13Email"
arrayGblVars(13,1) = AUOEmailValue
'Create an instance of the object that will build a DTS JOB, execute it, then delete the JOB.
'control will be returned back to the browser as soon as the method is executed.
on error resume next
set objDTSJOB = Server.CreateObject("SQLDMOUtil.DTSPackage")
objDTSJOB.AsyncExecute sPackageName, sServerForPackage,,,,arrayGblVars
if err.number <> 0 then
Response.Write "There was an error, please run the report again. "
Response.Write "The following error occured: " & err.description
else
Response.Write "Your request has been submitted and the data will be emailed to you in the next few minutes."
end if
set objDTSJOB = nothing
%>
Main Advantage
The user will gain back control of the browser as soon as the JOB gets scheduled (almost immediately). The browser’s response will be a message saying "the data will be emailed to you in a few minutes". As far as the email goes, our site is configured using Site Server 3.0 and it's Personalization and Membership Directory. Thus, every user has a Site Server account, which stores personal information, including each users email address.
So, we query this LDAP server, retrieve the user’s email address from the AUO object, and this value is also one of those global variables that is passed inside of the array. Now, while they are waiting for the data to be emailed to them, then can be running other reports, or doing whatever else they want since they will no longer have to wait for the asp page to load the response. The generated recordset will be attached to the email as an Excel spreadsheet.
Summary
I was given the task of creating a report that would allow the user to pass in specific parameters, call a stored procedure, generate a recordset, and then display it in Excel via the user’s browser. The problem that I encountered was the amount of time required for this process to complete.
So, realizing this was not an optimal solution we decided to transfer control of the process to the server as soon as possible so the user could go about their other activities, instead of waiting and being tied down to the browser until the result it brought back to display. To do this, we used SQL DMO, ASP, AND DTS.
| DISCLAIMER: The content provided in this article is not warranted or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real-world tactics for security and implementation of best practices. We are not liable for any negative consequences that may result from implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware. |
More ASP Articles
More By Jeff Mangan
developerWorks - FREE Tools! |
Building a software-as-a-service solution requires addressing a few key technical challenges. In this webcast, we'll focus on the role of IBM Tivoli Directory Server and WebSphere Portlet Factory in creating a Software as a Service solution. We will demonstrate how to use Tivoli Directory Server to prevent the user population of one tenant from accessing the virtual portal and portlet components of another tenant. We will also use the dynamic profile capability of WebSphere Portlet Factory to create multiple highly customized applications from one code base. FREE! Go There Now!
|
|
|
|
CakePHP is a stable production-ready, rapid-development aid for building Web sites in PHP. This "Cook up Web sites fast with CakePHP" series shows you how to build an online product catalog using CakePHP. FREE! Go There Now!
|
|
|
|
Learn how you can extend modern application lifecycle management to IBM System z through the IBM Rational Software Delivery Platform (SDP). The Did you say mainframe? e-kit includes podcasts, webcasts, tutorials, white and red papers, demos, and articles designed to help ease the challenges of modernizing your enterprise. This complimentary kit for mainframe developers is a practical, how-to guide for making the most of an existing development environment, including the skills and infrastructure already in place at an established enterprise. FREE! Go There Now!
|
|
|
|
Download the IBM WebSphere Portal V6.1 beta code and learn more about the rich features and enhancements in IBM WebSphere Portal V6.1. WebSphere Portal provides a composite application or business mashup framework and the advanced tooling needed to build flexible, SOA-based solutions, and scalability to meet the needs of any size organization. FREE! Go There Now!
|
|
|
|
In this tutorial, you can learn how to install and configure the IBM Rational Asset Manager Eclipse client, explore the different views in the Asset Management perspective, learn various search techniques, work with existing assets, and submit a new asset. FREE! Go There Now!
|
|
|
|
To create, test, and deploy a Web-based application or Web service rapidly, you need a proven relational database, a standards-compliant Web application server, and a flexible IDE. Ideally, all these software packages are production-tested, simple to obtain, easy to use, and well integrated with one another. This tutorial shows you how to use IBM-backed open source and free software to kick-start your Java Web-based application development. You'll learn exactly where to download such components, install them, and get them working for you today. FREE! Go There Now!
|
|
|
|
The combination of Eclipse, DB2 Express-C 9.5, and WebSphere Application Server Community Edition 2.0 -- all free to download, use, and deploy -- is an excellent from-prototype-to-production suite for all of your Java and Java enterprise development needs. What might not be obvious is the relative ease with which you can use these proven tools to create, test, and deploy cutting-edge, lightweight applications as well. This tutorial guides you through the development of a small human-resources application, first using conventional JavaServer Pages (JSP) based technology, and then migrating it to a highly interactive solution using Ajax. FREE! Go There Now!
|
|
|
|
Join this Rational Talks to You teleconference on December 11 at 1:00 pm ET to get tips on building your own plugins with Rational Method Composer. Get your questions answered! FREE! Go There Now!
|
|
|
|
Here's a fun way to learn about DB2! Learn or teach the basics of DB2 and relational database with an interactive game called The DB2 Detective Game. The game teaches relational database concepts and shows how technology can be applied to solving real-life problems (the game's theme is a crime investigation). This tutorial has been updated for DB2 9. FREE! Go There Now!
|
|
|
|
IBM Lotus Notes 8 provides a wide range of developers the ability to provide customized, integrated user interfaces via composite applications and via custom sidebar and toolbar plug-ins. This webcast provides you with tips and techniques to use with out-of-the-box capabilities of Lotus Notes 8, and survey how you can share useful components within your own company and within a larger community. FREE! Go There Now!
|
|
|
|
All FREE IBM® developerWorks Tools! |