simple recorrer fetch_status ejemplos ejemplo datos cursores anidados sql cursor

recorrer - ¿Por qué la gente odia tanto los cursores SQL?



select cursor sql server (14)

¿Puedes publicar ese ejemplo de cursor o un enlace a la pregunta? Probablemente haya una forma aún mejor que un CTE recursivo.

Además de otros comentarios, los cursores cuando se usan de forma incorrecta (lo que a menudo es) causan bloqueos innecesarios de página / fila.

Puedo entender el deseo de evitar tener que usar un cursor debido a la sobrecarga y la inconveniencia, pero parece que hay un serio cursor-fobia-manía sucediendo donde la gente hace todo lo posible para evitar tener que usar uno.

Por ejemplo, una pregunta preguntó cómo hacer algo obviamente trivial con un cursor y la respuesta aceptada propuesta usando una consulta recursiva de expresión de tabla común (CTE) con una función personalizada recursiva, aunque esto limita el número de filas que podrían procesarse a 32 (debido al límite de llamada de función recursiva en el servidor sql). Esto me parece una solución terrible para la longevidad del sistema, sin mencionar un gran esfuerzo solo para evitar el uso de un simple cursor.

¿Cuál es la razón de este nivel de odio insano? ¿Alguna ''autoridad notoria'' emitió una fatwa contra los cursores? ¿Hay algún mal indescriptible escondido en el corazón de los cursores que corrompe la moral de los niños o algo así?

Pregunta Wiki, más interesado en la respuesta que el representante.

Información relacionada:

Cursores rápidos de SQL Server

EDITAR: permítanme ser más preciso: entiendo que los cursores no deberían usarse en lugar de las operaciones relacionales normales ; eso es obvio. Lo que no entiendo es que la gente va a hacer todo lo posible para evitar los cursores, como si tuvieran piojos o algo así, incluso cuando un cursor es una solución más simple y / o más eficiente. Es el odio irracional lo que me desconcierta, no las obvias eficiencias técnicas.


Aparte de los problemas de rendimiento (no), creo que la mayor falla de los cursores es que son difíciles de depurar. Especialmente en comparación con el código en la mayoría de las aplicaciones cliente donde la depuración tiende a ser comparativamente fácil y las características del lenguaje tienden a ser mucho más fáciles. De hecho, sostengo que casi todo lo que uno hace en SQL con un cursor probablemente debería estar sucediendo en la aplicación cliente en primer lugar.


El optimizador a menudo no puede usar el álgebra relacional para transformar el problema cuando se utiliza un método de cursor. A menudo, un cursor es una excelente manera de resolver un problema, pero SQL es un lenguaje declarativo, y hay mucha información en la base de datos, desde restricciones hasta estadísticas e índices, lo que significa que el optimizador tiene muchas opciones para resolver el problema. problema, mientras que un cursor dirige más explícitamente la solución.


En Oracle, los cursores PL / SQL no darán como resultado bloqueos de tabla y es posible usar la recopilación masiva / la captación masiva.

En Oracle 10, el cursor implícito de uso frecuente

for x in (select ....) loop --do something end loop;

obtiene implícitamente 100 filas a la vez. La recopilación masiva explícita / la captación masiva también es posible.

Sin embargo, los cursores PL / SQL son un último recurso, utilícelos cuando no pueda resolver un problema con SQL basado en conjuntos.

