Mostrando entradas con la etiqueta Chapter 02. Mostrar todas las entradas
Mostrando entradas con la etiqueta Chapter 02. Mostrar todas las entradas

jueves, 16 de julio de 2015

Receta Multithreading en C# No. 2-8: Uso de la Estructura SpinWait - Ahorro de Ciclos de CPU

Índice

0. Introducción
1. Problema
2. Solución
3. Discusión de la Solución
3.1 La estructura SpinWait
4. Conclusiones
5. Glosario
6. Literatura & Enlaces

0. Introducción

Última receta multithreading de la serie Sincronización de Threads: en esta receta exploraremos la estructura SpinWait con la que podemos poner en espera un thread sin recurrir al uso de contrucciones basadas en el modo kernel: el thread pasará a modo bloqueado sin consumir ciclos de procesador. Esto nos llevará a entender que al alternación entre estos dos modos de operación conlleva a un ahorro de tiempo (o ciclos) de la Unidad de Procesamiento Central (CPU).

1. Problema

Requerimos aplicar un modo espera en un thread que optimice el consumo de ciclos de procesador.

2. Solución

En el namespace System.Threading encontramos la estructura SpinWait que optimiza el tiempo de uso de procesador.

3. Discusión de la Solución

3.1 La estructura SpinWait

La estructura SpinWait [2] está diseñada para poner en espera un thread sin ocupar tiempo de procesador en busy waits (~esperas desocupadas). Podemos exponer literalmente el comentario en [2]:
"SpinWait encapsulates common spinning logic. On single-processor machines, yields are always used instead of busy waits, and on computers with Intel processor employing Hyper-Threading technology, it helps to prevent hardware thread starvation."
SpinWait está diseñada como una construcción de sincronización híbrida, lo que quiere decir que la espera se realiza en modo bloqueado y no en modo usuario, de esta manera se evita ocupar tiempo de CPU de innecesaria.

Continuando, SpinWait es dependiente de la velocidad del procesador, por lo tanto un experimento efectuado con esta estructura puede variar significativamente de equipo en equipo dependiendo del número de núcleos lógicos y físicos.

Ahora podemos pasar a escribir un ejemplo de uso basado en el código presentando en [2]:

Ejemplo de uso:

En la línea 15 declaramos la variable valorCentinela para indicar cuando el thraed asociado con la estructura SpinWait debe terminar. Creamos un instancia de Task para ejecutar un thread que itera indefinidamente (líneas 24-34) y donde:
  • Línea 28: Se valida con NextSpinWaillYield si el control pasó al procesador o simple se ha efectuado un simple ~giro (spin). De ser así, incrementamos en una unidad la variable numeroCedes.
  • Línea 33: Invocamos el método SpinOnce [4] para dar un nuevo ~giro (spin).
El ciclo while se interrumpirá asignando true se asigne a la variable valorCentinela.


Casi al final, creamos un nuevo objeto Task para controlar cuando se ha de cambiar el valor de la variable valorCentinela. Cuando esto ocurra el ciclo del primer thread se interrumpirá y se culminará las llamadas a SpinOnce.



Compilación:



  1. csc /target:exe UsoSpinWait.cs


Ejecución assembly:



  1. .\UsoSpinWait.exe


> Prueba de ejecución: http://ideone.com/OsqwDQ



> Prueba de ejecución:
Ejecución assembly UsoSpinWait.exe
Figura 1. Ejecución assembly UsoSpinWait.exe.

En las 5 ocasiones que se ejecutó el assembly UsoSpinWait.exe la mayor parte de operaciones fueron cedidas al procesador; sin embargo, hay que dejar claro que esto ha sido para tiempos de espera corto. También quiero apuntar que la ejecución de este programa se realizó sobre un equipo con un procesador AMD FX 6300 de 3 núcleos físicos y 6 lógicos y puede variar en otro máquina con distinta configuración.

4. Práctica: Código C#

Hagamos una adaptación al ejemplo de SpinWait presentando en [1]. En este ejemplo demostraremos la diferencia entre el modo de espera de usuario y el modo de espera de kernel (o híbrido).

Archivo C# ModoUsuarioVsModoKernel.cs [Enlace alternativo]:

En la línea 10 creamos la variable static finalizado:bool con volatile [4] para indicar que el valor asignado estará presente y puede ser modificado desde cualquier thread sin generar ningún problema de sincronización.


