miércoles, 4 de junio de 2014

Quitar AUTO_CLOSE de Bases de Datos SQL Server

En SQL Server 2008 R2 existe una propiedad de las bases de datos llamada AUTO_CLOSE. Dicha propiedad hace, mientras esté activa (ON), que si una base de datos deja de ser accedida por alguna conexión se cierre, es decir entra en un estado de reposo por decirlo de alguna forma. Esto hace que cuando una conexión intente acceder a esta base de datos, SQL Server 2008 R2 deba realizar una serie de comprobaciones para "despertar" a la base de datos.

Todo esto se traduce en una sensación de lentitud al conectar con la base de datos. Para solucionarlo, podemos ejecutar el siguiente código:

01 USE [master]
02 GO
03 ALTER DATABASE [MiBaseDeDatos] SET AUTO_CLOSE OFF
04 GO

De esta forma, optimizamos el rendimiento de nuestras bases de datos, y lo más importante, es que no tiene ningún inconveniente. De hecho, es posible que en futuras versiones de SQL Server, esta configuración no exista y la base de datos este siempre "Despierta"  (AUTO_CLOSE = OFF).

martes, 3 de junio de 2014

Uso de Google Maps en aplicación Web con MVC4

Vamos a implementar una miniaplicación que mostrará diferentes puntos de interés turístico en nuestra aplicación usando las API de Google Maps. Además vamos a darle diferentes colores a los marcadores según el tipo de punto de interés de que se trate.  Para ello vamos a seguir los siguientes pasos.

Creamos un nuevo proyecto "Aplicación web ASP.NET" en Visual Studio 2013 y seleccionamos la plantilla MVC4. Ahora añadimos el siguiente script a la vista Views/Home/index.cshtml. De esta forma nos aseguramos que solo se cargarán estas librerías si ejecutamos esta vista en concreto.

01 <script src="http://maps.google.com/maps/api/js?sensor=true" type="text/javascript"></script> 

Ahora vamos a darle estilo al contenedor del mapa para asegurarnos que se vea correctamente y también vamos a darle estilo a la ventana emergente que aparecerá al hacer clic sobre los puntos de interés que coloquemos en el mapa. Esta porción de código CSS, podemos incluirla en nuestra hoja de estilo, pero en este ejemplo por comodidad lo incluiremos directamente en la vista. (Views/Home/index.cshtml)
01 <style>
02     #map_canvas img {
03         max-width: none;
04     }
05 
06     .infoDiv {
07         height: 300px;
08         width: 300px;
09         -webkit-user-select: none;
10         background-color: white;
11         border-style: solid;
12         border-color: red;
13         color: red;
14     }
15 </style>
A continuación creamos el contenedor del mapa, para ello nos vamos  nuevamente a Views/Home/index.cshtml y añadimos el siguiente código HTML.

01 <div id="map_canvas" style="height: 600px;"></div>

Por último tenemos que generar los puntos de interés, para ello usaremos jQuery para llamar a la función "mostrarMapa()" una vez se haya cargado la pagina. Este código lo escribiremos en cualquier parte de la página entre las conocidas etiquetas <script type="text/javascript"></script>, aunque suele ser común ponerlo al final.

01  $(document).ready(function () {
02             mostrarMapa();
03         });

El código de la función "mostrarMapa()" puede ser algo parecido a lo siguiente:

