Mes: noviembre 2023

Tareas diarias de un DBA SQL Server

Tareas diarias de un DBA SQL Server

En el post de ayer pudimos ver qué es un DBA y os prometí hablaros de las tareas que todo DBA de SQL Server debe ejecutar a diario. Pues bien, vamos a ello. Existen una serie de tareas que por su criticidad deberemos realizar o revisar diariamente. Obviamente todas estas estas tareas son candidatas de automatizarse, cosa que debe de ser nuestro objetivo final. Aunque, próximamente iremos viendo cómo debemos automatizar todas estas tareas hoy nos vamos a centrar solo en enumerarlas y ver por qué son necesarias.

Como comentamos ayer, una de las cualidades más importantes del buen administrador es tener el control absoluto sobre todo lo que gestiona. Esto no es solo aplicable a las bases de datos pero como este blog habla de ser DBA nos vamos a centrar en ello. Para tener un control absoluto sobre nuestros sistemas debemos por un lado llevar un mantenimiento preventivo para asegurar que no se produzcan incidencias. Por otro lado, deberemos también adelantarnos a los posibles problemas con una buena monitorización. Para que no se nos escape nada de lo que pasa es recomendable una buena auditoría. Y por último, por si todo lo demás falla, debemos asegurarnos de tener un buen plan de recuperación. Ahora sin más palabrería vamos a ver uno a uno cada uno de estos grupos que acaban de salir.

Tareas de copia de seguridad

Aunque en la introducción hemos hablado del plan de recuperación en último lugar, es tan importante que vamos a empezar por este apartado. Es importante tener al menos una copia diaria de todos los entornos de producción, aunque yo soy partidario de tener más y de todos los entornos. Una buena política de copias de seguridad tendrá una retención acorde con las necesidades técnicas y legales (en ocasiones hasta 10 años de retención para datos críticos).

En SQL Server existen 3 tipos de copias de seguridad: completa, diferencial y del log de transacciones. Mi política de backups modelo para un entorno productivo pasa por una copia completa semanal (los domingos), una copia diferencial diaria (de lunes a sábado) y una copia del log de transacciones cada hora. En este escenario ideal, mi retención de las copias semanales sería de 3 a 6 meses, las diarias de 1 a 3 meses y las horarias de al menos una semana.

No podemos hacer copias y olvidarnos de ellas, además de revisar cada día que las tareas no han dado error es importante que, con cierta frecuencia, recuperemos al menos uno de los ficheros de copias de seguridad para asegurarnos de que es correcto. SQL Server implementa la opción de verificar todos los backups durante el proceso de copia, pero para mi, esto no sustituye una prueba periódica. Aunque los backups sean correctos puede que el almacenamiento donde los tenemos se dañe con el tiempo y tenemos que ser capaces de reaccionar antes de que sea tarde.

Tareas de mantenimiento

Para mi, un buen plan de mantenimiento de SQL Server debe incluir tareas de desfragmentación de índices, actualización de las estadísticas y un chequeo de la integridad de las bases de datos. Estas son tareas muy pesadas por lo que tendrán una programación en las horas de menor actividad y nosotros solo verificaremos que han completado correctamente. Para este tipo de tareas yo siempre confío en los scripts de OLA Hallengren, software libre y de uso muy extendido en nuestro sector.

Desfragmentación de índices y actualización de estadísticas

El rendimiento de nuestras bases de datos depende en gran medida de sus índices. SQL Server los usará para acceder de eficientemente a los datos que almacenamos y si no están en buenas condiciones no va a poder usarlos. Por este motivo es de vital  importancia un buen plan de reorganización y reconstrucción de los índices fragmentados. Como norma general reorganizaremos los índices con una fragmentación entre el 5 y el 30%. Con menos de un 5% de fragmentación podemos considerar el índice en óptimas condiciones de funcionamiento. Para los índices fragmentados más del 30% ejecutaremos una tarea de reconstrucción que será más óptima.

Hemos dicho que SQL Server usa los índices para acceder a los datos pero esto no lo hace por arte de magia, implementa unos algoritmos que miran las estadísticas de las tablas y toman la decisión de qué índice usar y cuando. Es por esto que un mantenimiento de índices siempre debe de ir acompañado por un mantenimiento de estadísticas. 

Todo esto que os acabo de comentar, se puede hacer en una única ejecución de los procedimiento almacenados de OLA con el siguiente script:

EXECUTE dbo.IndexOptimize
@Databases = 'USER_DATABASES',
@FragmentationLow = NULL,
@FragmentationMedium = 'INDEX_REORGANIZE,INDEX_REBUILD_ONLINE,INDEX_REBUILD_OFFLINE',
@FragmentationHigh = 'INDEX_REBUILD_ONLINE,INDEX_REBUILD_OFFLINE',
@FragmentationLevel1 = 5,
@FragmentationLevel2 = 30,
@UpdateStatistics = 'ALL',
@OnlyModifiedStatistics = 'Y'

Comprobaciones de integridad de las bases de datos

Existen varios tipos de comprobaciones de integridad pero nosotros nos vamos a centrar en dos. Por un lado tenemos el famoso DBCC CHECKDB que nos revisa tanto la integridad de los datos como que los ficheros de base de datos no estén corruptos. Si a este comando le añadimos el comando PHYSICAL ONLY omitiremos el chequeo de integridad de los datos y solo se verificará que los ficheros no estén corruptos. 

