Nota:esta publicación se publicó originalmente solo en nuestro libro electrónico, Técnicas de alto rendimiento para SQL Server, Volumen 3. Puede encontrar información sobre nuestros libros electrónicos aquí.
Hace más de tres años, escribí una publicación sobre las opciones de cursor en SQL Server y por qué debería anular los valores predeterminados:
- ¿Qué impacto pueden tener las diferentes opciones de cursor?
Quería publicar un seguimiento para reiterar que, si bien nunca debe aceptar los valores predeterminados, realmente debe pensar qué opciones son más aplicables a su escenario. También quería aclarar algunos elementos que surgieron en los comentarios de esa publicación.
Andrew Kelly mencionó un gran punto, y es que un STATIC
cursor hace una copia única de los resultados, los coloca en tempdb y luego evita cualquier problema de simultaneidad que pueda afectar un DYNAMIC
cursor. Una opción no es claramente ganadora sobre la otra en todos los casos; por ejemplo, puede tener muchos cursores (o cursores con conjuntos de resultados muy grandes) y/o un tempdb ya sobrecargado y no desea descargar ningún estrés adicional allí. Pero es algo que vale la pena probar.
Fabiano también mencionó un gran punto que tanto DYNAMIC
y FAST_FORWARD
los cursores pueden ser vulnerable al problema de Halloween (discutido por Paul White en una serie de 4 partes, comenzando aquí). Paul también comentó que FAST_FORWARD
podría no ser vulnerable al problema, dependiendo de si el optimizador eligió un plan estático o dinámico (Marc Friedman de Microsoft entra en detalles aquí).
Finalmente, quería señalar que no todos los cursores predeterminados son iguales. Realicé algunas pruebas y verifiqué cómo SQL Server decidió establecer opciones de cursor en una variedad de escenarios (validado usando sys.dm_exec_cursors
función de gestión dinámica). El código es bastante simple:
DECLARE c CURSOR FOR [...blah blah...]; SELECT properties FROM sys.dm_exec_cursors(@@SPID);
Estos son los resultados de los escenarios que probé:
La consulta del cursor se basa en... | Tipo | Concurrencia | Alcance |
---|---|---|---|
una constante (FOR SELECT 1 o FOR SELECT SYSDATETIME() ) | Instantánea | Solo lectura | Global |
una tabla #temp / ##temp | Dinámico | Optimista | Global |
una tabla/vista de usuario | Dinámico | Optimista | Global |
una vista de catálogo / DMV | Instantánea | Solo lectura | Global |
una unión #tmp -> tabla/vista de usuario | Dinámico | Optimista | Global |
una unión #tmp -> vista de catálogo / DMV | Instantánea | Solo lectura | Global |
una tabla / vista de usuario de unión -> vista de catálogo / DMV | Instantánea | Solo lectura | Global |
Crédito donde se debe el crédito:esta investigación fue desencadenada por una respuesta de Jeroen Mostert en Stack Overflow.
Por lo tanto, debe tener en cuenta que las opciones predeterminadas para su cursor, si no las anula, pueden ser diferentes según la consulta subyacente del cursor. Si espera un comportamiento específico en alguno o en todos los casos, acostúmbrese a especificar explícitamente las opciones que desea.
Pero en realidad, el punto es...
…dejar de usar cursores. Realmente hay muy pocos problemas hoy en día donde la mejor solución es un cursor, especialmente si está en SQL Server 2012 o superior, donde casi todos los problemas que tradicionalmente se resuelven con cursores se pueden resolver mediante mejoras en las funciones de la ventana. Si aún siente que necesita usar cursores, siga los consejos de esta publicación y su predecesora para determinar qué opciones debe usar.