Con el método ModoEsperaUsuario (líneas 37-46) simulamos un tiempo de espera de usuario con la ejecución indefinida del ciclo while: este ciclo no finaliza sino hasta que el valor de la variable finalizado cambie a true.



Por otro lado, con el método ModoEsperaKernel (líneas 46-60) simulamos el tiempo de espera híbrido (o por kernel). La parte más interesante ocurre en esta sección del programa donde se muestra que con SpinWait la espera se hacen en modo usuario (manteniendo un consumo considerable de ciclos de CPU) durante poco tiempo y después el control pasa un estado de bloqueo (reduciendo así el consumo de ciclos de CPU).



En Main (líneas 12-34):

  • Líneas 16-17: Creación de dos threads que referencian los métodos mencionados anteriormente.
  • Línea 20: Se inicia la prueba del modo espera basado en usuario.
  • Línea 22: Suspendemos el tiempo de espera asignando true a la variable finalizado.
  • Línea 26: Asignamos nuevamente true a la variable finalizado para poder iniciar la prueba del modo de espera basado en kernel o híbrido.
  • Línea 29: Iniciamos el thread para simular la espera en modo híbrido.
Compilación:

  1. csc /target:exe ModoUsuarioVsModoKernel.cs

Ejecución assembly:

  1. .\ModoUsuarioVsModoKernel.cs

> Prueba de ejecución: http://ideone.com/p0BT3b


> Prueba de ejecución:
Ejecución del assembly ModoUsuarioVsModoKernel.exe
Animación 1. Ejecución del assembly ModoUsuarioVsModoKernel.exe.
Notemos lo que ocurre en la Animación 1: cuando ejecutamos el modo de espera en modo híbrido: durante los primeros ciclos el control está en modo usuario (false), después el thread (t2) pasa a modo bloqueado (true) y de este modo reduciendo el consumo innecesario de ciclos de procesador.

5. Conclusiones

En esta última receta multithreading aprendimos a distinguir los modos de espera: usuario e híbrido (con SpinWait). La espera basada en usuario puede significar el uso innecesario de recursos, y más en particular, ciclos de procesador.


A partir de la siguiente receta multithreading nos enfocaremos en las técnicas básicas y comunes para la gestión de un pool (grupo) de threads.

6. Glosario

  • Ciclo
  • Core
  • CPU
  • Espera
  • Híbrido
  • Núcleo
  • Procesador
  • Sincronización
  • Thread
  • Tiempo

7. Literatura & Enlaces