Debemos comprobar que nuestra base de datos no está corrupta de manera recurrente, siempre que sea posible ejecutaremos una comprobación completa a diario. Si no tenemos una ventana de mantenimiento disponible en el día a día para esta comprobación completa haremos al menos una comprobación physical only y dejaremos la comprobación para un día del fin de semana con mayor ventana de mantenimiento.

Esta comprobación la haremos con el siguiente script de OLA (la última línea solo la descomentaremos en caso de querer un chequeo physical only)

EXECUTE dbo.DatabaseIntegrityCheck
@Databases = 'USER_DATABASES'
,@CheckCommands = 'CHECKDB'
/*,@PhysicalOnly = 'Y' */

Tareas de monitorización

Un DBA profesional sabe anticiparse a los problemas, pero no porque tenga un especial sentido arácnido, sino porque tiene una buena monitorización que le avisa a los primeros síntomas. El log de errores de SQL Server debe ser nuestro amigo, debemos leerlo en busca de pistas que nos indiquen que algo no está como debería. Debemos prestar especial atención a los errores 823, 824 y 825 así como a todos los mensajes con una gravedad mayor a 17.

Si nuestro servidor tiene salida a internet y configurado el correo de base de datos lo mejor sería programar alertas para estos casos. Otros aspectos importantes a monitorizar son los bloqueos de consultas, sesiones con transacciones abiertas de larga duración, espacio restante en disco y en los ficheros de bases de datos si hemos definido un límite de crecimiento. Yo también suelo programar una alerta que comprueba que todas las bases de datos estén ONLINE. Por último si somos responsables de la ejecución de algún job miraremos su historial de ejecución.

Tareas de auditoría

Si bien este tipo de tareas no suelen incluirse en los listados de tareas diarias, una buena auditoría nos ayudará a saber qué está pasando. Además, podremos entender mejor los problemas que les puedan surgir a los usuarios. Y no hablo de una auditoría completa de todo lo que se ejecuta sino de por ejemplo auditar los inicios de sesión incorrectos. Esta auditoría, activada por defecto en SQL Server, nos ayuda a afrontar incidentes de acceso de los usuarios ya que registra el motivo del fallo. Si un usuario no puede acceder pero no vemos registro en el log es probable que no esté llegando al servidor.

Otra auditoría que a mi me es muy útil es el registro de cambios en la estructura de las tablas, con una consulta en un job vuelco en una tabla el contenido de la vista information_schema.columns y puedo detectar cuando hay un cambio que me pueda dar problemas. Me gusta también implementar en todos mis sistemas de producción una auditoría que registre diariamente en una tabla los permisos de todos los usuarios de SQL Server para que, cuando se produzca un fallo de permisos, pueda ver si ese usuario ha perdido los permisos por algo o es que nunca los ha tenido.

Conclusión

Es importante saber prevenir y anticiparnos a los problemas. Diariamente mantendremos nuestras bases de datos y revisaremos que todo esté correcto. En resumen:

  • Optimizaremos índices y estadísticas.
  • Chequeamos la integridad de las bases de datos.
  • Haremos y verificaremos las copias de seguridad.
  • Buscaremos errores en el log de errores de SQL Server.
  • Revisaremos el espacio libre en disco.
  • Auditamos los problemas más comunes a los que nos podamos llegar a enfrentar.

Puede parecer mucho pero os aseguro que todas estas tareas se pueden automatizar y al final lo único que debemos hacer es estar pendientes de un sistema de monitorización o del correo electrónico que nos avise en caso de que algo no va como debería.

Publicado por Roberto Carrancio en SQL Server, 8 comentarios
¿Qué es ser DBA?

¿Qué es ser DBA?

Un tema de conversación típico cuando conoces a una persona es interesarse por su profesión. Los que nos dedicamos a esto, no estamos exentos de eso y respondemos orgullosos “SOY DBA”. Sin embargo, a lo largo de estos años que llevo dedicándome a las bases de datos, muchas veces quien tengo delante no sabe lo que es ser DBA. 

Hemos escrito ya varios artículos en este blog que se llama SoyDBA y sin embargo no os hemos explicado qué significa realmente ser DBA. La mayoría de los que estáis leyendo estas líneas seguro que ya lo sabéis, bien porque ser DBA sea vuestro objetivo o porque ya seáis DBAs. Vamos a tratar dar respuesta a estas preguntas para que todo el mundo sepa de lo que hablamos. Ya seáis DBAs, queráis serlo o este sea vuestro primer contacto con este concepto y este maravilloso mundo quedaos que va a ser interesante.

¿Qué es un DBA?

DBA son las siglas en inglés de Administrador de Bases de Datos. Aunque el nombre parezca muy descriptivo, lo cierto es que nuestras funciones son tan variadas que a veces es difícil marcar dónde acaba nuestra responsabilidad y dónde empieza la de otros roles.

Lo que sí podemos decir, es que ya seamos DBA de SQL Server o de otro SGBD, nuestro trabajo es muy parecido. Cambiará cómo hacer las cosas pero las tareas son las mismas.

Nuestro SGBD de referencia no sería la única clasificación posible, existen DBAs orientados a infraestructura y otros al rendimiento. Aunque en esto, lo normal es encontrar perfiles mixtos en este sentido y solo ver esta diferencia en puestos altamente especializados. 

¿Necesito un Administrador de Bases de Datos?

