November 12, 2010 at 1:50 pm
Just wanted to throw out a question to developers on what method do they use to loop around different objects.I typically use cursors, was wondering if there is a better way or any new concept in 2008 where i can avoid cursors. Thanks
November 12, 2010 at 1:52 pm
If you really do need to loop through a dataset, then a cursor is a perfectly valid way to do it. The problem with cursors isn't that, it's that most uses of them can be resolved by much more efficient queries that work faster.
If you're trying to avoid cursors for the sake of avoiding them, then CLR has some good looping methods in it.
- Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
Property of The Thread
"Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon
November 12, 2010 at 2:33 pm
You say to "loop through different objects". Can you clarify this? As Gus said, if you really do have to loop, a cursor will do that, but most people think they have to loop when they really don't.
November 12, 2010 at 3:50 pm
Just to reiterate what the others have said: 99% of all loops in SQL can be avoided with proper set-based programming. If you're willing to learn, we're willing to help you learn better ways to do things. Remember - SQL is a set-based programming language, not a loop-based one (that processes things Row-By-Agonizing-Row).
People here have seen loop-based code that runs in hours reduced to simple set-based code that runs in seconds.
Interested?
Wayne
Microsoft Certified Master: SQL Server 2008
Author - SQL Server T-SQL Recipes
November 12, 2010 at 11:02 pm
sqldba_icon (11/12/2010)
Just wanted to throw out a question to developers on what method do they use to loop around different objects.I typically use cursors, was wondering if there is a better way or any new concept in 2008 where i can avoid cursors. Thanks
I assume you mean possibly looping around to get to different databases or tables for common maintenance solutions. If that's true, then there is no need to avoid cursors. A While Loop will still be necessary if you use a Temp Table and you're not using it for RBAR. Use a nice, tight, Forward Only, Read Only, Static cursor. Yes, there are ways to avoid cursors for such things using concatenation of commands but the cursor won't be the resource hog or performance problem that a RBAR cursor would be.
--Jeff Moden
Change is inevitable... Change for the better is not.
November 13, 2010 at 7:07 pm
sure. where can i find the details?
November 14, 2010 at 5:44 pm
sqldba_icon (11/13/2010)
sure. where can i find the details?
Google? Books Online? I'm not trying to be a smart guy here... that's where I'd look.
--Jeff Moden
Change is inevitable... Change for the better is not.
November 15, 2010 at 6:19 am
Jeff Moden (11/12/2010)
sqldba_icon (11/12/2010)
Just wanted to throw out a question to developers on what method do they use to loop around different objects.I typically use cursors, was wondering if there is a better way or any new concept in 2008 where i can avoid cursors. ThanksI assume you mean possibly looping around to get to different databases or tables for common maintenance solutions. If that's true, then there is no need to avoid cursors. A While Loop will still be necessary if you use a Temp Table and you're not using it for RBAR. Use a nice, tight, Forward Only, Read Only, Static cursor. Yes, there are ways to avoid cursors for such things using concatenation of commands but the cursor won't be the resource hog or performance problem that a RBAR cursor would be.
Jeff: "Fast_Forward" does all the "forward only", "read only", "static" options all in one. Per MSDN/BOL, it also includes some performance optimizations. (You probably already know this, but I wasn't sure.)
- Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
Property of The Thread
"Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon
November 15, 2010 at 3:20 pm
Jeff Moden (11/14/2010)
sqldba_icon (11/13/2010)
sure. where can i find the details?Google? Books Online? I'm not trying to be a smart guy here... that's where I'd look.
Not trying to be the smart guy here either, but I think Jeff's being rather modest. Try looking up some of his articles (or Gail 'Gila Monster' Shaw's). I'd suggest their posts as well - but as there are some 10 billion of them (approx) I'd sort out a granular search based on your requirements and see what pops up. If you had time to read them all - you'd be well sorted - but also close to retirement <g>
I'm a DBA.
I'm not paid to solve problems. I'm paid to prevent them.
November 15, 2010 at 4:15 pm
sqldba_icon (11/13/2010)
sure. where can i find the details?
I would suggest starting off by reading this article[/url] by MVP Jeff Moden.
I would also suggest the two "15 Ways to Lose Your Cursor" articles here[/url].
I would then search for "cursor" and "loop" in the forums on this site, and see how people have been helped to get rid of their cursors/loops and replace them with set-based solutions.
If you run into problems, post back. But first, please read the first article in my signature, and post the requested data, and the code you're trying to change. You'll get several people jumping in to help you learn.
Wayne
Microsoft Certified Master: SQL Server 2008
Author - SQL Server T-SQL Recipes
November 17, 2010 at 6:07 pm
GSquared (11/15/2010)
Jeff: "Fast_Forward" does all the "forward only", "read only", "static" options all in one. Per MSDN/BOL, it also includes some performance optimizations. (You probably already know this, but I wasn't sure.)
I haven't tested in quite a while (I only use cursors to show how slow they are) but it used to be that listing the options separately produced faster code. That was way back in SQL Server 7. I believe it was Kevin Boles that showed me that but I'm not 100% sure. Guess I need to write another test.
--Jeff Moden
Change is inevitable... Change for the better is not.
November 18, 2010 at 2:01 am
I have used a table to hold the loop counter. Running the whole statement was too much for the memory available so it was broken down into processing by year (created about 6 chunks). The relevant years put in a table, top 1 processed then removed from the year counter table - looped until the counter table was empty.
I'm not saying this is pretty or clever but it is another way to do it and I knew less. Today I would use a cursor.
BTW - this was no way a rbar, just cut it down to a few million rows a go.
November 18, 2010 at 9:19 am
GSquared (11/15/2010)
Jeff Moden (11/12/2010)
sqldba_icon (11/12/2010)
Just wanted to throw out a question to developers on what method do they use to loop around different objects.I typically use cursors, was wondering if there is a better way or any new concept in 2008 where i can avoid cursors. ThanksI assume you mean possibly looping around to get to different databases or tables for common maintenance solutions. If that's true, then there is no need to avoid cursors. A While Loop will still be necessary if you use a Temp Table and you're not using it for RBAR. Use a nice, tight, Forward Only, Read Only, Static cursor. Yes, there are ways to avoid cursors for such things using concatenation of commands but the cursor won't be the resource hog or performance problem that a RBAR cursor would be.
Jeff: "Fast_Forward" does all the "forward only", "read only", "static" options all in one. Per MSDN/BOL, it also includes some performance optimizations. (You probably already know this, but I wasn't sure.)
Not quite -- STATIC isn't included. Per BOL....
FAST_FORWARD
Specifies a FORWARD_ONLY, READ_ONLY cursor with performance optimizations enabled. FAST_FORWARD cannot be specified if SCROLL or FOR_UPDATE is also specified.
Hugo Kornelis wrote a marvelous article comparing the performance of a number of different cursor options and discovered that conventional wisdom about this is often wrong. Noteworthy was his finding:
Based on all tests, it turns out that the best performance is achieved by specifying a STATIC cursor. I would add the LOCAL, FORWARD_ONLY, and READ_ONLY options for documentation purposes, but they make no performance difference.
and
If you think that the FAST_FORWARD option results in the fastest possible performance, think again. I have not found one single test case where it was faster than, or even as fast as, a STATIC cursor.
And yes, his first conclusion was "Always try to replace the cursor by a set-based equivalent first."
Rich
November 18, 2010 at 9:48 am
I just did a simple speed test on a do-nothing cursor.
DECLARE c CURSOR STATIC FOR
SELECT NAME
FROM sys.columns;
DECLARE @DB sysname;
OPEN c;
FETCH NEXT FROM c
INTO @DB;
DECLARE @Start DATETIME;
SET @Start = GETDATE();
WHILE @@FETCH_STATUS = 0
FETCH NEXT FROM c
INTO @DB;
SELECT DATEDIFF(millisecond, @Start, GETDATE());
CLOSE c;
DEALLOCATE c;
It's not a full test, but I ran default, static, and fast-forward, 10 times each. Default (no options) took between 13 and 16 milliseconds for each run. Static took 3 to 10, with 6 being the most common. Fast-forward took between 3 and 10, with 3 being the most common. Real tests would be more complex and on much more data.
As per Hugo's blog entry:
Disclaimer: All results presented here are only valid for my test cases (as presented below) on my test data (a copy of the SalesOrderDetail table in the AdventureWorks sample database), on my machine (a desktop with 2GB of memory, a dual-core processor, running SQL Server 2005 SP2), and with my workload (just myself, and only the test scripts were active). If your situation is different, for instance if the table will not fit in cache, if the database is heavily accessed by competing processes, or if virtually any other variable changes, you really ought to perform your own test if you want to squeeze everything out of your cursor. And also consider that many options are included to achieve other goals than performance, so you may not be able to use all options without breaking something.
I ran different test data on a different machine, and got different results.
In my general speed testing, I've found fast-forward to be as fast or faster than other options more often that not. That's not universal, but nothing is.
- Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
Property of The Thread
"Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon
November 26, 2010 at 12:16 am
HI,
Avoid Cursor , Using While loop
Just go through it
----- Solution ----- 1
If Identity Column Does not exist in the table
DECLARE @iIndex INT ,@RowsCount int
SELECT Identity(INT,1,1) AS Sr_No, FieldName1, FieldName2, FieldName3,…………… FieldNameN
INTO #Temp_Table
FROM Table_Name
---- WHERE
ORDER BY FieldNameX
SELECT @iIndex = 1
SELECT @RowsCount = @@RowCount
or
SELECT @RowsCount = Count(Sr_No) FROM #Temp_Table
WHILE @iIndex <= @RowsCount
BEGIN --- 2
if EXISTS(SELECT Sr_No FROM #Temp_Table WHERE Sr_No = @iIndex)
BEGIN
SELECT @FieldName1 = FieldName1,@FieldName2 = FieldName2,@FieldName3= FieldName3, @FieldName4= FieldName4 …….N
FROM #Temp_Table WHERE Sr_No = @iIndex
--- Perform your Task
END
SELECT @iIndex = @iIndex + 1
END --- 2
DROP TABLE #Temp_Table
----- Solution ----- 2
If Identity Column exist in the table
DECLARE @FieldName1 DataType, @FieldName2 DataType ……….. @FieldNameN DataType
DECLARE @iIndex INT ,@RowsCount int
SELECT IdentityColumn_Name ,FieldName2 ,FieldName3 ,FieldName4 ,FieldName4 ……….,FieldNameN
INTO #Temp_Table
FROM Table_Name
---- WHERE
ORDER BY FieldNameX
SELECT TOP 1 @RowsCount = IdentityColumn_Name FROM #Temp_Table ORDER BY IdentityColumn_Name DESC
SELECT TOP 1 @iIndex = IdentityColumn_Name FROM #Temp_Table ORDER BY IdentityColumn_Name
WHILE @iIndex <= @RowsCount
BEGIN
if EXISTS(SELECT IdentityColumn_Name FROM #Temp_Table WHERE IdentityColumn_Name = @iIndex)
BEGIN
SELECT @FieldName1 = FieldName1,@FieldName2 = FieldName2,@FieldName3= FieldName3, @FieldName4= FieldName4 …….N
FROM #Temp_Table WHERE IdentityColumn_Name = @iIndex
--- Perform your Task
END
SELECT @iIndex = @iIndex + 1
END
DROP TABLE #Temp_Table
Patel Mohamad
Viewing 15 posts - 1 through 15 (of 15 total)
You must be logged in to reply to this topic. Login to reply