Otra razón es la paralelización, es más fácil para la base de datos paralelizar grandes sentencias basadas en conjuntos que código imperativo fila por fila. Es la misma razón por la cual la programación funcional se vuelve cada vez más popular (Haskell, F #, Lisp, C # LINQ, MapReduce ...), la programación funcional facilita la paralelización. El número de CPU por computadora está aumentando, por lo que la paralelización se vuelve cada vez más un problema.


En general, porque en una base de datos relacional, el rendimiento del código que utiliza cursores es un orden de magnitud peor que las operaciones basadas en conjuntos.



Hay una respuesta anterior que dice que "los cursores son la forma MÁS LENTA de acceder a datos dentro de SQL Server ... los cursores son más de treinta veces más lentos que las alternativas basadas en conjuntos".

Esta afirmación puede ser cierta bajo muchas circunstancias, pero como una declaración general es problemática. Por ejemplo, hice un buen uso de los cursores en situaciones en las que quiero realizar una operación de actualización o eliminación que afecta a muchas filas de una tabla grande que está recibiendo lecturas de producción constantes. Ejecutar un procedimiento almacenado que hace estas actualizaciones una fila a la vez termina siendo más rápido que las operaciones basadas en conjuntos, porque la operación basada en conjuntos entra en conflicto con la operación de lectura y termina causando problemas de bloqueo horribles (y puede matar completamente el sistema de producción, en casos extremos).

En ausencia de otra actividad de base de datos, las operaciones basadas en conjuntos son universalmente más rápidas. En los sistemas de producción, depende.


La "sobrecarga" con los cursores es simplemente parte de la API. Los cursores son la forma en que las partes del RDBMS funcionan bajo el capó. A menudo CREATE TABLE e INSERT tienen INSERT SELECT , y la implementación es la implementación obvia del cursor interno.

Al usar paquetes de "operadores basados ​​en conjuntos" de mayor nivel, los resultados del cursor se convierten en un único conjunto de resultados, lo que significa menos API de ida y vuelta.

Los cursores son anteriores a los idiomas modernos que ofrecen colecciones de primera clase. Old C, COBOL, Fortran, etc., tuvieron que procesar las filas de una en una porque no había una noción de "colección" que se pudiera usar ampliamente. Java, C #, Python, etc., tienen estructuras de listas de primera clase para contener conjuntos de resultados.

El problema lento

En algunos círculos, las uniones relacionales son un misterio, y la gente escribirá cursores anidados en lugar de una simple combinación. He visto operaciones de bucle anidado verdaderamente épicas escritas en montones y montones de cursores. Derrotando una optimización de RDBMS. Y corriendo muy despacio.

Simple SQL reescribe para reemplazar los bucles de cursor anidados con combinaciones y un único bucle de cursor plano puede hacer que los programas se ejecuten en la centésima vez. [Ellos pensaron que yo era el dios de la optimización. Todo lo que hice fue reemplazar los bucles anidados con combinaciones. Todavía usa cursores.]

Esta confusión a menudo conduce a una acusación de cursores. Sin embargo, no es el cursor, es el mal uso del cursor el problema.

El problema del tamaño

Para los conjuntos de resultados realmente épicos (es decir, volcar una tabla en un archivo), los cursores son esenciales. Las operaciones basadas en conjuntos no pueden materializar conjuntos de resultados realmente grandes como una sola colección en la memoria.

Alternativas

Intento utilizar una capa de ORM tanto como sea posible. Pero eso tiene dos propósitos. Primero, los cursores son administrados por el componente ORM. En segundo lugar, el SQL está separado de la aplicación en un archivo de configuración. No es que los cursores sean malos. Es que codificar todas esas aperturas, cierres y recuperaciones no es una programación de valor agregado.


Las respuestas anteriores no han enfatizado lo suficiente la importancia del bloqueo. No soy un gran admirador de los cursores porque a menudo dan como resultado bloqueos a nivel de tabla.


Los cursores hacen que las personas apliquen excesivamente una mentalidad de procedimiento a un entorno basado en conjuntos.

¡Y ellos son LENTOS !

De SQLTeam :

Tenga en cuenta que los cursores son la forma MÁS LENTA de acceder a datos dentro de SQL Server. Solo debe usarse cuando realmente necesite acceder a una fila a la vez. La única razón por la que se me ocurre es llamar a un procedimiento almacenado en cada fila. En el artículo de Cursor Performance descubrí que los cursores son más de treinta veces más lentos que las alternativas basadas en conjuntos .


Los cursores tienden a ser utilizados por los desarrolladores principiantes de SQL en lugares donde las operaciones basadas en conjuntos serían mejores. Particularmente cuando las personas aprenden SQL después de aprender un lenguaje de programación tradicional, la mentalidad de "iterar sobre estos registros" tiende a llevar a las personas a usar cursores de manera inapropiada.

Los libros SQL más serios incluyen un capítulo que ordena el uso de cursores; los bien escritos dejan en claro que los cursores tienen su lugar, pero no deberían usarse para operaciones basadas en conjuntos.

Obviamente hay situaciones en las que los cursores son la elección correcta, o al menos una opción correcta.


Por lo que vale, he leído que en el lugar "uno", un cursor superará su contraparte basada en conjunto en un total acumulado. En una tabla pequeña, la velocidad de sumar las filas sobre el orden por columnas favorece la operación basada en conjuntos, pero a medida que la tabla aumenta en tamaño de fila, el cursor se volverá más rápido porque simplemente puede llevar el valor total acumulado al siguiente pase del lazo. Ahora donde deberías hacer un total acumulado es un argumento diferente ...


Probablemente haya concluido su pregunta después del segundo párrafo, en lugar de llamar a la gente "loca" simplemente porque tienen un punto de vista diferente del suyo y de otra manera intentar burlarse de los profesionales que pueden tener una muy buena razón para sentirse de la manera en que lo hacen.

En cuanto a su pregunta, aunque ciertamente hay situaciones en las que se puede necesitar un cursor, en mi experiencia los desarrolladores deciden que un cursor "debe" ser usado mucho más a menudo de lo que realmente es el caso. La posibilidad de que alguien se equivoque por el uso excesivo de los cursores y no los use cuando debería es MUCHO más alto en mi opinión.


básicamente 2 bloques de código que hacen lo mismo. tal vez es un ejemplo un poco extraño, pero demuestra el punto. SQL Server 2005:

SELECT * INTO #temp FROM master..spt_values DECLARE @startTime DATETIME BEGIN TRAN SELECT @startTime = GETDATE() UPDATE #temp SET number = 0 select DATEDIFF(ms, @startTime, GETDATE()) ROLLBACK BEGIN TRAN DECLARE @name VARCHAR DECLARE tempCursor CURSOR FOR SELECT name FROM #temp OPEN tempCursor FETCH NEXT FROM tempCursor INTO @name SELECT @startTime = GETDATE() WHILE @@FETCH_STATUS = 0 BEGIN UPDATE #temp SET number = 0 WHERE NAME = @name FETCH NEXT FROM tempCursor INTO @name END select DATEDIFF(ms, @startTime, GETDATE()) CLOSE tempCursor DEALLOCATE tempCursor ROLLBACK DROP TABLE #temp

la actualización única demora 156 ms mientras el cursor tarda 2016 ms.