Para responder a esta pregunta debes preguntarte si existen bases de datos en tu empresa. Si la respuesta es sí, claramente necesitas un DBA. Puede que no necesites una persona en plantilla dedicada en exclusiva a esas tareas pero está claro que alguien las tiene que hacer y si no es una persona especializada no sacarás todo el partido posible a tus bases de datos. Si aún te quedan dudas piensa que, por lo general, las bases de datos albergan información necesaria para la continuidad de tu negocio. ¿Merece la pena dejar eso en manos inexpertas?

¿Qué hago para ser Administrador de Bases de Datos?

Un antiguo compañero (ahora amigo) solía decir que a DBA se llega por accidente y no le faltaba razón. Rara vez la gente sigue un plan formativo orientado a la administración de bases de datos. Estos son escasos, caros y, normalmente, están fuera de los planes de formación en las escuelas y universidades. La mayoría de los que nos dedicamos a esto hemos llegado aquí desde un puesto de soporte o de desarrollo. Tienes una base de datos que administrar, no sabes muy bien cómo pero empiezas a informarte y al final, a base de práctica y muchas horas de lectura, te especializas. Si has tenido suerte, un compañero te habrá enseñado lo necesario, aunque esto no te va a librar de las horas de práctica y lectura. 

Da igual si estás empezando o ya llevas tiempo como DBA, en las bases de datos, como en todo, es necesario aprender cosas nuevas día a día para no quedarse atrás. Internet está lleno de blogs como este (y mejores) donde formarte y aprender cosas nuevas.

¿Qué hace un DBA?

Seguro que has notado que durante todo este artículo hemos pasado rozando el tema de las funciones de un DBA. Es algo intencionado, detallaré en otro artículo lo que para mi es imprescindible en nuestro dia a dia. Sin embargo, no podemos dejar esto sin unas pinceladas sobre este tema. Como hemos hablado existen dos caminos, uno más orientado a infraestructura y otro más de rendimiento, conocido también como performance o devops en algunos sitios. No es buena idea centrarse solo en uno de esos dos caminos dejando de lado el otro. Por ejemplo, puedes ser el mejor administrando infraestructura pero cuando una consulta no rinde como se espera tienes que tener la capacidad de detectar el problema para no volverte loco mirando el servidor. De la misma manera, si sabes optimizar el código pero no el servidor vas a estar muy limitado a la hora de afrontar muchos casos. 

Un buen DBA debe implementar infraestructura, gestionar los accesos, diseñar y desplegar soluciones de alta disponibilidad, configurar una buena política de backups y planes de mantenimiento y solucionar problemas de rendimiento e incidencias. En resumen deberías tener el control de todo lo que está bajo tu responsabilidad y te pueda causar un problema en un futuro.

Conclusión

Para ser DBA necesitarás una buena base de informática, eso te facilitará mucho las cosas. Además, tendrás que dedicar tus esfuerzos en investigar y aprender cosas nuevas. Las bases de datos son un mundo apasionante, lleno de retos profesionales y puede llegar a ser muy gratificante. Por suerte tienes un montón de información disponible en multitud de páginas web. Eso sí, cuando te enfrentes a un problema no confíes en soluciones milagrosas (ejecuta este script y todo arreglado), duda, pregúntate qué te ha llevado al problema en el que estás, entiende por qué se hacen las cosas que te dicen en esa web y luego ya soluciona el error. 

Publicado por Roberto Carrancio en Otros, 4 comentarios

NIVELES DE AISLAMIENTO – Casos Prácticos

En esta segunda entrada sobre los niveles de aislamiento vamos a ver qué significa en la práctica lo que vimos en el post de ayer. Si aún no lo has leído te recomiendo que vayas primero a él para saber de lo que hablamos. Vamos a comparar el mismo caso práctico con los niveles de aislamiento READ UNCOMMITTED, READ COMMITTED y READ COMMITTED SNAPSHOT.

Para que todos podáis hacer las pruebas en vuestra instalación de SQL vamos a usar la base de datos de ejemplo AdventureWorks. AdventureWorks es una base de datos de ejemplo que proporciona Microsoft y que está disponible para descargar en su web. Tanto si estáis empezando a aprender SQL como si ya lleváis tiempo y queréis estar al día os recomiendo siempre que tengáis una instalación donde hacer pruebas con alguna base de datos de ejemplo. Otra buena base de datos que no debería faltar en vuestra instalación de pruebas es la versión SQL de los datos anonimizados de stackoverflow que proporciona Brent Ozar.

Caso Práctico

Este ejemplo es uno de los más típicos que nos vamos a encontrar en nuestro día a día como DBA. Vamos a simular 2 transacciones, la primera va a hacer una actualización de la tabla de personas y mientras la actualización esté en progreso una segunda transacción va a intentar leer los datos.

NIVEL DE AISLAMIENTO READ COMMITTED

SESIÓN 1SESIÓN 2NOTAS
Nivel de Aislamiento 1La primera sesión inicia una operación de escritura sobre la tabla. Se genera un bloqueo exclusivo sobre el registro.
Nivel de Aislamiento 2Cuando la segunda sesión va a leer se queda en espera, el intento de bloqueo compartido sobre el registro no es compatible con el bloqueo exclusivo de la transacción de la primera sesión.
rollbackLa transacción se aborta. Se genera un rollback y se libera el bloqueo exclusivo.
Nivel de Aislamiento 3Con el bloqueo exclusivo liberado la segunda sesión ya es capaz de devolver los datos solicitados. 

NIVEL DE AISLAMIENTO READ COMMITTED SNAPSHOT

