Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2005 Forums
 Transact-SQL (2005)
 using cursors in general, discussion.

Author  Topic 

sapator
Constraint Violating Yak Guru

462 Posts

Posted - 2011-02-04 : 18:39:56
I went to a company for an interview and to my surprise they were still using cursors in sql server.
Now i'm not the best sql programmer around and i think i have skipped the cursors part(due to younger age) but i think some of you guys can give some info on this one.
Are cursors needed nowadays and what is a job that only a cursor can do(as i was told when i asked why they use them(they didn't elaborate).
Thanks.

dataguru1971
Master Smack Fu Yak Hacker

1464 Posts

Posted - 2011-02-04 : 19:21:29
Cursors are for people who don't know who how to think "Set based". In some cases, they may be required, but in general..they should be avoided. More often than not, a set based solution can be achieved. People have a habit to think about what they want to do to a ROW of data instead of what they want to do to a set of data.

I am sure there are instances where a cursor IS required...just can't think of any off hand that a set based solution wasn't far better. most people just assume that "if I want to do something to each of these rows, I need to do it one row at a time"..when that often isn't the case.

Set based > While Loop> Cursor. Cursor is the last choice, at least for me. At work, a coworker was working on a complex string parsing cursor that was around 300 lines long. I showed him a 5 column select statement that did the same thing...sometimes people just don't think it can be done without a cursor.

Part if it, I think, comes from other languages or methods that are "row by row" type operations. Some ADO recordset operations in VB come to main. Mainframe SAS programs come to mind...I find it a distinct mindset difference about how one approaches the data. If you think in Set based ..you generally don't even consider a cursor.

Are the needed? maybe, but they are surely not needed everywhere they are currently used.





Poor planning on your part does not constitute an emergency on my part.
Go to Top of Page

sapator
Constraint Violating Yak Guru

462 Posts

Posted - 2011-02-04 : 19:52:39
I have the same thoughts as you do but i'm not a sql guru so i'm just reading what expert people write.
I told them (when they said they use cursors) that this is an old and bad habit and they told me that even "select" is a cursor itself.So i thought that either i'm not well educated or that they are idiots. :)
Go to Top of Page

dataguru1971
Master Smack Fu Yak Hacker

1464 Posts

Posted - 2011-02-04 : 19:57:49
Well, you likely made a mistake criticizing their practice of using them by saying it was an old and bad habit. A better approach is to say that "in many cases, there may be opportunities to leverage set based solutions, which could yield performance benefits over cursors". Key point..not criticizing them.

A SELECT could be seen as a cursor, if one doesn't think Set-Based. There are way more people here, actually qualified as an expert, so hopefully they weigh in.

here is an interesting thread on the topic http://stackoverflow.com/questions/24168/why-are-relational-set-based-queries-better-than-cursors

I am sure the experts here have written many as well.



Poor planning on your part does not constitute an emergency on my part.
Go to Top of Page

ZZartin
Starting Member

30 Posts

Posted - 2011-02-04 : 20:03:48
The uses I've found for cursors are times where I do in fact want to parse a set of data row by row, for example some of the results in your cursor will have an impact on other rows in the same cursor. Sometimes it just makes more sense in a case like that to use a cursor instead of trying to come up with a complex update/insert command involving a lot of sub-queries. There might always be cases where performance wise it makes more sense to parse a lot of small queries instead of trying to come up with a one big command that could potentially lock your tables up.

For example one cursor i use parses a temp table and runs various lookups/calculations to insert them into another table. In theory it could be done with a single insert statement but it would be much much harder to read/modify at a later date.
Go to Top of Page

sapator
Constraint Violating Yak Guru

462 Posts

Posted - 2011-02-04 : 20:13:26
Thanks again guys.
Also i market the article down for read tomorrow cuz i have to duplicate some tables right now.
Also dataguru1971 you are right about my behavior i've been to many interview but it was 8 in the morning and i was having a lecture in how cursors do everything nicely.So i cracked :P
Bottom line, i have a second interview with them on Monday so i guess it didn't matter to their ego what i said :)
Either that or the fact that i worked for a doze insurance companies here (they are one).
Go to Top of Page

dataguru1971
Master Smack Fu Yak Hacker

1464 Posts

Posted - 2011-02-04 : 20:15:56
Well, good luck. Focus on what you can help them improve, not what they do wrong.



Poor planning on your part does not constitute an emergency on my part.
Go to Top of Page

dataguru1971
Master Smack Fu Yak Hacker

1464 Posts

Posted - 2011-02-04 : 20:19:56
quote:
Originally posted by ZZartin



For example one cursor i use parses a temp table and runs various lookups/calculations to insert them into another table. In theory it could be done with a single insert statement but it would be much much harder to read/modify at a later date.


Ease of readability is subjective though. I can sort out a set based procedure a lot faster than a cursor. I bet a CTE and a set based solution would be pretty easy to follow..

Keeping in mind of course, that even set based solutions can manifest with hidden RBAR (term courtesy of Jeff Moden). I have seen that mistake too, which can often result in people thinking a cursor works "better" when it was only the RBAR that made the set based solution seem ineffective.



Poor planning on your part does not constitute an emergency on my part.
Go to Top of Page

russell
Pyro-ma-ni-yak

5072 Posts

Posted - 2011-02-05 : 08:58:49
A recordset is sometimes referred to as a cursor -- though not when we're talking about SQL Server. This is probably why they told you a select is a cursor.

quote:
Cursors are for people who don't know who how to think "Set based".
I hate when people say things like this. Or "SSIS is useful if you don't know SQL."

A place and time for everything (except cascading keys ).

Suppose I asked you for a list of every user table in every database along with the number of rows, reserved KB, data KB and index size. How will you do that without a cursor?

Go to Top of Page

robvolk
Most Valuable Yak

15732 Posts

Posted - 2011-02-05 : 10:08:42
I still stand by my "put sugar in coffee using a spoon or tweezers" analogy regarding cursors. More babble about it here:

http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=47319
http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=72457
http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=118835 id="quote">quote:
In theory it could be done with a single insert statement but it would be much much harder to read/modify at a later date.
I have found the opposite to be true. I can NEVER figure out what's being done in a cursor procedure, especially if it can be done with a single SQL statement. My reply in the first link above has an example of that. I've also found cursor code to be more verbose.

I understand why people hesitate to learn set-based thinking, especially when they've started with iterative/procedural programming. I've been there, I've melted my brain on it, I hated it at first too. But once I got it, it's made all of my programming skills better, even non-SQL code. While it's a good practice to break larger problems into smaller pieces, SQL Server cursors are not the right way to do that. All they add is navigational overhead that gets in the way of solving the problem.
quote:
Sometimes it just makes more sense in a case like that to use a cursor instead of trying to come up with a complex update/insert command involving a lot of sub-queries.
Unfortunately that way of thinking is too pervasive, and unless you deliberately break away from it, you'll forever struggle to use SQL effectively. Take the extra time to do it in a set-based way, even if you're under pressure to get it done quickly. And I'll think you'll find the set-based method is easier and less complicated to code, once you get your mind thinking that way.

Go to Top of Page

dataguru1971
Master Smack Fu Yak Hacker

1464 Posts

Posted - 2011-02-05 : 10:24:23
Taking a general opinion out of context I see. I never meant to imply that they never needed to be used, only that many times they are used--there are set based options available which are better. My opinion is based on personal experience where everyone thinks "row by row" instead of set based. It was just a general comment is all..:)

Obviously there are places where cursors are useful. However, I dug this out of my stuff when I was messing around with CTE's. It appears to produce correct data at a glance, but never really picked it up again. Not a cursor though..again, not perfect, was just messing around a while back with 2005 when I was trying to figure out uses for CTE's and trying to learn. Obviously, can't do every database without a cursor or sp_MSFOREACHDB in your question.



;WITH
usertables as (
SELECT id
from sysobjects
where xtype = 'U'
)

,reserved as
( SELECT id,SUM(reserved)-SUM(isnull(used,0)) as unused,Resv=SUM(reserved)
FROM sysindexes
Where indid in (0,1,255)
Group by id
)
,data as
(SELECT id,SUM(case when indid <2 then dpages else 0 end) as pages,
SUM(Case When indid = 255 then isNull(used,0) else 0 end) as usedpages
FROM sysindexes
Where indid <2
Group by id
)
,indexes as
(select id,sum(used)as iused
from sysindexes
where indid in (0, 1, 255)
group by id
)
,row as
( Select id,rows
from sysindexes
where indid < 2 )

, spaceused as
(Select object_name(u.id) as tablename
,data=pages-usedpages
,reserved = resv
,iused = iused-pages-usedpages
,rows
,unused
FROM usertables u,reserved s,data d, indexes i,row r
WHERE u.id = d.id
and u.id = s.id
and u.id = i.id
and u.id = r.id
and i.id = s.id
and r.id = s.id
and r.id = u.id
)
SELECT tablename
,reserved = ltrim(str(reserved * d.low / 1024.,15,0) + ' ' + 'KB')
,dataKB = ltrim(str(data * d.low / 1024.,15,0) + ' ' + 'KB')
,indexKB = ltrim(str(iused * d.low / 1024.,15,0) + ' ' + 'KB')
,unusedKB = ltrim(str(unused * d.low / 1024.,15,0) + ' ' + 'KB')
FROM spaceused,master.dbo.spt_values d
where d.number = 1 and d.type = 'E'
order by data * d.low / 1024 desc








Poor planning on your part does not constitute an emergency on my part.
Go to Top of Page

dataguru1971
Master Smack Fu Yak Hacker

1464 Posts

Posted - 2011-02-05 : 10:34:20
quote:
Originally posted by robvolk

I still stand by my "put sugar in coffee using a spoon or tweezers" analogy regarding cursors. More babble about it here:

http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=47319
http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=72457
http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=118835 id="quote">quote:
In theory it could be done with a single insert statement but it would be much much harder to read/modify at a later date.
I have found the opposite to be true. I can NEVER figure out what's being done in a cursor procedure, especially if it can be done with a single SQL statement. My reply in the first link above has an example of that. I've also found cursor code to be more verbose.

I understand why people hesitate to learn set-based thinking, especially when they've started with iterative/procedural programming. I've been there, I've melted my brain on it, I hated it at first too. But once I got it, it's made all of my programming skills better, even non-SQL code. While it's a good practice to break larger problems into smaller pieces, SQL Server cursors are not the right way to do that. All they add is navigational overhead that gets in the way of solving the problem.
quote:
Sometimes it just makes more sense in a case like that to use a cursor instead of trying to come up with a complex update/insert command involving a lot of sub-queries.
Unfortunately that way of thinking is too pervasive, and unless you deliberately break away from it, you'll forever struggle to use SQL effectively. Take the extra time to do it in a set-based way, even if you're under pressure to get it done quickly. And I'll think you'll find the set-based method is easier and less complicated to code, once you get your mind thinking that way.





Yeah, what he said. I LOL'd at brick wall example...that is a good one!



Poor planning on your part does not constitute an emergency on my part.
Go to Top of Page

russell
Pyro-ma-ni-yak

5072 Posts

Posted - 2011-02-05 : 11:38:27
I agree that the need is rare. Sorry if I took your remark out of context.

By the way, sp_msforeachdb uses a cursor.
Go to Top of Page

dataguru1971
Master Smack Fu Yak Hacker

1464 Posts

Posted - 2011-02-05 : 16:03:44
quote:
Originally posted by russell

I agree that the need is rare. Sorry if I took your remark out of context.

By the way, sp_msforeachdb uses a cursor.



LOL. No doubt, but at least I don't have to write it.



Poor planning on your part does not constitute an emergency on my part.
Go to Top of Page

russell
Pyro-ma-ni-yak

5072 Posts

Posted - 2011-02-05 : 17:55:02
LOL good point.

Once again, sorry. Didn't mean to be a, well you know what, lol.

Nice work on the query above. I restore a whole bunch of production databases nightly to a sandbox server. Serves two purposes: (1) to make sure the backups are good and (2) so the business analysts can play with some real data. As an added bonus, it gives me the ability to monitor growth simply by iterating through every database and capturing the size of the objects. I used sp_spaceused to do it.

Compared the results of mine to yours, and they return the same results. Yours might be more efficient (though I would tweak it slightly). Because I want every db, and every table in one shot, I'm forced to use a cursor, a temp table and dynamic SQL. Granted, it runs super fast (and on high end hardware) but it is NOT the picture of beautiful, optimized code!
Go to Top of Page

dataguru1971
Master Smack Fu Yak Hacker

1464 Posts

Posted - 2011-02-05 : 18:31:00
Thanks!..it was really something from maybe 18 months ago or even longer when I was looking at procs I found with cursors and tried finding other ways. One of the procs was that sp_spaceusedbytable and it seemed an easy one to play with. I never really went back and cleaned it up...looking at it today, and what I have learned since..I could make it better. I never compared execution plans or anything on it, but I would think it "might" be more efficient but I never put in practice.

Might be useful as a view or table valued function in each db though with some tweaks though..then you could just select the records from the view into your temp table (or table variable?)

I didn't take offense. If you do tweak it and use it, let me know ...you can steal it if you like.Just happened to have that handy when you posed the question (aside from the "every database" part..)

edit: results do match, but a quick re-scan shows that one of the CTE's has a where clause that doesn't jive with the select..


,data as
(SELECT id,SUM(case when indid <2 then dpages else 0 end) as pages,
SUM(Case When indid = 255 then isNull(used,0) else 0 end) as usedpages
FROM sysindexes
Where indid <2 or indid = 255 ---missed this.
Group by id
)





Poor planning on your part does not constitute an emergency on my part.
Go to Top of Page

sapator
Constraint Violating Yak Guru

462 Posts

Posted - 2011-02-05 : 18:49:27
Useful info guys.Thanks.
All post something for the "go" statement in a new thread if you don't mind.
Go to Top of Page
   

- Advertisement -