Puedo entender querer evitar tener que usar un cursor debido a la sobrecarga y las molestias, pero parece que está ocurriendo una seria fobia al cursor 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 propuso utilizar 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 llamadas a funciones recursivas en el servidor sql). Esto me parece una solución terrible para la longevidad del sistema, sin mencionar un tremendo esfuerzo solo para evitar usar un cursor simple.
¿Cuál es la razón de este nivel de odio loco? ¿Alguna 'autoridad notoria' ha emitido una fatwa contra los cursores? ¿Algún mal indescriptible acecha en el corazón de los cursores que corrompe la moral de los niños o algo así?
Pregunta de Wiki, más interesado en la respuesta que en el representante.
Información relacionada:
Cursores de avance rápido de SQL Server
EDITAR: permítanme ser más preciso: entiendo que los cursores no deben usarse en lugar de las operaciones relacionales normales ; eso es obvio. Lo que no entiendo es que las personas se desviven mucho para evitar 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 eficiencias técnicas obvias.
32
es una tontería. Presumiblemente estás pensando en disparadores recursivos y el máximo@@NESTLEVEL
de32
. Se puede configurar en la consultaOPTION (MAXRECURSION N)
con el valor predeterminado100
e0
ilimitado.Respuestas:
La "sobrecarga" con los cursores es simplemente parte de la API. Los cursores son cómo funcionan las partes del RDBMS debajo del capó. A menudo
CREATE TABLE
yINSERT
tienenSELECT
declaraciones, y la implementación es la implementación del cursor interno obvio.El uso de "operadores basados en conjuntos" de nivel superior agrupa los resultados del cursor en un único conjunto de resultados, lo que significa menos API de ida y vuelta.
Los cursores son anteriores a los idiomas modernos que proporcionan colecciones de primera clase. Old C, COBOL, Fortran, etc., tuvieron que procesar las filas una a la vez porque no había una noción de "colección" que pudiera usarse 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 unión. He visto operaciones de bucle anidado verdaderamente épicas escritas como montones y montones de cursores. Derrotando una optimización RDBMS. Y corriendo muy despacio.
Las reescrituras simples de SQL para reemplazar los bucles de cursor anidados con combinaciones y un solo bucle de cursor plano pueden hacer que los programas se ejecuten en la centésima vez. [Pensaban que yo era el dios de la optimización. Todo lo que hice fue reemplazar los bucles anidados con uniones. Todavía usé 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 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 usar una capa 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 se separa 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.
fuente
Los cursores hacen que las personas apliquen excesivamente una mentalidad procesal a un entorno basado en conjuntos.
¡Y son LENTOS !
De SQLTeam :
fuente
Hay una respuesta anterior que dice "los cursores son la forma MÁS LENTA de acceder a los datos dentro de SQL Server ... los cursores son treinta veces más lentos que las alternativas basadas en conjuntos".
Esta afirmación puede ser cierta en muchas circunstancias, pero como afirmación general es problemática. Por ejemplo, he hecho buen uso de los cursores en situaciones en las que deseo realizar una operación de actualización o eliminación que afecta a muchas filas de una tabla grande que recibe lecturas de producción constantes. La ejecución de un procedimiento almacenado que realiza 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 el sistema de producción por completo, 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.
fuente
Los desarrolladores de SQL suelen utilizar los cursores 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 inapropiadamente.
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 deben usarse para operaciones basadas en conjuntos.
Obviamente, hay situaciones en las que los cursores son la elección correcta, o al menos una elección correcta.
fuente
El optimizador a menudo no puede usar el álgebra relacional para transformar el problema cuando se usa 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 explícitamente la solución.
fuente
En Oracle, los cursores PL / SQL no generarán bloqueos de tabla y es posible utilizar la recolección masiva / la obtención masiva.
En Oracle 10, el cursor implícito de uso frecuente
recupera implícitamente 100 filas a la vez. También es posible la recolección masiva explícita / la obtención masiva.
Sin embargo, los cursores PL / SQL son un último recurso, úselos 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 para paralelizar grandes declaraciones basadas en conjuntos que el código imperativo fila por fila. Es la misma razón por la que 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 convierte cada vez más en un problema.
fuente
En general, porque en una base de datos relacional, el rendimiento del código usando cursores es un orden de magnitud peor que las operaciones basadas en conjuntos.
fuente
Las respuestas anteriores no han enfatizado lo suficiente la importancia del bloqueo. No soy un gran fanático de los cursores porque a menudo resultan en bloqueos a nivel de tabla.
fuente
Por lo que vale, he leído que el "único" lugar donde un cursor superará a su contraparte basada en conjuntos es un total acumulado. En una tabla pequeña, la velocidad de resumir las filas en 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 paso del lazo. Ahora, donde debe hacer un total acumulado es un argumento diferente ...
fuente
Estoy de acuerdo con el artículo en esta página:
http://weblogs.sqlteam.com/jeffs/archive/2008/06/05/sql-server-cursor-removal.aspx
fuente
Fuera de los problemas de rendimiento (no), creo que la mayor falla de los cursores es que son dolorosos de depurar. Especialmente comparado con el código en la mayoría de las aplicaciones cliente, donde la depuración tiende a ser relativamente fácil y las características del lenguaje tienden a ser mucho más fáciles. De hecho, afirmo que casi todo lo que uno está haciendo en SQL con un cursor probablemente debería estar sucediendo en la aplicación cliente en primer lugar.
fuente
¿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 manera inadecuada (que a menudo) causan bloqueos innecesarios de página / fila.
fuente
Probablemente podría haber concluido su pregunta después del segundo párrafo, en lugar de llamar a las personas "locas" simplemente porque tienen un punto de vista diferente al suyo y de otra manera tratar de burlarse de los profesionales que pueden tener una muy buena razón para sentirse como ellos.
En cuanto a su pregunta, aunque ciertamente hay situaciones en las que se puede requerir un cursor, en mi experiencia los desarrolladores deciden que un cursor "debe" usarse MUCHO más a menudo de lo que realmente es el caso. En mi opinión, la posibilidad de que alguien cometa un error al usar demasiado los cursores en lugar de no usarlos cuando deberían debería ser MUCHO mayor.
fuente
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:
la actualización individual tarda 156 ms mientras que el cursor tarda 2016 ms.
fuente