SESIÓN 1SESIÓN 2NOTAS
Nivel de Aislamiento 1La primera sesión inicia una operación de escritura sobre la tabla. Se genera un snapshot del dato anterior a la transacción en TempDB
Nivel de Aislamiento 3Cuando la segunda sesión solicita ese registro lo puede recuperar del snapshot en TempDB.
rollbackLa transacción se aborta. Se genera un rollback y se elimina el snapshot.

NIVEL DE AISLAMIENTO READ UNCOMMITTED

SESIÓN 1SESIÓN 2NOTAS
Nivel de Aislamiento 1La primera sesión inicia una operación de escritura sobre la tabla. 
Nivel de Aislamiento 4Cuando la segunda sesión solicita ese registro lo lee directamente aunque se esté modificando.
rollbackLa transacción se aborta y se genera un rollback
Nivel de Aislamiento 3En una segunda lectura la sesión 2 recupera un dato diferente.

Conclusión

Hemos podido ver que significa leer datos sucios y qué implicaciones tiene. Además, hace unos días vimos también el peligro de las lecturas fantasma de NOLOCK que también se producen en el nivel de aislamiento READ UNCOMMITTED. Tras esta serie de artículos estamos preparados para elegir los niveles de aislamiento correctos para nuestras bases de datos. 

Ahí va mi recomendación personal: si tenemos que hacer una prueba o leer un dato puntualmente en un entorno productivo pero sin afectar a la producción podemos usar READ UNCOMMITTED. No deberíamos usar este nivel de aislamiento en ningún caso más. Usaremos un nivel de aislamiento READ COMMITTED SNAPSHOT si nuestra base de datos tiene un problema de bloqueos. Si estamos desarrollando una base de datos nueva mi recomendación también sería READ COMMITTED SNAPSHOT. Por el contrario, en la mayoría de los casos, si todo funciona con la configuración por defecto mejor dejarlo como está. Al fin y al cabo, un cambio que va a afectar a todas las transacciones requiere un esfuerzo en pruebas que rara vez nos será rentable si no es para solucionar un problema específico. 

Publicado por Roberto Carrancio en SQL Server, 0 comentarios
NIVELES DE AISLAMIENTO EN SQL SERVER

NIVELES DE AISLAMIENTO EN SQL SERVER

Como os prometí en el pasado artículo sobre el uso de NOLOCK hoy vamos a profundizar sobre los distintos niveles de aislamiento que implementa SQL Server. Es teoría básica de bases de datos, pero me parece imprescindible volver a ello frecuentemente y afianzar conceptos clave que marcarán el funcionamiento de nuestra base de datos. Aunque los niveles de aislamiento son algo común de todos los gestores de bases de datos, no todos implementan todos ni usan el mismo nivel por defecto. Aunque según el estándar SQL existen 4 niveles de aislamiento, en este artículo nos vamos a centrar en los niveles de aislamiento que implementa SQL Server. No solo porque es mi base de datos principal, sino también porque SQL Server implementa 5+1 niveles de aislamiento frente a los 3 que soporta Oracle o los 4 del estándar de PostgreSQL. 

Antes de profundizar en los niveles de aislamiento, hay que afianzar otra serie de conceptos básicos como las propiedades ACID de una base de datos y la gestión de concurrencia basada en bloqueos. 

Gestión de transacciones

Tenemos que entender las transacciones como la operación más básica del motor de base de datos. Son operaciones indivisibles y tienen que terminar completamente. Para entenderlo podemos compararlo con una transacción comercial, Tu pides un producto y esperas a que el vendedor te diga el precio. El vendedor te dice el precio y espera a que le des el dinero. Tu le das el dinero y esperas a que te de el producto. Si la transacción es correcta llegará hasta el final, pero si se detiene en cualquiera de las fases se volverá a la situación inicial donde tu tienes el dinero pero no el producto. 

Con este ejemplo en mente vamos a explicar lo que son las propiedades ACID (siglas en inglés de Atomicidad, Consistencia, Aislamiento y Durabilidad).

  • Atomicidad: Como hemos dicho, las transacciones son la operación básica de las bases de datos y deben ser indivisibles. Al igual que en nuestro ejemplo de la compra, para que la operación se finalice se tienen que completar todos los pasos de la transacción.
  • Consistencia: Toda transacción debe mantener la coherencia de la base de datos. Si no termina correctamente tiene que hacer rollback (deshacer los cambios) y volver al estado original. Es lo mismo que cuando decíamos que si nuestra compra se interrumpe volvemos a tener el dinero pero no el producto.
  • Aislamiento: Cada transacción es independiente de las demás. El comportamiento de esta característica cambiará en función del nivel, que es lo que vamos a ver más adelante. En nuestro ejemplo, nuestra compra no se ve afectada por las demás compras.
  • Durabilidad: Todas las transacciones tienen que estar registradas en la base de datos y permanecer en ella después de una interrupción de servicio. Cuando el servicio se reanude, las transacciones confirmadas se verán reflejadas en la base de datos, mientras que las no confirmadas sufrirán un rollback.

Gestión de concurrencia

Tipos de bloqueos

Por defecto, SQL Server implementa los bloqueos para garantizar el aislamiento de las transacciones. En este contexto podemos encontrarnos con dos tipos de bloqueos, los bloqueos compartidos y los bloqueos exclusivos. Entenderemos el bloqueo compartido como el tipo de bloqueo para operaciones de lectura y los bloqueos exclusivos como los bloqueos para las escrituras. 

Compatibilidad entre bloqueos