01 function mostrarMapa() {
02         
03 
04         //definimos el punto central en el mapa
05         google.maps.visualRefresh = true;
06         var puntoInicial = new google.maps.LatLng(37.388308, -5.995510);
07         
08         var mapOptions = {
09             zoom: 14,
10             center: puntoInicial,
11             mapTypeId: google.maps.MapTypeId.G_NORMAL_MAP
12         };
13         //creamos el mapa
14         var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
15         
16         //esto son los datos de los puntos de interes en JSON, que bien podría venir de un servicio Rest, una base de datos, o cualquier otro origen de datos.
17         var data = [
18                   { "Id": 1, "tipo": "Monumento", "PuntoDeInteres": "Torre del Oro", "Descripcion": "La Torre del Oro de Sevilla es una torre albarrana situada en el margen izquierdo del río Guadalquivir, junto a la plaza de toros de la Real Maestranza.", "Long": "37.382446", "Lat": "-5.996472" },
19                   { "Id": 2, "tipo": "Restaurante", "PuntoDeInteres": "La mia tana", "Descripcion": "Pizza, pasta y risotto en un restaurante italiano decorado con originales cuadros que se salen del lienzo", "Long": "37.390723", "Lat": "-5.991137" },
20                   { "Id": 3, "tipo": "Interes turistico", "PuntoDeInteres": "Plaza de España", "Descripcion": "La plaza de España de Sevilla es un gran espacio abierto monumental rodeado por un edificio semicircular de estilo regionalista.", "Long": "37.377059", "Lat": "-5.987319" },
21                   { "Id": 4, "tipo": "Monumento", "PuntoDeInteres": "Catedral de Sevilla", "Descripcion": "es la catedral gótica cristiana con mayor superficie del mundo. La Unesco la declaró en 1987, junto al Real Alcázar y el Archivo de Indias, Patrimonio de la Humanidad 2 y, el 25 de julio de 2010, Bien de Valor Universal Excepcional.", "Long": "37.385839", "Lat": "-5.993128" }
22                ];
23 
24         //Ahora recorremos los datos y uno a uno vamos estableciendo los puntos sobre el mapa.
25         $.each(data, function (i, item) {
26 
27             var punto = new google.maps.LatLng(item.Long, item.Lat);
28             
29             var marker = new google.maps.Marker({
30                 'position': punto,
31                 'map': map,
32                 'title': item.PuntoDeInteres                
33             });
34             
35             //ponemos los marcadores de diferentes colores según el tipo de punto turistico de que se trate.
36             if (item.tipo == "Monumento")
37                 marker.setIcon('http://maps.google.com/mapfiles/ms/icons/blue-dot.png');
38             else if (item.tipo == "Restaurante")
39                 marker.setIcon('http://maps.google.com/mapfiles/ms/icons/green-dot.png');
40             else if (item.tipo == "Interes turistico")
41                 marker.setIcon('http://maps.google.com/mapfiles/ms/icons/red-dot.png');
42             else
43                 marker.setIcon('http://maps.google.com/mapfiles/ms/icons/yellow-dot.png')
44                        
45 
46             //añadimos informacion adicional sobre el punto en question, que se nos mostrará al hacer click sobre este.
47             var infowindow = new google.maps.InfoWindow({
48                 content: "<div class='infoDiv'><h2>" + item.PuntoDeInteres + "</h2>" + "<h3>" + item.tipo + "</h3>" + "<div><h4> " + item.Descripcion + "</h4></div></div>"
49             });
50 
51             google.maps.event.addListener(marker, 'click', function () {
52                 infowindow.open(map, marker);
53             });
54 
55         })        
56     }

Puede descargar el ejemplo aquí.

lunes, 8 de julio de 2013

SQL SERVER 2008 R2: Limitar conexiones de inicios de sesión con Triggers DDL.

Hay veces que es interesante impedir que un Inicio de Sesión  establezca más de una conexión con el servidor. Para ello SQL Server 2008 R2 incorporar los llamados Desencadenadores (triggers) DDL. Este artículo nos servirá para poner un ejemplo de estos interesantes triggers, que a diferencia de los que usamos normalmente, que se disparan al realizar modificaciones, inserciones o borrados de datos de una tabla, estos se disparan ante alteraciones en la estructura de la base de datos, por ejemplo, o cualquier otro evento sobre el servidor.

Según la MSDN de microsoft, un Desencadendor DDL es: "Los desencadenadores DDL se inician en respuesta a una variedad de eventos de lenguaje de definición de datos (DDL). Estos eventos corresponden principalmente a las instrucciones de Transact-SQL que comienzan por las palabras clave CREATE, ALTER, DROP, GRANT, DENY, REVOKE o UPDATE STATISTICS. Algunos procedimientos almacenados del sistema que ejecutan operaciones de tipo DDL también pueden activar desencadenadores DDL". Podéis encontrar mas información aquí.

Centrandonos en el ejemplo:  Vamos a limitar que un inicio de sesión no pueda realizar mas de tres conexiones simultaneas al Servidor de SQL Server 2008 R2. Para ello vamos a programar un trigger DDL sobre el Inicio de Sesión deseado y el evento de LOGON.

Lo primero que hacemos es crear un nuevo Inicio de Sesión con el Management Studio, para ello hacemos click derecho sobre la carpeta "Seguridad", luego en Nuevo/Inicio de Sesión. Lo configuramos como en la imagen.


Ahora vamos a darle todos los permisos posibles, es decir, será administrador.



Creamos por último el trigger DDL para controlar el número de conexiones:


01 USE master;
02 GO
03 CREATE TRIGGER limite3conexiones_usuarioLimitado
04 ON ALL SERVER WITH EXECUTE AS 'usuarioLimitado'
05 FOR LOGON
06 AS
07 BEGIN
08 IF ORIGINAL_LOGIN()= 'usuarioLimitado' AND
09 (SELECT COUNT(*) FROM sys.dm_exec_sessions
10 WHERE is_user_process = 1 AND
11 original_login_name = 'usuarioLimitado') > 3
12 ROLLBACK;
13 END;

Para probarlo, tan solo tenemos que realizar varias conexiones con el inicio de sesión que hemos creado, hasta superar el limite.



miércoles, 26 de junio de 2013

SQLServer 2008. Importación masiva de datos de un fichero delimitado a una tabla.

Como todos sabréis, y sino os lo digo yo, SQL Server 2008 (en todas sus versiones) nos ofrece un abanico enorme de posibilidades para realizar cualquier cosa que podamos imaginar sobre una base de datos. En este artículo me centrare en insertar grandes volúmenes de datos en una tabla de una tacada. 

Como ya he comentando, tenemos muchísimas posibilidades, pero si los datos están en un fichero externo, es decir, no viene de otra base de datos ya sea en nuestro servidor u otro (enlace al artículo sobre vinculación de servidores), dichas posibilidades se van recortando, aun así, son muchas. Entre ellas y por mi propia experiencia, las que más me gustan son dos:  mediante XML y con ficheros delimitados.

