<p>It is generally accepted that the use of cursors in stored procedures should be avoided where possible (replaced with set based logic etc). If you take the cases where you need to iterate over some data, and can do in a read only manner, are fast forward (read only forward) cursor more or less inefficient than say while loops? From my investigations it looks as though the cursor option is generally faster and uses less reads and cpu time.  I haven't done any extensive testing, but is this what others find?  Do cursors of this type (fast forward) carry additional overhead or resource that could be expensive that I don't know about.</p>
<p>Is all the talk about not using cursors really about avoiding the use of cursors when set-based approaches are available, and the use of updatable cursors etc.</p>

[{'answer_id': 37176, 'author': 'GateKiller', 'author_id': 383, 'author_profile': 'https://Stackoverflow.com/users/383', 'pm_score': 1, 'selected': False, 'text': '<p>People avoid cursor because they generally are more difficult to write than a simple while loops, however, a while loop can be expensive because your constantly selecting data from a table, temporary or otherwise.</p>\n\n<p>With a cursor, which is readonly fast forward, the data is kept in memory and has been specifically designed for looping.</p>\n\n<p><a href="http://www.sqlteam.com/article/cursor-performance" rel="nofollow noreferrer">This article</a> highlights that an average cursor runs 50 times faster than a while loop.</p>\n'}, {'answer_id': 38434, 'author': 'Simon Munro', 'author_id': 3893, 'author_profile': 'https://Stackoverflow.com/users/3893', 'pm_score': -1, 'selected': True, 'text': "<p>The 'Best Practice' of avoiding cursors in SQL Server dates back to SQL Server 2000 and earlier versions.  The rewrite of the engine in SQL 2005 addressed most of the issues related to the problems of cursors, particularly with the introduction of the fast forward option.  Cursors are not neccessarily worse than set-based and are used extensively and successfully in Oracle PL/SQL (LOOP).</p>\n\n<p>The 'generally accepted' that you refer to <strong>was</strong> valid, but is now outdated and incorrect - go on the assumption that fast forward cursors behave as advertised and perform.  Do some tests and research, basing your findings on SQL2005 and later</p>\n"}, {'answer_id': 38454, 'author': 'Eric Z Beard', 'author_id': 1219, 'author_profile': 'https://Stackoverflow.com/users/1219', 'pm_score': 4, 'selected': False, 'text': '<p>While a fast forward cursor does have some optimizations in Sql Server 2005, it is <em>not</em> true that they are anywhere close to a set based query in terms of performance.  There are very few situations where cursor logic cannot be replaced by a set-based query.  Cursors will always be inherently slower, due in part to the fact that you have to keep interrupting the execution in order to fill your local variables.</p>\n\n<p>Here are few references, which would only be the tip of the iceberg if you research this issue: </p>\n\n<p><a href="http://www.code-magazine.com/Article.aspx?quickid=060113" rel="nofollow noreferrer">http://www.code-magazine.com/Article.aspx?quickid=060113</a></p>\n\n<p><a href="http://dataeducation.com/re-inventing-the-recursive-cte/" rel="nofollow noreferrer">http://dataeducation.com/re-inventing-the-recursive-cte/</a></p>\n'}, {'answer_id': 91107, 'author': 'Piotr Anders', 'author_id': 11377, 'author_profile': 'https://Stackoverflow.com/users/11377', 'pm_score': -1, 'selected': False, 'text': '<p>If You want a even faster cursor than FAST FORWARD then use a STATIC cursor. They are faster than FAST FORWARD. Not extremely faster but can make a difference. </p>\n'}, {'answer_id': 461370, 'author': 'Miles D', 'author_id': 3898, 'author_profile': 'https://Stackoverflow.com/users/3898', 'pm_score': 2, 'selected': False, 'text': '<p>This answer hopes to consolidate the replies given to date.</p>\n\n<p>1) If at all possible, used set based logic for your queries i.e. try and use just <code>SELECT</code>, <code>INSERT</code>, <code>UPDATE</code> or <code>DELETE</code> with the appropriate <code>FROM</code> clauses or nested queries - these will almost always be faster.</p>\n\n<p>2) If the above is not possible, then in SQL Server 2005+ <code>FAST FORWARD</code> cursors are efficient and perform well and should be used in preference to while loops.</p>\n'}, {'answer_id': 3239555, 'author': 'StartupGuy', 'author_id': 390722, 'author_profile': 'https://Stackoverflow.com/users/390722', 'pm_score': 2, 'selected': False, 'text': '<p>"If You want a even faster cursor than FAST FORWARD then use a STATIC cursor. They are faster than FAST FORWARD. Not extremely faster but can make a difference."</p>\n\n<p>Not so fast! According to Microsoft:\n"Typically, when these conversions occurred, the cursor type degraded to a ‘more expensive’ cursor type. Generally, a (FAST) FORWARD-ONLY cursor is the most performant, followed by DYNAMIC, KEYSET, and finally STATIC which is generally the least performant."</p>\n\n<p>from: <a href="http://blogs.msdn.com/b/mssqlisv/archive/2006/06/23/644493.aspx" rel="nofollow noreferrer">http://blogs.msdn.com/b/mssqlisv/archive/2006/06/23/644493.aspx</a></p>\n'}, {'answer_id': 14095487, 'author': 'Jeff Moden', 'author_id': 313265, 'author_profile': 'https://Stackoverflow.com/users/313265', 'pm_score': 1, 'selected': False, 'text': '<p>To answer Mile\'s original questions...</p>\n\n<p>Fast Forward, Read Only, Static cursors (affectionately known as a "Fire Hose Cursor") are typically as fast or faster than a equivalent Temp Table and a While loop because such a cursor is nothing more than a Temp Table and a While loop that has been optimized a bit behind the scenes.</p>\n\n<p>To add to what Eric Z. Beard posted on this thread and to further answer the question of...</p>\n\n<blockquote>\n  <p>"Is all the talk about not using cursors really about avoiding the use\n  of cursors when set-based approaches are available, and the use of\n  updatable cursors etc."</p>\n</blockquote>\n\n<p>Yes.  With very few exceptions, it takes less time and less code to write proper set-based code to do the same thing as most cursors and has the added benefit of using much fewer resources and usually runs MUCH faster than a cursor or While loop.  Generally speaking and with the exception of certain administrative tasks, they really should be avoided in favor of properly written set-based code.  There are, of course, exceptions to every "rule" but, in the case of Cursors, While loops, and other forms of RBAR, most people can count the exceptions on one hand without using all of the fingers. ;-)</p>\n\n<p>There\'s also the notion of "Hidden RBAR".  This is code that looks set-based but actually isn\'t.  This type of "set-based" code is the reason why certain people have embraced RBAR methods and say they\'re "OK".  For example, solving the running total problem using an aggregated (SUM) correlated sub-query with an inequality in it to build the running total isn\'t really set-based in my book.  Instead, it\'s RBAR on steroids because ,for each row calculated, it has to repeatedly "touch" many other rows at a rate of N*(N+1)/2.  That\'s known as a "Triangular Join" and is at least half as bad as a full Cartesian Join (Cross Join or "Square Join").</p>\n\n<p>Although MS has made some improvements in how Cursors work since SQL Server 2005, the term "Fast Cursor" is still an oxymoron compared to properly written set-based code.  That also holds true even in Oracle.  I worked with Oracle for a short 3 years in the past but my job was to make performance improvements in existing code.  Most of the really substantial improvements were realized when I converted Cursors to set-based code.  Many jobs that previously took 4 to 8 hours to execute were reduced to minutes and, sometimes, seconds.</p>\n'}, {'answer_id': 27359172, 'author': 'Fabiano Novaes Ferreira', 'author_id': 4337447, 'author_profile': 'https://Stackoverflow.com/users/4337447', 'pm_score': 2, 'selected': False, 'text': "<p>You can avoid cursors most of the time, but sometimes it's necessary.</p>\n\n<p>Just keep in mind that FAST_FORWARD is DYNAMIC ... FORWARD_ONLY you can use with a STATIC cursor. </p>\n\n<p>Try using it on the Halloween problem to see what happens !!!</p>\n\n<pre><code>IF OBJECT_ID('Funcionarios') IS NOT NULL\nDROP TABLE Funcionarios\nGO\n\nCREATE TABLE Funcionarios(ID          Int IDENTITY(1,1) PRIMARY KEY,\n                          ContactName Char(7000),\n                          Salario     Numeric(18,2));\nGO\n\nINSERT INTO Funcionarios(ContactName, Salario) VALUES('Fabiano', 1900)\nINSERT INTO Funcionarios(ContactName, Salario) VALUES('Luciano',2050)\nINSERT INTO Funcionarios(ContactName, Salario) VALUES('Gilberto', 2070)\nINSERT INTO Funcionarios(ContactName, Salario) VALUES('Ivan', 2090)\nGO\n\nCREATE NONCLUSTERED INDEX ix_Salario ON Funcionarios(Salario)\nGO\n\n-- Halloween problem, will update all rows until then reach 3000 !!!\nUPDATE Funcionarios SET Salario = Salario * 1.1\n  FROM Funcionarios WITH(index=ix_Salario)\n WHERE Salario &lt; 3000\nGO\n\n-- Simulate here with all different CURSOR declarations\n-- DYNAMIC update the rows until all of then reach 3000\n-- FAST_FORWARD update the rows until all of then reach 3000\n-- STATIC update the rows only one time. \n\nBEGIN TRAN\nDECLARE @ID INT\nDECLARE TMP_Cursor CURSOR DYNAMIC \n--DECLARE TMP_Cursor CURSOR FAST_FORWARD\n--DECLARE TMP_Cursor CURSOR STATIC READ_ONLY FORWARD_ONLY\n    FOR SELECT ID \n          FROM Funcionarios WITH(index=ix_Salario)\n         WHERE Salario &lt; 3000\n\nOPEN TMP_Cursor\n\nFETCH NEXT FROM TMP_Cursor INTO @ID\n\nWHILE @@FETCH_STATUS = 0\nBEGIN\n  SELECT * FROM Funcionarios WITH(index=ix_Salario)\n\n  UPDATE Funcionarios SET Salario = Salario * 1.1 \n   WHERE ID = @ID\n\n  FETCH NEXT FROM TMP_Cursor INTO @ID\nEND\n\nCLOSE TMP_Cursor\nDEALLOCATE TMP_Cursor\n\nSELECT * FROM Funcionarios\n\nROLLBACK TRAN\nGO\n</code></pre>\n"}, {'answer_id': 51301397, 'author': 'Burak Kartal', 'author_id': 4490167, 'author_profile': 'https://Stackoverflow.com/users/4490167', 'pm_score': 2, 'selected': False, 'text': '<p><strong>Some alternatives to using cursor:</strong></p>\n\n<p>WHILE loops\nTemp tablolar\nDerived tables\nAssociated subqueries\nCASE statements\nMultiple interrogations\nOften, cursor operations can also be achieved with non-cursor techniques.</p>\n\n<p>If you are sure that the cursor needs to be used, the number of records to be processed should be reduced as much as possible. One way of doing this is to get the records to be processed first into a temp table, not the original table, but a cursor that will use the records in the temp table. When this path is used, it is assumed that the number of records in the temp table has been greatly reduced compared to the original table. With fewer records, the cursor completes faster.</p>\n\n<p>Some cursor properties that affect performance include:</p>\n\n<p>FORWARD_ONLY: Supports forwarding only the cursor from the first row to the end with FETCH NEXT. Unless set as KEYSET or STATIC, the SELECT clause is re-evaluated when each fetch is called.</p>\n\n<p>STATIC: Creates a temp copy of the created data and is used by the cursor. This prevents the cursor from being recalculated each time it is called, which improves performance. This does not allow cursor type modification, and changes to the table are not reflected when the fetch is called.</p>\n\n<p>KEYSET: Cursored rows are placed in a table under tempdb, and changes to nonkey columns are reflected when the fetch is called. However, new records added to the table are not reflected. With the keyset cursor, the SELECT statement is not evaluated again.</p>\n\n<p>DYNAMIC: All changes to the table are reflected in the cursore. The cursor is re-evaluated when each fetch is called. It uses a lot of resources and adversely affects performance.</p>\n\n<p>FAST_FORWARD: The cursor is one-way, such as FORWARD_ONLY, but specifies the cursor as read-only. FORWARD_ONLY is a performance increase and the cursor is not reevaluated every fetch. It gives the best performance if it is suitable for programming.</p>\n\n<p>OPTIMISTIC: This option can be used to update rows in the cursor. If a row is fetched and updated, and another row is updated between fetch and update operations, the cursor update operation fails. If an OPTIMISTIC cursor is used that can perform line update, it should not be updated by another process.</p>\n\n<p>NOTE: If cursore is not specified, the default is FORWARD_ONLY.</p>\n'}]
['https://Stackoverflow.com/questions/37029', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/3898/']