Cada operación de lectura generará un bloqueo compartido sobre el recurso que lea. Pueden existir varias operaciones de lectura simultáneas sobre un mismo recurso y cada una de ellas generará un bloqueo compartido. Las operaciones de escritura, sin embargo, generarán un bloqueo exclusivo, ya que mientras hay una escritura en curso no puede haber más operaciones (ni lecturas ni escrituras) sobre ese recurso. 

Cuando se inicia una operación de escritura, intentará generar un bloqueo exclusivo en el recurso afectado. Si existen bloqueos (compartidos o exclusivos) en el recurso este intento de bloqueo exclusivo no podrá iniciarse y esperará a que termine el resto de transacciones.

Niveles de aislamiento

Como a estas alturas ya sabrás, los niveles de aislamiento son una forma de controlar el acceso concurrente a los datos de una base de datos, es decir, cómo se comporta el sistema cuando varios usuarios o procesos intentan leer o modificar los mismos registros al mismo tiempo. Los niveles de aislamiento afectan al rendimiento y a la consistencia de los datos, así que vamos a verlos en detalle.

Read uncommitted isolation

Este es el nivel más bajo de aislamiento, permite leer los datos que están siendo modificados por otras transacciones, incluso si éstas no han terminado o confirmado sus cambios. Esto puede provocar problemas como lecturas sucias, lecturas no repetibles o lecturas fantasma, que veremos más adelante. Este nivel tiene el mejor rendimiento, pero el peor nivel de consistencia. Es el equivalente al uso de NOLOCK que vimos en el post anterior.

Read committed isolation

Este es el nivel predeterminado de SQL Server. Impide leer los datos que están siendo modificados por otras transacciones hasta que éstas terminen y confirmen sus cambios. Esto evita las lecturas sucias, pero no las lecturas no repetibles o las lecturas fantasma. Este nivel tiene un buen equilibrio entre rendimiento y consistencia, pero puede no ser suficiente para algunas operaciones críticas.

Read committed snapshot isolation (RCSI)

Este es el nivel predeterminado de Azure SQL Database y de Oracle, por ejemplo. Es, simplemente, una variación de Read Committed que en vez de generar bloqueos genera snapshots. Los snapshots son la versión original de los datos modificados, se almacenan en tempdb mientras dure la transacción bloqueante. El resultado es que una transacción de lectura nunca bloqueará a una escritura y viceversa. Se diferencia de read uncommitted en que, aunque el dato que estás leyendo pueda estarse cambiando, lo que lees si que ha sido un dato confirmado en algún momento.

Repeatable read isolation

Este nivel garantiza que si una transacción lee un registro, nadie podrá modificarlo hasta que la transacción termine. Esto evita las lecturas no repetibles, pero no las lecturas fantasma. Este nivel tiene un peor rendimiento que el anterior, ya que bloquea más registros y puede generar más contención.

Serializable isolation

Este es el nivel más alto de aislamiento, que impide cualquier modificación concurrente de los datos que lee una transacción. Esto evita tanto las lecturas no repetibles como las lecturas fantasma, pero tiene el peor rendimiento y el mayor riesgo de bloqueos y esperas.

Snapshot isolation

Este nivel permite leer los datos tal y como estaban al inicio de la transacción, sin importar si otros usuarios o procesos los han modificado después. Esto evita todos los problemas de consistencia mencionados, pero tiene un mayor coste de almacenamiento y procesamiento, ya que requiere mantener varias versiones de los datos en la base de datos. Puede generar errores cuando concurren varios procesos de escritura.

A modo resumen podemos ver estas dos tablas:

* Snapshot es un nivel de aislamiento solo a nivel de transacción. En caso de colisión en la escritura devuelve un error.
** SERIALIZABLE También bloquea la inserción de registros nuevo

Problemas de no elegir el nivel de aislamiento correcto

Hemos hablado de que los niveles de aislamiento nos puede ocasionar una serie de problemas como lecturas sucias, lecturas no repetibles y lecturas fantasma, pero, ¿qué son estos términos?

Lectura sucia: No es leer “50 sombras de Grey”. Ocurre cuando una transacción lee un dato que está siendo modificado por otra transacción, pero ésta no ha confirmado sus cambios. Por ejemplo, si la transacción A modifica el precio de un producto, pero no lo confirma, y la transacción B lee ese precio, puede obtener un valor incorrecto o inconsistente.

Lectura no repetible: Ocurre cuando una transacción lee dos veces el mismo dato, pero obtiene valores distintos porque otra transacción lo ha modificado entre medias. Por ejemplo, si la transacción A lee el stock de un producto, luego la transacción B lo reduce al comprarlo, y la transacción A lo vuelve a leer, obteniendo un valor menor al esperado.

Lectura fantasma: Ocurre cuando una transacción lee un conjunto de datos que cumple cierto criterio, pero luego otra transacción inserta o elimina registros que también cumplen ese criterio. Por ejemplo, si la transacción A cuenta el número de clientes que viven en una ciudad, luego la transacción B añade o borra clientes de esa ciudad, y la transacción A vuelve a contarlos, puede obtener un número diferente al inicial.

Conclusión

Como hemos visto, elegir el nivel de aislamiento ideal para nuestra base de datos es un pulso entre rendimiento y coherencia de los datos. Recuerda que debes elegir el nivel adecuado para cada caso, teniendo en cuenta las ventajas e inconvenientes de cada uno. Un nivel de aislamiento serializable sería lo más seguro pero prácticamente imposibilita la concurrencia entre varios procesos, mientras que un Read Uncommitted ofrece el mejor rendimiento a un precio demasiado alto.

