Social Icons

twitter facebook google plus linkedin

viernes, 28 de septiembre de 2012

Contained Databases en SQL Server 2012

Es muy común que una base de datos, en algún momento de su existencia y por razones particulares, tenga que ser llevada hacia otro servidor SQL Server. El proceso es simple. Hay que exportar la base de datos hacia el servidor de destino y listo. No tiene mucha complicación ni ciencia alguna. Todos sabemos que este escenario ideal no existe. Nunca una migración va a ocurrir de esta forma. Siempre algo que requerirá más trabajo, que son los objetos a nivel de aplicación.

Una Contained Database guarda absolutamente todos sus objetos dentro de la base de datos, cosa que cuando sea necesario levantar la base de datos, lo pueda hacer sin problema alguno. O sea, no tiene dependencias.

Una contained database almacena lo siguiente:

  • Tables

  • Functions

  • Constraints

  • Schemas

  • Types

  • Logins

  • Application-Level Agent Job

  • Persisted error messages

  • Linked server information

  • System Settings


Y soporta ambas autenticaciones.

Para habilitar el login hacia contained databases, se debe ejecutar el siguiente código:


sp_configure 'show advanced', 1;
RECONFIGURE WITH OVERRIDE;
go
sp_configure 'contained database authentication', 1;
RECONFIGURE WITH OVERRIDE;
go


Para crear una base de datos contenida, se puede hacer via código:


CREATE DATABASE [MiDB] CONTAINMENT = PARTIAL


O se puede hacer a través del asistente:

[caption id="attachment_1415" align="alignnone" width="300"]Creacion de un usuario a través de wizard Creacion de un usuario a través de wizard[/caption]

Para crear un usuario se hace usan las mismas instrucciones como si fuera una base de datos común y corriente:


USE MiDB
GO
CREATE USER MiUSER WITH PASSWORD = 'TEST123!!'
GO


En conclusión, una contained db es una base de datos común y corriente, pero se diferencia de las demás porque almacena todos los objetos necesarios para funcionar en cualquier instancia de SQL Server 2012.

viernes, 21 de septiembre de 2012

Diferencia entre SELECT @@IDENTITY, SELECT SCOPE_IDENTITY() y SELECT IDENT_CURRENT('tabla')

Hola Mundo

No es una novedad que en los motores de bases de datos exista una función que sirva para generar números de forma correlativa, o bien, definiendo un inicio y un incremento. Por ejemplo, en MySQL existe auto_increment y en SQL Server se llama identity.

Aprovecho estas líneas para tirar las orejas de aquellos desarrolladores que usan estas funciones de auto incremento como claves primarias. Hay muchas funciones que generan valores únicos y que son justamente para eso.

Volviendo al tema. En SQL Server existen 3 funciones que permiten saber el último número generado con identity. Estas funciones se ámbito en el ámbito en el cual operan.

SELECT @@IDENTITY

Esto devolverá el último valor generado con identity. No importa donde haya sido, simplemente lo mostrará.

SELECT SCOPE_IDENTITY()

Devolverá el último valor generado en el ámbito. Por ejemplo, si se está trabajando dentro de un trigger, devolverá el último valor que identity generó dentro del trigger.

SELECT IDENT_CURRENT('tabla')

Devolverá el último valor generado en la tabla que se especifica.

 

Ojalá que les sirva.

 

Chau

jueves, 6 de septiembre de 2012

Duplicar datos tabla en la misma tabla (Y como comerse la memoria y el disco de forma brutal)

Hoy estaba jugando con mi SQL Server, obviamente en entorno de pruebas,  y tuve la "brillante" idea de duplicar los datos de una tablas de hecho de AdventureWorksDW. Aparte de lograr que los registros se duplicaran, noté bastantes cosas que quiero compartir con ustedes.

Importante: Antes de duplicar los datos dentro de la misma tabla, debes desactivar las claves primarias. De lo contrario, arrojará un error. Recomiendo copiar los datos hacia una tabla temporal.

Sentencias:

INSERT INTO tabla SELECT * FROM tabla
Esta es la sentencia básica. Lo que hace es seleccionar todos los registros y volverlos a insertar. O sea, si se tienen 10 registros, insertará esos mismos 10 registros, quedando así con 20 registros. Ésta es la forma mas básica que hay.

INSERT INTO tabla SELECT top 100 * FROM tabla
Esta selecciona los 100 primeros registros y las inserta. O sea, si se tienen 1000 registros, insertará los primeros 100 registros, quedando así con 1100 registros.

INSERT INTO tabla SELECT * FROM tabla WHERE campo1 = 'algo'
Esta sentencia selecciona e inserta solo los registros donde la clausula WHERE se cumpla. No importa cuantos registros sean.

INSERT INTO tabla SELECT top 100 * FROM tabla WHERE campo1 = 'algo'
Esta hace lo mismo que la anterior, pero solo tomando en cuenta los 100 primeros registros.

Nunca hagas esto (a no ser de que sepas muy bien lo que estás haciendo)

Puedes hacer un sencillito script que duplique de forma exponencial los registros, causando un excesivo uso de disco y recursos de memoria. Con esta operación, el log de transacciones crece de forma desmesurada.


DECLARE @contador int
SET @contador = 0
WHILE (@contador < 10)
BEGIN
INSERT INTO tabla SELECT * FROM tabla
SET @contador = @contador + 1
END
GO

Si tenemos una tabla de 1000 registros, la primera vez insertará 1000 registros, quedando así con 2000 registros. La segunda vez, seleccionará los 2000 registros y los insertará, quedando así con 4000 registros. Esto ocurrirá hasta que se cumpla la condición (Imagina este escenario, pero  partiendo con 60000 registros)

Para finalizar quiero exponer algunas conclusiones:

  1. Nunca realices experimentos así en entornos de producción.

  2. Siempre ten un respaldo de las bases de datos.

  3. Ten controlado el crecimiento del log de transacciones. Hay mucha documentación al respecto.

  4. Si vas a duplicar los datos de tu tabla, hazlo de manera controlada y no de forma brutal (como lo hice yo)


Chau!