En esta ocasión vamos a explicar como lo haríamos con ficheros delimitados, donde nuevamente, tenemos varias posibilidades, siendo la que explicaré a continuación no la mas rápida (de implementar), pero si la más segura y efectiva. Este proceso sería muy útil a la hora de hacer una importación/exportación de datos.
Teniendo la tabla:
01 CREATE TABLE poetas
02 (
03    CODIGO integer not null PRIMARY KEY,
04    NOMBRE VARCHAR(150) not null,
05    APELLIDOS VARCHAR(150) not null,
06    DIRECCION VARCHAR(150) null,
07    LOCALIDAD VARCHAR(150) null,
08    PROVINCIA VARCHAR(150) null
09 )
Y teniendo un fichero con el siguiente formato: 
01 1|Gustavo Adolfo|Bécquer| Conde de Barajas|Sevilla|Sevilla##
Donde el carácter "|" es el separador de campos, y los caracteres "##" el separador de linea. Además necesitamos un XML con la definición de campos del fichero a usar relacionándolos con los campos y tipos de las columnas de la tabla donde se van a insertar los datos. El formato sería: 

01 <?xml version="1.0"?> 
02 
03 <BCPFORMAT xmlns="http://schemas.microsoft.
04 com/sqlserver/2004/bulkload/format" xmlns:xsi="http://www.w3.
05 org/2001/XMLSchema-instance"> 
06 
07 <RECORD> 
08 
09 <FIELD ID="1" xsi:type="CharTerm" TERMINATOR="|"/> 
10 <FIELD ID="2" xsi:type="CharTerm" TERMINATOR="|"/> 
11 <FIELD ID="3" xsi:type="CharTerm" TERMINATOR="|"/> 
12 <FIELD ID="4" xsi:type="CharTerm" TERMINATOR="|"/> 
13 <FIELD ID="5" xsi:type="CharTerm" TERMINATOR="|"/> 
14 <FIELD ID="6" xsi:type="CharTerm" TERMINATOR="##"/> 
15 
16 </RECORD> <ROW> 
17 
18 <COLUMN SOURCE="1" NAME="CODIGO" xsi:type="SQLSMALLINT"/> 
19 <COLUMN SOURCE="2" NAME="NOMBRE" xsi:type="SQLNVARCHAR"/> 
20 <COLUMN SOURCE="3" NAME="APELLIDOS" xsi:type="SQLNVARCHAR"/> 
21 <COLUMN SOURCE="4" NAME="DIRECCION" xsi:type="SQLNVARCHAR"/> 
22 <COLUMN SOURCE="5" NAME="LOCALIDAD" xsi:type="SQLNVARCHAR"/> 
23 <COLUMN SOURCE="6" NAME="PROVINCIA" xsi:type="SQLNVARCHAR"/> 
24 
25 </ROW> </BCPFORMAT> 


Solo nos faltaría ejecutar una instrucción como esta:


01 INSERT INTO poetas(CODIGO, NOMBRE, APELLIDOS, DIRECCION, LOCALIDAD, PROVINCIA) 
02 SELECT  CODIGO, NOMBRE, APELLIDOS, DIRECCION, LOCALIDAD, PROVINCIA
03 FROM OPENROWSET(BULK 'C:\exportacion\poetas.txt', 
04 FORMATFILE='C:\exportacion\poetas.xml' 
05 ) as t1 ;
Aclarar que igual que lo hacemos con una sentencia INSERT, podríamos hacerlo con un UPDATE o un DELETE sin más problemas. También deciros que esta instrucción disparará una sola vez los triggers que tengamos  en la tabla, por lo que deberemos programarlos para que traten el conjunto de datos y no solo un registro.

domingo, 23 de junio de 2013

Exprés: ¿Qué ha indexado google de mi web?

Es muy interesante saber que páginas (y como) tiene google indexadas de nuestra web, o de cualquier otra. Para ello nos ofrece esta utilidad, muy usada en el mundo de SEO. Se trata del comando site:dominio.com. para usarla tan solo tenemos que ir www.google.es y escribir en el buscador site:dominioquequeramosver.loquesea. (También para subdominios)

Nos aparecerán todas las páginas que google tiene indexadas sobre dicho dominio. Con esto podremos comprobar si estan correctas todas nuestras URLs amigables por ejemplo, o si hay algunas páginas que no queremos que google indexe. 

Para limitar la indexación de google, usaremos el fichero robots.txt introduciendo una directiva "Disallow:paginaquenoqueremosqueaparezca" con las URLs que queramos bloquear. También podríamos usar un subdominio, o una carpeta cuyo contenido no queramos que indexe.

Por último, comentar que esta utilidad de google nos da la posibilidad de pasarle parámetros de búsqueda siguiendo a la instrucción de la forma: site:dominioquequeramosver.loquesea palabrasdebusqueda. De esta forma, filtraremos los resultados obteniendo tan solo las páginas donde aparezcan las palabras de búsqueda que le pasamos como parámetro.