A partir de aquí, en tu mano está elegir el nivel de aislamiento ideal para tu base de datos. Solo espero que este post te haya ayudado a entender mejor qué son los niveles de aislamiento en SQL Server y cómo afectan a la consistencia y al rendimiento de tu base de datos. Si tienes alguna duda o comentario, puedes dejarlo abajo en los comentarios, mandarme un mail o contactarme por Twitter. 

Publicado por Roberto Carrancio en SQL Server, 7 comentarios
¿Qué es NOLOCK y por qué no debes usarlo?

¿Qué es NOLOCK y por qué no debes usarlo?

SQL Server implementa varios niveles de aislamiento sobre los que hablaremos más en profundidad en un futuro post, aunque por defecto se implementa el nivel READ COMMITTED o lecturas confirmadas. Sin embargo, esto se puede cambiar a nivel base de datos, transacción o incluso para una tabla dentro de una misma transacción. Hoy nos vamos a centrar en este último caso para lo que vamos a usar el HINT NOLOCK. Vamos a ver casos prácticos de uso aunque antes aclararemos algunos conceptos básicos.

Primero de todo, ¿qué es un HINT?

Un HINT (en español sugerencia de consulta) es un parámetro que indicamos a la hora de escribir nuestras consultas SQL y modifican el comportamiento del optimizador de consultas y del motor de base de datos. En SQL Server tenemos HINTS de 3 tipos: los HINTS de combinación, para especificar el tipo de JOIN que va a aplicar el motor de base de datos (Loop, Merge, Hash o Remote). Los HINTS de consulta, que se aplican con la cláusula OPTION y afectan a todos los operadores de la consulta y, por último, los HINTS de tabla que requieren la cláusula WITH y se usan para invalidar el comportamiento predeterminado del optimizador de consultas sobre esa tabla durante la instrucción DML. 

Los HINT de tabla se pueden aplicar sin la cláusula WITH aunque esto es una característica en desuso que dejará de tener compatibilidad en futuras versiones de SQL Server. Deberemos declarar la cláusula WITH para asegurarnos la futura compatibilidad de nuestro código.

WITH (NOLOCK) un poco (más) de teoría

Entrando ya en lo que nos ocupa, NOLOCK es, como hemos podido ver, un HINT de tabla que le dice al motor de base de datos que no mire ni aplique bloqueos sobre esa tabla. En resumidas cuentas, es como si leyéramos nuestra tabla en un nivel de aislamiento READ UNCOMMITTED. 

Así, a priori, puede parecer una buena idea usarlo, no bloqueos significa menos tiempos de espera y hasta menos consumo de recursos al no tener que dedicar esfuerzos en gestionar los bloqueos de filas, páginas o tablas. Podemos pensar, también, que los datos que estamos leyendo no cambian y por eso no nos preocupa. Sin embargo, NOLOCK tiene un “problema” y son las lecturas fantasma (no te preocupes si no entiendes nada, lo vamos a ver en la práctica).

Demostración

Preparación de un entorno de laboratorio

Para comprobar cómo funciona NOLOCK y sus efectos vamos a crear una tabla que vamos a llamar FrasesDeEmpresa. A continuación, vamos a añadirle 10.000 registros con una frase que normalmente se ha dicho más de 10.000 veces en todas las empresas del mundo: “ESTO ES URGENTE”

Uso de NOLOCK

Tenemos creada nuestra tabla FrasesDeEmpresa con sus 10.000 registros. Pongamos que alguien decide cambiarla y ahora la frase más escuchada es “Si funciona no lo toques”. Supongamos también que mientras alguien está cambiando todos los registros nosotros queremos leerlo. Como hemos dicho el comportamiento normal de SQL es READ COMMITTED así que hasta que quién está escribiendo no termine nosotros no podemos leer y sufriremos un bonito bloqueo.

Oh vaya, lecturas confirmadas significa que no puedo leer hasta que el que escribe no confirme que ha terminado. ¿Quién lo iba a decir? Esto era urgente así que voy a usar NOLOCK y voy a leer lo que haya en ese momento aunque esté a medias.

Problemas de NOLOCK

Como hemos visto gracias al HINT NOLOCK hemos podido leer lo que se estaba escribiendo. El problema viene si por lo que sea la transacción de escritura no termina y deja todo como estaba, habríamos leído una información que nunca ha sido correcta. Pero hay más, como os decía antes este no es el único problema de NOLOCK, podemos tener las denominadas lecturas fantasmas. Esto es que por leer datos que se están manipulando nos encontremos con más o menos registros de los que verdaderamente hay. Veamos un ejemplo:

¿Qué ha pasado aquí? Nosotros teníamos 10.000 registros y solo los estaban actualizando. No se ha borrado ninguno y sin embargo nuestra cuenta ha contado un registro menos la mayoría de las veces.

Para entender esto tenemos que entender el comportamiento de los índices clustered. Si os fijáis, cuando he definido la tabla he definido el campo id como Primary Key lo que automáticamente lo convierte en índice clustered. Los datos están almacenados en mi disco duro ordenados por id. Cuando yo voy recorriendo todos los registros de mi tabla FrasesDeEmpersas para contar mientras otro mueve los registros de sitio me puedo encontrar con que un registro que ya he leido se mueve hacia delante y lo cuento 2 veces o con el caso contrario, que un registro que voy a leer simplemente ya no está ahí porque está detrás. Esto es lo que se conoce como lecturas fantasma y es el verdadero problema de NOLOCK y del nivel de aislamiento READ UNCOMMITTED.