[1]: Multithreading in C# 5.0 Cookbook by Eugene Agafonov. Copyright 2013 Eugene Agafonov, 978-1-84969-764-4.
[2]: SpinWait Structure (System.Threading) - https://msdn.microsoft.com/en-us/library/system.threading.spinwait(v=vs.110).aspx
[3]: SpinWait.NextSpinWillYield Property (System.Threading) - https://msdn.microsoft.com/en-us/library/system.threading.spinwait.nextspinwillyield(v=vs.110).aspx
[4]: volatile (C# Reference) - https://msdn.microsoft.com/en-us/library/x13ttww7.aspx


A

miércoles, 15 de julio de 2015

Receta T-SQL No. 2-10: Creación y Uso de Cursores

Índice

0. Introducción
1. Problema
2. Solución
3. Discusión de la Solución
4. Práctica: Código C#
5. Conclusiones
6. Glosario
7. Literatura & Enlaces

0. Introducción

Última receta T-SQL de esta serie de recetas dedicadas a comprender las construcciones programáticas disponibles en el lenguaje T-SQL: declaración de variables, asignación de variables, uso de sentencias de control de flujo, sentencias iterativas. El objetivo principal de esta receta es entender cómo podemos usar un cursor para el tratamiento individual de los registros (filas) retornados por una sentencia T-SQL. Se presentarán algunas advertencias de rendimiento a la hora de usar este enfoque de manipulación de registros.

1. Problema

Necesitamos conocer cómo lograr el procesamiento de registro-por-registro en lugar de recurrir a operaciones masivas (o basadas en conjunto) sobre registros o filas.

2. Solución

En T-SQL podemos usar cursores para el tratamiento de registro-por-registro para lograr un control más riguroso sobre lo que se ha de hacer sobre cada registro.

3. Discusión de la Solución

Lo primero que debemos considerar antes de entrar en materia es la siguiente precaución con el uso de cursores [1]:
Advertencia uso de cursores
Figura 1. Advertencia uso de cursores [1].
Algunas de las situaciones donde se podría recurrir al uso de cursores son las que se mencionan en [1]:
  • Obtención de información de administración de una base de datos.
  • Solución de problemas que en el modo de operación basado en conjunto no son posibles de solucionar.
Para la creación de cursores deberíamos seguir estos pasos:
  1. Declaración de una variable CURSOR
  2. Apertura del cursor
  3. Recuperación de registros (filas) uno a la vez
  4. Ciclar registro-por-registro
  5. Cierre del cursor
  6. Liberación de recursos del cursor
En el ejemplo que escribiremos en la sección práctica seguiremos estos pasos para iterar por cada registro (tienda) en la tabla Store de la base de datos AdventureWorks2012.

4. Práctica: Código C#

El punto 4 (líneas 24-28) es donde ocurre la parte más interesante del procesamiento de registro-por-regitro (row-by-row) aquí tratamos de forma individual cada registro de la tabla Store de la base de datos AdventureWorks2012. El procesamiento que hacemos aquí por cada fila consiste en mostrar el ID de la tienda y su nombre; en la Figura 2 se muestra el resultado de la ejecución de este código T-SQL.
Salida ejecución cursor

5. Conclusiones

Aprendimos a crear un cursor para la exploración de registro por registro de un conjunto de registros. Este tipo de operación, como se adivirtió arriba, puede reducir el rendimiento de la aplicación, reducir la concurrencia, disminuir el ancho de banda, bloquear el acceso a recursos, entre otros; es por eso que se debe usar en situaciones muy especiales y prestando particular atención con no afectar el desempeño de la aplicación.


Con la próxima receta damos inicio a la tercera serie de recetas T-SQL: NULLs y sus trampas.

6. Glosario

  • Cursor
  • Rendimiento
  • Sentencia
  • T-SQL

7. Literatura & Enlaces

[1]: SQL Server 2012 T-SQL Recipes - A Problem-Solucion Approach by Jason Brimhall, David Dye, Jonathan Gennick, Andy Roberts, and Wayne Sheffield. Copyright 2012 Jason Brimhall, David Dye, Jonathan Gennick, Andy Roberts, and Wayne Sheffield, 978-1-4302-4200-0.

S

lunes, 13 de julio de 2015

Receta T-SQL No. 2-9: Pausa de la Ejecución de un Batch Durante un Período

Índice

0. Introducción
1. Problema
2. Solución
3. Discusión de la Solución
3.1 Sentencia WAITFOR
3.2 Utilidades de WAITFOR
4. Práctica: Código T-SQL
4.1 Práctica #1
4.2 Práctica #2
5. Conclusiones
6. Glosario
7. Literatura & Enlaces

0. Introducción

Aprenderemos a usar la sentencia WAITFOR para detener o bloquear la ejecución de un batch T-SQL durante un período determinado. Exploraremos la utilidad de esta sentencia a través de un par de ejemplos de práctica. También enunciáremos las demás aplicaciones interesantes de WAITFOR: espera hasta que una transacción se haya ejecutado durante cierto tiempo, y la modificación de un número de registros en una transacción.

1. Problema

Pausar la ejecución de un batch T-SQL durante un período.

2. Solución

T-SQL cuenta con la sentencia WAITFOR para la especificación un período de espera.

3. Discusión de la Solución

3.1 Sentencia WAITFOR

La sentencia WAITFOR [2] permite, además de bloquear la ejecución de un batch durante un período específico:
  • retrasar la ejecución hasta determinada hora del día, 
  • establecer la espera hasta que se hayan modificado un número determinado de registros, e 
  • inclusive hasta que se retorne un registro en una transacción.
La sintaxis de uso de esta sentencia es así:

WAITFOR
{
    DELAY 'time_to_pass'
    | TIME 'time_to_execute'
    | [ ( receive_statement ) | ( get_conversation_group_statement ) ] 
      [ , TIMEOUT timeout ]
}

Donde:
  • DELAY: Indica la continuación de la ejecución de un batch, un procedimiento almacenado, o una transacción pasado un período.
    • 'time_to_pass': Tiempo de espera. Máximo 24 horas.
  • TIME: Indica el momento en que ha de continuar la ejecución de un batch, un precedimiento almacenado, o una transacción.
    • 'time_to_execute': Tiempo en que debe empezar la ejecución.
    • receive_statement: Sentencia RECEIVE valida. Opcional.
    • get_conversation_group_statement: Sentencia GET CONVERSATION GROUP valida. Opcional.
  • TIMEOUT timeout: Período de espera, en milisegundos, en la recepción de un mensaje en una cola. Opcional.
(Las sentencias RECEIVE y GET CONVERSATION GROUP las estudiáremos con detalle en futuras recetas.)

Podemos poner dos ejemplos de uso básicos de este sentencia:

Ejemplo de uso 1: Ejecución de procedimiento almacenado después de dos horas de retraso:

BEGIN
    WAITFOR DELAY '02:00';
    EXECUTE sp_helpdb;
END;
GO

Ejemplo de uso 2: Ejecución de procedimiento almacenado en un hora determinada -22:20-:

EXECUTE sp_add_job @tarea = 'TareaPrueba';
BEGIN
    WAITFOR TIME '22:20'
    EXECUTE sp_update_job @tarea = 'TareaPrueba';
        @Mensaje = 'TareaEjecutada'
END;
GO

3.2 Utilidades de WAITFOR

Entre las utilidades interesantes de WAITFOR tenemos [1]:
  • Ejecución asincrónica: Asumamos que hemos ejecutado un procedimiento almacenado y debemos esperar un período (e.g., 10 minutos) hasta que se haya finalizado su ejecución; una vez finalizado se han de ejecutar otras tareas que son dependientes de éste.
  • Tareas de mantenimiento: Queremos que un procedimiento almacenado se ejecute a una hora determinada (e.g., horas no operativas del negocio); esto para la ejecución de tareas de mantenimiento o consolidación de datos de las tablas, o generación de reportes basados en agregaciones.

4. Práctica: Código T-SQL

4.1 Práctica #1:

En este primer ejemplo retrasaremos la ejecución de una sentencia SELECT pasados 10 segundos:

WAITFOR DELAY '00:00:10';
BEGIN
SELECT TransactionID, Quantity
FROM Production.TransactionHistory;
END;

> Prueba de ejecución:

4.2 Práctica #2:
Ejecución de sentencia T-SQL retrasada por 10 segundos.
Animación 1. Ejecución de sentencia T-SQL retrasada por 10 segundos.

Ahora veremos cómo podemos postponer la ejecución de una sentencia T-SQL a las 07:52:23, siendo las ~07:52:12:

WAITFOR TIME '07:52:13';
BEGIN
SELECT COUNT(*)
FROM Production.TransactionHistory;
END;

> Prueba de ejecución:
Ejecución de sentencia T-SQL a las 07:51:23.
Animación 2. Ejecución de sentencia T-SQL a las 07:51:23.

5. Conclusiones

Estudiamos la sentencia WAITFOR: con la cual podemos retrasar, o postponer (entre otras operaciones) la ejecución de una sentencia, procedimiento almacenado, o transacción. En la sección práctica, demostramos el uso de esta sentencia a través de simples ejemplos que nos dan una intuición acerca de su utilidad (enunciada en la sección 3.2).

En la próxima receta T-SQL estudiáremos la creación y uso de cursores.

6. Glosario

  • Agregación
  • Batch
  • Consulta
  • Ejecución
  • Procedimiento almacenado
  • Transacción

7. Literatura & Enlaces

[1]: SQL Server 2012 T-SQL Recipes - A Problem-Solucion Approach by Jason Brimhall, David Dye, Jonathan Gennick, Andy Roberts, and Wayne Sheffield. Copyright 2012 Jason Brimhall, David Dye, Jonathan Gennick, Andy Roberts, and Wayne Sheffield, 978-1-4302-4200-0.
[2]: WAITFOR (Transact-SQL) - https://msdn.microsoft.com/en-us/library/ms187331.aspx


S

sábado, 11 de julio de 2015

Receta Multithreading en C# No. 2-7: Uso de Barrier para la Sincronización de Algoritmos Iterativos

Índice

0. Introducción
1. Problema
2. Solución
3. Discusión de la Solución
4. Práctica: Código C#
5. Conclusiones
6. Glosario
7. Literatura & Enlaces

0. Introducción

En esta séptima receta mulithreading en C# haremos algo muy interesante y es sincronizar múltiples threads dentro de un proceso que implementa lógica iterativa (ciclos, o loops) hasta que todos los threads hayan llegado a un punto concreto. Destacaremos otras importantes utilidades de este tipo de sincronización. El ejemplo que se presentará consistirá en la sincronización de una banda musical integrada por un guitarrista y un vocalista que deben estar sincronizados para que su interacción tenga sentido y ritmo.

1. Problema

Requerimos implementar lógica de sincronización que permita controlar y generar una señal de registro una vez que el flujo de ejecución de dos o más threads alcancen un determinado punto dentro del proceso.

2. Solución

La librería común de .NET ofrece la clase Barrier para la sincronización y cooperación de múltiples threads dentro de un proceso basado en fases/etapas.

3. Discusión de la Solución

La clase Barrier [2] (namespace System.Threading) permite que múltiples threads se ejecuten en paralelo para cooperar en cálculos, iteraciones, etc., dentro de un proceso. Cálculos e iteraciones que pueden requerir la reunión o finalización una vez se alcance un punto de ejecución.

Esta clase como advierten en [1, 2] es idónea para:
  • Procesos de múltiples fases
  • Algoritmos iterativos
  • Cálculos paralelos

4. Práctica: Código C#

Escribamos un ejemplo para la sincronización de 2 threads que simulan ser los integrantes de una banda musical:
  • un vocalista, y 
  • un guitarrista.

En la línea 10 creamos un objeto Barrier con el que queremos sincronizar dos (2) threads, y generar la notificación a modo de mensaje en la salida estándar con:

b => Console.WriteLine("Fin de la fase: {0}", b.CurrentPhaseNumber + 1)


Dentro de Main (líneas 14-24) creamos dos threads a los que asignamos la ejecución del método Tocar con los parámetros que indican:
  • el integrante de la banda, y 
  • el instrumento que éste toca.
En Tocar (líneas 26-43):
  • Líneas 28-42: Ciclo for que itera hasta dos veces (fases/etapas).
    • Línea 32: Simulación del tiempo que tarda el integrante en empezar a cantar/tocar.
    • Línea 33: Muestra mensaje advirtiendo que el integrante ha empezando a ejecutar su performance.
    • Línea 37: Simula el tiempo que el integrante tarda en ejecutar su performance.
    • Línea 39: Muestra mensaje advirtiendo que el integrante ha finalizado de ejecutar su performance.
    • Línea 41: Con esta línea sincronizamos la finalización de cada etapa/fase del performance (ejecución) de los integrantes (threads) de la banda: punto de sincronización.
Compilación:

  1. csc /target:exe SincronizacionBanda.cs

Ejecución assembly:

  1. .\SincronizacionBanda.exe

> Prueba de ejecución: ideone.com

> Prueba de ejecución (local):
Ejecución del assembly SincronizacionBanda.exe
Animación 1. Ejecución del assembly SincronizacionBanda.exe.

5. Conclusiones

Hemos usado la clase System.Threading.Barrier para la sincronización de múltiples threads para que una vez éstos alcancen un punto específico de la ejecución de un proceso emitan una señal de registro (o reunión) para la generación de una acción/notificación en particular. Este tipo de sincronziación, como vimos, es útil para algoritmos basados en iteración que requieren la acción de múltiples threads para completar su tarea.


En la próxima receta multithreading en C# estudiáremos la clase ReaderWriterLockSlim para crear un mecanismo seguro de sincronización sobre un rescurso compartido.

6. Glosario

  • Algoritmo iterativo
  • Barrier
  • Cálculo
  • Etapa
  • Fase
  • Iteración
  • Loop
  • Multithreading
  • Recurso compartido
  • Sincronización

7. Literatura & Enlaces

[1]: Multithreading in C# 5.0 Cookbook by Eugene Agafonov. Copyright 2013 Eugene Agafonov, 978-1-84969-764-4.
[2]: Barrier Class (System.Threading) - https://msdn.microsoft.com/en-us/library/system.threading.barrier(v=vs.110).aspx


J

Receta T-SQL No. 2-8: Ir a un Punto de Procesamiento en un Batch T-SQL

Índice

0. Introducción
1. Problema
2. Solución
3. Discusión de la Solución
4. Práctica: Código C#
5. Conclusiones
6. Glosario
7. Literatura & Enlaces

0. Introducción

En T-SQL tenemos la posibilidad de programar un conjunto de sentencias que se ejecuten rutinariamente. Las sentencias pueden requerir una lógica de control de flujo de ejecución basada en condiciones y saltos a puntos de procesamiento específicos; es por esta razón que dedicaremos nuestro esfuerzo en comprender cómo T-SQL provee los mecanismos lógicos para permitir seguir este enfoque de ejecución.

1. Problema

Se requiere programar un batch T-SQL que permita pasar el control del flujo de ejecución a un punto específico de la lógica de implementación.

2. Solución

T-SQL cuenta con la sentencia GOTO para solucionar este problema. GOTO pasa el control de flujo de ejecución a un punto marcado por una etiqueta con un nombre único y de donde se continuará con la ejecución del batch.

3. Discusión de la Solución

Al usar GOTO [2] omitimos la ejecución de las sentencias que se hallen entre esta sentencia y el punto de salto con el nombre de la etiqueta correspondiente, es por esta razón que debemos tener cuidado con el excesivo uso de esta construcción.

Para declarar una etiqueta seguimos esta sintaxis:

nombre_etiqueta:

Notemos los dos puntos (:) después del nombre de la etiqueta: es requerido sintácticamente. A partir de los dos puntos seguidos escribiremos las sentencias T-SQL que se ejecutarán después de haber dado el salto con la sentencia GOTO.

IF (SELECT ...) = 'RealizarPago'
    GOTO calcular_salario
    -- sentencia 1
    -- sentencia 2
    -- sentencia 3
    -- ...
    -- sentencia n
calcular_salario:
    -- otras_sentencias

En este fragmento de código T-SQL una vez que se evalúa en VERDADERO el predicado de la sentencia IF, la instrucción GOTO calcular_salario omitirá el resto de sentencias (i.e.sentencia 1sentencia 2sentencia 3sentencia n) y dará el salto a la etiqueta calcular_salario para continuar a partir de ahí la ejecución de las sentencias otras_sentencias.

Deberíamos considerar la nota dada en [2]:
"The logic implemented using GOTO can almost always be implemented using the other control-of-flow statements. GOTO is best used for breaking out of deeply nested control-of-flow statements."

4. Práctica: Código C#

Escribamos un ejemplo práctico usando la base de datos Adventure Works 2012, en particular la tabla HumanResources.Department para validar que el nombre de un departamento ya se encuentra en uso. Si el departamento se encuentra en la tabla mencionada, se omitirá la inserción del registro en la base datos y sólo se mostrará un mensaje en la salida estándar anunciando que el registro para ese departamento ya existe.


Declaramos las variables:
  • Línea 3: La variable @NombreDepartamento contiene el nombre de departamento que queremos insertar en la tabla HumanResources.Department.
  • Línea 4: La variable @NombreGrupo contiene el nombre del grupo para el departamento.
  • Línea 5: Con la variable @Existe de tipo bit mantenemos control si el registro para Engineering existe.
Con la sentencia IF de la línea 7 validamos si el registro con Name igual al valor de @NombreDepartamento existe. Ha sido intencional que esta esta expresión se evalúe en verdadero, pues el propósito es demostrar el uso de GOTO (línea 10). Notemos además que hemos asignado 1 a la variable @Existe para indicar que el registro existe.

Ahora nos encontramos en la línea 17 (las líneas 12-16 han sido omitidas por el uso de GOTO) y aquí validamos que el valor de @Existe sea igual a 1. Dado que es así, mostramos el mensaje correspondiente con PRINT.

Cuando ejecutamos este batch en Microsoft SQL Management Studio obtenemos este resultado en la salida de mensajes:

El departmento Engineering ya existe en `HumanResources.Department`.

5. Conclusiones

Hemos aprendido a usar la sentencia GOTO para dar saltos en el flujo de control de un batch de T-SQL. A pesar de su utilidad, hay que tener siempre en cuenta que el excesivo uso de esta construcción puede conllevar a la generación de código difícil de comprender. En su lugar se puede recurrir a otras sentencias de control flujo aptas para lógicas más complejas.


En la próxima receta T-SQL (2-9) veremos cómo podemos pausar la ejecución durante un determinado período.

6. Glosario

  • Base de datos
  • Batch
  • Salto
  • Sentencia

7. Literatura & Enlaces

[1]: SQL Server 2012 T-SQL Recipes - A Problem-Solucion Approach by Jason Brimhall, David Dye, Jonathan Gennick, Andy Roberts, and Wayne Sheffield. Copyright 2012 Jason Brimhall, David Dye, Jonathan Gennick, Andy Roberts, and Wayne Sheffield, 978-1-4302-4200-0.
[2]: Using GOTO - https://technet.microsoft.com/en-us/library/ms188729(v=sql.105).aspx


J