Ya sólo queda finalizar con un pequeño resumen de recomendaciones, finalizando así con el presente artículo. Vamos a ello...
El Modo de Recuperación (Recovery) de nuestra base de datos, puede convertirse en nuestro gran aliado si realizamos Operaciones de Registro Mínimo. De hecho, incluso si no relizamos Operaciones de Registro Mínimo, un Modo de Recuperación Simple evitará la necesidad de realizar Copias de Seguridad de Log (Backup Log), con el consiguiente ahorro en operaciones de acceso a disco (además, nos permitirá poder tener ficheros de Log más pequeños y minimizar las operaciones de crecimiento del Log). Claro está que el Modo de Recuperación Simple es menos seguro, pues no permite recuperar hasta un momento dado (RESTORE STOPAT), y además, no dispondremos de Backups de Log que pueden resultarnos de mucha ayuda (ej: en Modo de Recuperación Completo, si perdemos un Backup Full, podemos recuperar el Backup Full anterior, y aplicar todos los Backups de Log hasta el momento del tiempo que deseemos, por ejemplo, un momento posterior al Backup Full perdido: tolerancia a fallo de backups ;-).
Si la base de datos destino utiliza el Modo de Recuperación Completo (recovery FULL), resulta de gran interés poder apoyarse en TEMPDB (por ejemplo, utilizando tablas temporales) o en alguna otra base de datos adicional que utilice el Modo de Recuperación SIMPLE, para poder minimizar la escrituras en el LOG de SQL Server, y así, mejorar sensiblemente el rendimiento de nuestros procesos de carga.
Recordar, que TEMPDB se crea cada vez que se inicia la instancia de SQL Server, en consecuencia, es importante establecer un tamaño por defecto de TEMPDB correctamente dimensionado, y ser conscientes que ante un reinicio de la instancia (ej: un balanceo del Grupo de Recursos del Cluster utilizado para SQL Server, en caso de tratarse una instalación de SQL Server en Cluster), perderemos el contenido de TEMPDB (el concepto de persistencia en TEMPDB es bastante relativo, jeje ;-).
Para el desarrollo de Cargas Incrementales (típico ejemplo de Data Warehouse), en muchas ocasiones interesa crear una primera tabla temporal con todas la filas (es decir, una carga completa) mediante una sentencia SELECT INTO sobre una base de datos en Modo de Recuperación Simple. Seguidamente, realizaremos una operación INSERT INTO sobre la tabla definitiva, en esta ocasión sólo con las filas estrictamente necesarias (Carga Incremental). Debe recordarse, que muchas veces al trabajar con Tablas Versionadas o Tablas SCD Tipo 2, resulta especialmente dificil poder determinar directamente las filas incrementas que deseamos cargar (es decir, resulta especialmente dificil evitar el primer SELECT INTO que antes comentamos), existiendo casos en que se realizan modificaciones con efecto retroactivo en los datos origen, se realizan modificaciones manuales en los datos origen, etc. Un ejemplo típico es la creación de una nueva versión sobre una tabla SCD de Tipo 2. Si tenemos una Póliza con una única versión, con Fecha Desde a 01/01/2008 y Fecha Hasta a 31/12/9999, y se crea una nueva versión con Fecha Desde 01/01/2009 y Fecha Hasta 31/12/2009, también se modificará la versión original (en particular el campo Fecha Hasta, cerrándolo a 31/12/2008). Si esta nueva versión se crea en Febrero de 2009 (es decir, es un cambio con efecto retroactivo), podría ser que en alguna carga anterior alguna fila de otra tabla estuviese relacionada con versión original, cuando después de la creación de la nuevo versión, debería relacionarse con la nueva versión (típico problema de la utilización de Claves Subrogadas). Este tipo de problemáticas, y otras más, suelen solucionarse de una forma más clara y sencilla realizando una carga en dos fases (SELECT INTO e INSERT INTO), aunque no quita que sea posible realizarlo en una única fase (eso sí, recordar que el código hay que mantenerlo, y que la rotación del personal invita a generar código de fácil mantenimiento).
Del mismo modo, también quiero comentar que en algunos procesos de carga críticos, se realiza una Carga Incremental mediante SELECT INTO, creando una tabla con el conjunto de filas incremental que posteriormente será agregado a la tabla destino (la cual se trata de una Tabla Particionada, utilizando ALTER TABLE SWITCH para cargar una partición vacía). Aquí se aprovecha el Particionamiento de SQL Server, para evitar tener que realizar el INSERT INTO sobre la tabla destino, con el objetivo de mejorar el rendimiento. Claro está, que no siempre resulta posible o intersante esta opción. Por ejemplo, si estamos cargando un fichero de Log (ej: el Log del ISA Server, un Application Log de Windows, etc.), podemos permitirnos el hecho cargar un mes completo como una partición, pero en otros casos (ej: pagos de primas en una empresa de seguros) puede que no podamos debido a que puedan insertarnos filas con efecto retroactivo (es decir, tendíamos que realizar modificaciones sobre múltiples particiones que ya estaban cargadas previamente, complicándose dicho proceso de carga).
Otro detalle a tener en cuenta, es que en la realización de Cargas Totales con operaciones INSERT INTO (y también con BCP y BULK INSERT), suele ser interesante eliminar los índices antes de realizar la carga, realizar la carga, y volver a crear los índices. Claro está, que en el caso de Cargas Incrementales, la eliminación y creación de índices suele aportar más inconvenientes que ventajas (es decir, que suele resultar mucho más costosa).
Resulta de gran importancia tener correctamente dimensionados nuestros ficheros de base de datos, tanto dimensionar los ficheros de datos, como dimensionar los ficheros de LOG. Con esto, no sólo me refiero al tamaño asignado a dichos ficheros. Es tan importante asignar un tamaño suficiente a los ficheros de datos y log, como configurar apropiadamente las opciones de crecimiento de los ficheros, pues estas últimas tienen un impacto directo en la generación de actividad de entrada salida extraordinaria.
Por supuesto, un buen dimensionamiento de la Memoria RAM de SQL Server será de gran ayuda. Recordemos, que SQL Server por defecto intentará consumir toda la memoria RAM que le sea necesario sin hacer incurrir en paginación al Sistema Operativo. En consecuencia, cuanta mayor memoria disponga nuestra Instancia de SQL Server, mayor será la cantidad de páginas de datos que se podrán mantener en memoria, y en consecuencia se podrá minimizar la necesidad de acceder a disco para la lectura de dichas páginas (el acceso a disco es quizás el principal cuello de botella para cualquier motor de base de datos).