Conclusión

A veces nos podemos sentir tentados de usar lecturas sucias para evitar bloqueos. Cuando esto pase, lo mejor es que dejemos lo que estamos haciendo, vayamos a tomar una cerveza y esperemos a que se nos pase. Siento ser tan tajante pero para mi no es una opción una configuración que pone en peligro cualquiera de las propiedades ACID de nuestra base de datos. Existen alternativas a los bloqueos como el nivel de aislamiento READ COMMITTED SNAPSHOT (el que implementa Oracle y no se ha acabado el mundo) que veremos en futuras entradas del blog y que nos solucionarán el problema sin poner el peligro la integridad de nuestros resultados. 

Publicado por Roberto Carrancio en SQL Server, 5 comentarios
VISTAS INDEXADAS DE SQL SERVER

VISTAS INDEXADAS DE SQL SERVER

Las vistas son tablas virtuales que nos devuelven datos de una consulta sobre una o varias tablas. Igual que una tabla tiene sus columnas y sus filas pero al contrario que estas ese conjunto de datos como tal no está almacenado en ningún sitio. Cada tabla tiene sus datos y la vista los lee de ahí. Entonces, ¿los resultados de datos de las vistas no se guardan en ningún sitio? En realidad hay algunos tipos de vistas que sí guardan los datos finales como es el caso de las vistas materializadas que implementan algunos gestores de bases de datos (Oracle, por ejemplo). En el caso de SQL Server este tipo de vista no está disponible, aunque no podemos descartar que se implemente en un futuro (en Azure Synapse Analytics han existido desde siempre).

¿Qué alternativa tenemos en SQL Server?

Como hemos visto antes, las vistas las vemos como si fueran una tabla pero en realidad no tienen datos, los recuperan dinámicamente de las tablas a las que se referencia. Esto es muy útil en la mayoría de los casos ya sea por simplicidad de las consultas, para abstraernos de la estructura original y simplificar la estructura saliente o para gestionar permisos. Sin embargo el uso de una vista no afecta en nada al rendimiento pues ejecuta la consulta tal cual como si la escribiéramos a mano. Si una vista lee sobre varias tablas grandes generará mucho consumo de E/S y si la definición de la vista incluye procesamientos complejos y muchas uniones entre tablas tendremos una notoria degradación de rendimiento.

Como alternativa, en SQL Server podemos hacer uso de un tipo de vista especial que son las Vistas Indexadas (o indizadas), son vistas que tienen un índice clustered por lo que si van a almacenar el conjunto de resultados en la base de datos para poder hacer una lectura plana.

Dónde usar las vistas indexadas

Las vistas indexadas ofrecen un rendimiento de lecturas mejorado al hacer uso del índice para leer los datos y no tener que ejecutar la consulta subyacente. Sin embargo, nos pueden llegar a penalizar considerablemente las operaciones de escritura al añadir no sólo otro índice donde escribir los datos sino complejidad a ese índice. Adicionalmente podremos crear tantos índices nonclustered sobre la vista como necesitemos. Al igual que ocurre con los índices de las tablas en nuestra mano queda medir el coste/beneficio y valorar su idoneidad.

Con las vistas indexadas notaremos una mejora sustancial en el rendimiento de nuestras consultas si las aplicamos sobre entornos con una gran diferencia de lecturas frente a escrituras, se me viene a la cabeza sobre todo entornos Data Warehouse, bases de datos OLAP o entornos de minería de datos. Rara vez serán recomendables en entornos con alta carga de transacciones IUD (insert, update y delete) en bases de datos OLTP.

Limitaciones de las vistas indexadas

Como ya hemos visto uno de los inconvenientes de las vistas indexadas es que la degradación en rendimiento de las escrituras es mayor que la mejora en las lecturas, esto nos limita en gran medida su uso. Sin embargo no es su única limitación, la verdad es que tienen una amplia lista de incompatibilidades y requisitos. Uno de los principales requisitos de las vistas indexadas es que hay que crearlas con la opción SCHEMABINDING esto implica que no se podrán modificar las tablas referenciadas.

Consideraciones para crear vistas indexadas

Además de tener que crear la vista como SCHEMABINDING tenemos que tener en cuenta otros aspectos importantes:

  • Las vistas indexadas no admiten expresiones no deterministas. Es decir, las expresiones de la vista siempre deben devolver el mismo resultado no como GETDATE() que nos devolvería un valor distinto en cada ejecución.
  • Las tablas y funciones dentro de la vista deben declararse con el nombre completo (esquema.tabla).
  • No se admiten subconsultas.
  • No se admiten OUTER JOINS, esto deja fuera RIGHT JOIN y LEFT JOIN.
  • El índice clustered de nuestra vista ocupará espacio en disco.
  • Solo se puede hacer referencia a tablas de la misma base de datos.
  • Si tenemos GROUP BY, la definición de la vista debe contener COUNT_BIG(*), pero no HAVING.
  • No se puede usar EXISTS, NOT EXISTS, COUNT(*), MIN, MAX, hints de tablas, TOP ni UNION.
  • No puede utilizar los tipos de datos text,  ntext ,  image o  XML. El tipo de datos float se puede utilizar en la vista, pero no en el índice agrupado

Como crear vistas indexadas

Para crear una vista indexada lo primero que haremos será crear la vista con la opción SCHEMABINDING 

