September 19, 2005 at 11:40 pm
Hi Experts!
I have a question about triggers.
I have a stored procedure that I call from an ASP page that can take a longer amount of time than would be good to keep a user waiting for the page to load. I was thinking to change the call to the stored procedure to a simple update of a single column in a single table row that would fire a trigger that calls the stored procedure in order reduce the time the the user waits for the page to load. This would only work if one assumption that I'm making is correct. That assumption is that events will occur in the following order:
1. Update query called from ASP page
2. Trigger fires, check updated column. If correct column is updated, stored proc is called.
3. Update query completes and ASP page fully loads.
4. Some time later, the stored proc completes
Is this how things work with a trigger or will the update query that fired the trigger not complete until the trigger fully executes? If it is the latter, than this will gain no advantage for the users experience of having a faster loading ASP page.
If I can't use a trigger to do what I want, does anyone have a suggestion regarding what I can do to get a stored proc to trigger from an ASP page and run in the background so the page can fully load without the stored proc completing? The ASP page is not dependent on the results of the stored proc call, so this is OK.
Any help would be greatly appreciated.
Thanks!
September 19, 2005 at 11:57 pm
Basically the trigger action has to complete before the asp finishes because those actions are part of the transaction. If you need to delay that, you can flag a field in a table, then run a job every minute or two checking to see if that flag is set. If it is run the proc to finish the task.
September 20, 2005 at 2:18 am
Well, the way it works, is that the stored proc operates on a subset of records that pertain to a group of users. When a user in the group hits that page when the flag is set, the stored procedure is called with a group ID parameter to operate on the records that are pertinent to that group. The flag gets set for ALL groups at once but the stored procedure only gets called on demand by a user going to the ASP page. This helps break up the processing.
Using a job like you describe, the job would find ALL flags set and call the stored procedure for ALL groups which will take a long time to run. Shortening the processing time and strain on system resources was the purpose for breaking up the transaction in the first place.
Things work pretty well as is except for a user in a large group who hits the page when the flag is set. The stored proc for that user could take up to 20 seconds which is quite long when waiting for a page to load.
How about creating a unique job that calls the stored proc and then deletes itself. I could then schedule the job to run immediately. Would this work and run in the background? I'm not sure exactly how to do this though.
Thanks in advance!
September 20, 2005 at 7:00 am
You can always execute the job right away. But I'm not sure that this is called as an external process... but that would be pretty easy for you to test.
September 20, 2005 at 7:10 am
I confirm that it runs in another process (checked using a waitfor delay in a job that I fired from an alert).
September 20, 2005 at 11:13 am
Yeah, I got this to work too! Now, I'm concerned that this is improper use of the Job facility of SQL Server. I could have a couple hundred of these jobs created in a short amount of time. Is this OK to do? Will this cause more overhead for SQL Server than just calling the stored proc to the point that it bogs the server down?
September 20, 2005 at 11:18 am
I might understand this process for huge batch processing that can't hold the user from doing something else. But I can't see that being used on almost every part of the app???
Have you looked into optimizing the current code/dbs/servers? Or maybe upgrading the server if it's no longer adequate?
September 20, 2005 at 3:13 pm
to start a job from a Trigger is bad. Jobs are NOT re-entrant, can you imagine what would happen if you try to start a job that hasn't finished yet?
I think you need to redisign your app. You can as posted above poll with a job the "flagged" records and perform the corresponding actions. To avoid the ALL records processing that you mention try to think about it as a different table in which you have two columns GroupID and "ProcessedFlag" The trigger inserts the GroupID then on the job you can call the proc with First Group that has not been processed and when done, Flag it as well ... Done!
* Noel
September 20, 2005 at 3:16 pm
Thanx, looks like we agree again .
September 20, 2005 at 3:25 pm
Well, here's what would happen:
1. A Flag gets set marking that all groups need an update. I only want the a groups update to happen if a user of that group makes a request by going to that ASP page.
2. In the ASP page, that groups Flag is CLEARED within code that checks the flag, so other users of the group hitting the ASP page can not trigger the update.
3. After clearing the flag, a stored proc is called which creates a job and starts the job. From TSQL a job can be created with a dynamic name, so I'd append the unique group ID to the job name creating a unique job name. So with the flag protection and unique job name, there would be no reentrancy since a users of the same group hitting the ASP page would no longer see the flag set. The created job would simply call my other stored proc that acutally updates the data.
4. The job is deleted upon completion.
Like I said, the original stored proc that updates the data is working pretty well considering how much it is doing. But, for the user experience of a web page loading, it is taking too long, so I'd like to have it run in the background.
Any other thoughts on this idea?
September 20, 2005 at 6:02 pm
the problem with creating jobs on the fly is that you are assuming alot!
1. The Account that created the job needs access to msdb (something I don't like particulary from ASP)
2. That Name has to be moved back and forth inorder to create and delete somenthing that can be static
3. If you still feel happy about your decision feel free to do it but you are really generating more activity than what's really needed. Tables are meant for that .. a lot of DML but not the system ones (in my opinion)
Cheers
* Noel
September 20, 2005 at 6:13 pm
Hmmm. Well I understand the ASP issue with access to msdb. The name is entirely used by the single stored procedure that creates the job so handling of that is pretty tidy. I'm not sure how it could be static unless the job was handling things in batch.
Regarding generating more activity, is it really? In one case, I call a stored proc from ASP that takes some time (10-20 secs) causing the page to load slowly. In the other case, I call a small stored proc that generates and starts a job that calls the other slower stored proc which can then run in the background. The small stored proc that creates the job returns quickly and the ASP page loads quickly. The job runs and deletes itself. Seems like a little bit of extra activity but a better user experience. I am concerned that this may violate some usage of jobs however.
How frequently can I make a job run? If I had a job running frequently that would call the updating stored proc on all groups with the flag set, maybe that would spread out the processing enough that it wouldn't be so bad. Then no processing would be done from the ASP call. Is that what you're suggesting?
September 20, 2005 at 6:33 pm
Yes that was my sussestion but wasn't expecting high frequency Officially you can't run a job in intervals of less than a minute. There are ways around it like round robin the minute with #seconds/#Jobs or using undocumented settings for the frequency. If you really need high frequency I woud do it in the FRONT end somehow (it is ussually more flexible )
* Noel
September 21, 2005 at 2:05 am
There is an undocumented way to run a job every 10 seconds.
Here is an example how we use it:
DECLARE @nJobId AS UNIQUEIDENTIFIER
DECLARE @szJobName AS VARCHAR(1000)
DECLARE @DBName as VARCHAR(1000)
SET @DBName = DB_NAME() --Database to run the command on
SET @szJobName = 'Queue Count Refresh ' + @DBName
IF EXISTS (SELECT name FROM msdb.dbo.sysjobs WHERE name = @szJobName) BEGIN
EXEC msdb.dbo.sp_delete_job @job_name = @szJobName
END
EXEC msdb.dbo.sp_add_job @job_name = @szJobName,
@enabled = 1,
@description = 'Calls QueueCountJob to update the QueueCount table',
@job_id = @nJobId OUTPUT
EXEC msdb.dbo.sp_add_jobstep @job_id = @nJobId,
@step_id = 1,
@step_name = 'Queue Count Refresh',
@subsystem = 'TSQL',
@command = 'EXECUTE QueueCountRefresh', -- Command to execute
@database_name = @DBName --Database to run the command on
EXEC msdb.dbo.sp_add_jobschedule @job_id = @nJobId,
@name = 'Every 10 seconds',
@freq_type = 4,
@freq_interval = 1,
@freq_subday_type = 0x2, -- Second
@freq_subday_interval = '10' -- 10 seconds
EXEC msdb.dbo.sp_add_jobserver @job_id = @nJobId
GO
Viewing 14 posts - 1 through 13 (of 13 total)
You must be logged in to reply to this topic. Login to reply