TimFred
asked on
Can I convert a cursor to a "Fire Hose" Cursor in my stored procedure?
I have a stored procedure with many cursors in it. Sometimes it runs for 5-7minutes. Rather than re-writing thte stored proc. I would like to change the cursors to act as a "Fire Hose Cursor". I found an article on MSDN about server side cursors and firehose cursors and they said that: It turns out that ODBC determines whether a server cursor or a Default Result Set should be used during prepare/execute time. If the multiple array binding happens before prepare/execute (row array size > 1), server cursor is used by ODBC. It could even re-prepare if the binding with array size > 1 is left before the next execute. So the solution is to temporarily set the row array size to 1 before the prepare/execute/re-execute and reset it back to the >1 value before fetching. That way, you get a fire hose cursor and the block-fetch behavior.
The following is a sample of one of my cursors(I did not paste the whole thing in here, it actually goes on for 207 fields):
DECLARE cur_total CURSOR FOR
SELECT distinct r, person_id, inst_id, identity_id
FROM #temp
OPEN cur_total
FETCH cur_total INTO @r, @person_id2, @instid2, @identity_id
WHILE (@@fetch_status = 0) BEGIN
DECLARE cur_fields CURSOR FOR
SELECT DISTINCT field_order, field_name
FROM #temp
where person_id = @person_id2
and r = @r
and inst_id = @instid2
and identity_id = @identity_id
order by field_order, field_name
OPEN cur_fields
FETCH cur_fields INTO @field_order, @field_name
IF (@@fetch_status = 0) BEGIN
UPDATE #done
SET field1_name = @field_name,
field1_value = (select field_value
FROM #temp t
WHERE t.field_name = @field_name AND t.person_id = @person_id2
and t.r = @r and t.inst_id = @instid2 and t.identity_id = @identity_id)
where person_id = @person_id2
and r = @r
and inst_id = @instid2
and counter = @identity_id
END
FETCH cur_fields INTO @field_order, @field_name
IF (@@fetch_status = 0) BEGIN
UPDATE #done
SET field2_name = @field_name,
field2_value = (select field_value
FROM #temp t
WHERE t.field_name = @field_name AND t.person_id = @person_id2
and t.r = @r and t.inst_id = @instid2 and t.identity_id = @identity_id)
where person_id = @person_id2
and r = @r
and inst_id = @instid2
and counter = @identity_id
END
CLOSE cur_fields
deallocate cur_fields
FETCH cur_total INTO @r, @person_id2, @instid2, @identity_id
END
CLOSE cur_total
deallocate cur_total
Is there some way I can convert my cursor code so that it operates as a "fire hose" cursor? Maybe by incorporating:
// set row array size to 1 just before execute
(SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)1, 0);
// set row array size to > 1 just before fetch
(SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)ROW_ARRAY_SIZE , 0);
Please let me know if something like this is possible?
The following is a sample of one of my cursors(I did not paste the whole thing in here, it actually goes on for 207 fields):
DECLARE cur_total CURSOR FOR
SELECT distinct r, person_id, inst_id, identity_id
FROM #temp
OPEN cur_total
FETCH cur_total INTO @r, @person_id2, @instid2, @identity_id
WHILE (@@fetch_status = 0) BEGIN
DECLARE cur_fields CURSOR FOR
SELECT DISTINCT field_order, field_name
FROM #temp
where person_id = @person_id2
and r = @r
and inst_id = @instid2
and identity_id = @identity_id
order by field_order, field_name
OPEN cur_fields
FETCH cur_fields INTO @field_order, @field_name
IF (@@fetch_status = 0) BEGIN
UPDATE #done
SET field1_name = @field_name,
field1_value = (select field_value
FROM #temp t
WHERE t.field_name = @field_name AND t.person_id = @person_id2
and t.r = @r and t.inst_id = @instid2 and t.identity_id = @identity_id)
where person_id = @person_id2
and r = @r
and inst_id = @instid2
and counter = @identity_id
END
FETCH cur_fields INTO @field_order, @field_name
IF (@@fetch_status = 0) BEGIN
UPDATE #done
SET field2_name = @field_name,
field2_value = (select field_value
FROM #temp t
WHERE t.field_name = @field_name AND t.person_id = @person_id2
and t.r = @r and t.inst_id = @instid2 and t.identity_id = @identity_id)
where person_id = @person_id2
and r = @r
and inst_id = @instid2
and counter = @identity_id
END
CLOSE cur_fields
deallocate cur_fields
FETCH cur_total INTO @r, @person_id2, @instid2, @identity_id
END
CLOSE cur_total
deallocate cur_total
Is there some way I can convert my cursor code so that it operates as a "fire hose" cursor? Maybe by incorporating:
// set row array size to 1 just before execute
(SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)1, 0);
// set row array size to > 1 just before fetch
(SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)ROW_ARRAY_SIZE
Please let me know if something like this is possible?
The "Server Side" and "Firehose" Cursors that ODBC uses are not the same thing as the Cursor declared in your Stored Procedure.
The ODBC Cursors deal with the resultset returned from your stored procedure after the stored procedure has completed.
So, if your stored procedure takes 5 minutes to execute, nothing you do in VB is going to speed that up.
So First, the obligatory moral statement: Do NOT use CURSORS in SQL. Try to rewrite your SP into something set based.
If it turns out that you really need to do this row by agonizing row, create your recordsets in VB and do the processing there instead of in SQL.
--
JimFive
The ODBC Cursors deal with the resultset returned from your stored procedure after the stored procedure has completed.
So, if your stored procedure takes 5 minutes to execute, nothing you do in VB is going to speed that up.
So First, the obligatory moral statement: Do NOT use CURSORS in SQL. Try to rewrite your SP into something set based.
If it turns out that you really need to do this row by agonizing row, create your recordsets in VB and do the processing there instead of in SQL.
--
JimFive
ASKER
Lowfatspread,
Can you give me an example of how you would convert the cursor example I gave to an update statement?
Thanks!
Can you give me an example of how you would convert the cursor example I gave to an update statement?
Thanks!
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
please take a look at this article and let me know if I can implement this to speed up my cursors:
http://blogs.msdn.com/mssqlisv/archive/2006/03/24/560386.aspx
http://blogs.msdn.com/mssqlisv/archive/2006/03/24/560386.aspx
No, your problem is with SQL Cursors not ODBC Cursors.
--
JimFive
--
JimFive
the server side cursor processing is for the result sets returned by a stored procedure it has nothing to do with the
internal cursors within the stored procedure itself...
a brief examination of your code leads me to believe that this cursor is not required...
and should be replace by pure update statements with joins to the tables in question.
a re-design of your stored procedure is the best way forward.
Regards,
Lowfatspread