Una vez que tenemos creada la vista tendremos que crear el índice clustered.

En este punto el optimizador de consultas podrá usar nuestro índice para cualquier consulta sobre la tabla, incluso para consultas sobre las tablas sin que se use la vista aunque, esto último, sólo en ediciones Enterprise de SQL Server.

Conclusiones

Un gran poder conlleva una gran responsabilidad y las vistas indexadas son una increíble herramienta en entornos o tablas con gran cantidad de lectura y pocas modificaciones pero si no es así nos pueden hacer mucho daño al servidor. El uso de vistas indexadas de SQL Server puede ser una buena técnica para mejorar el rendimiento de las consultas al reducir el costo de E/S y la duración de las consultas, pero requiere pruebas, planificación y un estudio pormenorizado de donde usar vistas indexadas. Se debe realizar un análisis completo del impacto en el rendimiento, midiendo las mejoras en el rendimiento de lecturas frente al coste en las escrituras.

Publicado por Roberto Carrancio en Rendimiento, SQL Server, 4 comentarios
BABELFISH PG Porque hay vida más allá de SQL Server

BABELFISH PG Porque hay vida más allá de SQL Server

Cada vez que toca renovar licencias de SQL Server hay una pregunta recurrente de todos mis clientes: ¿Y si migramos a PostgreSQL y nos ahorramos este dinero? Normalmente, quien me hace esta pregunta espera de mí un tajante NO. Sin embargo, hasta ahora mi respuesta siempre había sido: “Es una opción, claro. PostgreSQL es un excelente gestor de bases de datos y, si estás desarrollando una nueva aplicación y no tienes esa camisa de fuerza que es migrar todo tu código, me parece perfecto. Eso sí, asegúrate de tener un buen soporte.” Ahora bien, a día de hoy, BABELFISH for PostgreSQL ha mejorado lo suficiente como para hacerme cambiar esta respuesta. 

¿Qué es BABELFISH?

Empecemos por el principio, Babelfish es un complemento para PostgreSQL y ahora también para Aurora PostgreSQL (Amazon) que nos permite utilizar nuestra misma cadena de conexión SQL Server y nuestro código T-SQL sobre una base de datos de Postgre. Además de este “traductor” incorpora una funcionalidad de migración de nuestros datos desde cualquier versión licenciada de SQL hacía PostgreSQL.

Esquema de Babelfish

¿Cómo funciona BABELFISH?

Paso 1. Instalación:

Como es lógico para empezar a trabajar con Babelfish lo primero que debemos hacer es instalarlo, para lo que necesitaremos un sistema operativo linux. Es importante destacar que la instalación de babelfish incluye la instalación de una versión de PostgreSQL con los componentes necesarios para su funcionamiento y no funcionará con una instalación de PostgreSQL desde cualquier otra fuente. Por suerte, el bundle de instalación de Babelfish incluye un fichero con las instrucciones detalladas paso a paso para completar la instalación de manera exitosa, eso sí, las instrucciones de instalación son para Ubuntu y los pasos pueden diferir ligeramente en otras distribuciones.

En caso de que queramos una versión cloud, Babelfish es una capacidad integrada de Amazon Aurora y no tiene coste adicional. Se puede habilitar Babelfish en Amazon Aurora desde la consola de administración de RDS.

Paso 2. Configuración:

Una vez concluida la instalación, es el momento de conectar a PostgreSQL y empezar a configurar todo. Para empezar crearemos un usuario que será propietario de la base de datos de muestra. Crearemos también la base de datos de muestra y definiremos si Babelfish va a trabajar en modo base de datos única o va a admitir varias bases de datos. Esta configuración no se va a poder cambiar por lo que si elegimos la opción single-db debemos estar muy seguros.

Paso 3. Migración:

Ahora que ya tenemos todo instalado y configurado toca entrar en materia y migrar los datos de nuestro SQL Server. Para la migración tenemos dos opciones otra vez, modo base de datos única o modo de múltiples bases de datos. Cada uno de los modos de migración tiene sus pros y sus contras y una vez más, una vez elegido uno no lo podremos cambiar. La primera vez que iniciemos Babelfish se crearán una base de datos master y una tempdb, si teníamos objetos creados en la master deberemos recrearlos en esta. En cuanto a la tempdb una vez creada no se borrará nunca al contrario de lo que pasa en SQL Server.

En el modo de migración de base de datos única, los nombres de los esquemas se crean tal cual, por lo que si el objetivo es terminar migrando a PostgreSQL nativo tendremos que terminar haciendo cambios en el código. Si este es nuestro objetivo (que, a estas alturas, debería serlo) es recomendable mover todas las tablas al esquema DBO en SQL Server antes de la migración.

Tendrás que elegir el modo de migración de múltiples bases de datos si quieres migrar varias bases de datos, si no tienes claras tus necesidades futuras o si lo que quieres es migrar varias bases de datos de usuarios juntas y el objetivo final no es realizar una migración PostgreSQL.

Siguientes pasos y conclusiones

En este punto ya estamos preparados para empezar a trabajar con Babelfish for PostgreSQL de manera transparente como si de un SQL Server se tratara, esto nos permitirá ir migrando gradualmente nuestras aplicaciones hasta conseguir un funcionamiento con PostgreSQL Nativo y podremos reinvertir el dinero ahorrado en licencias de SQL Server en un mejor hardware y/o en un soporte de alto nivel para PostgreSQL.

Publicado por Roberto Carrancio en Otros, 1 comentario