Método Parse() o los métodos de la clase Convert




Vamos arrojar un poco de luz sobre las diferencias entre utilizar el método Parse() de las estructuras de tipos de .NET o utilizar los métodos de la clase System.Convert. En realidad parece que hacen lo mismo pero existe una gran diferencia.Supongamos que dejamos que un usuario introduzca un valor numérico por pantalla y queremos realizar cálculos con ese valor. Por lo tanto, el valor introducido por el usuario será del tipo System.String y deberemos convertirlo a un tipo de valor numérico, por ejemplo System.Int32.
En definitiva queremos saber que diferencia hay entre ejecutar estas dos lineas de código:
int valorA Convert.ToInt32(valorUsuario);
int valorB Int32.Parse(valorUsuario);
Cuando utilizamos la segunda opción, el método Parse(), si el usuario no ha introducido ningún valor (null) recibiremos una excepción del tipo System.FormatException. Lo que indica que el formato del argumento no cumple las especificaciones del parámetro del método invocado.
En cambio, cuando utilizamos la primera opción, los métodos de la clase System.Convert, si el valor pasado al método es null, el método ConovertToInt32() devolverá un valor numérico, devolverá cero en todos los casos que el valor de entrada sea null.
Utilizando la herramienta Reflector podemos ver las diferencias de código que hay entre estas dos formas de convertir los tipos de .NET.

     
    Convert.ToInt32();

public static int ToInt32(string value)
{
     if (value == null)
     {
          return 0;
     }
     return int.Parse(value, CultureInfo.CurrentCulture);
}
 

    Int32.Parse();

public static int Parse(string s)
{
     return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
}
Espero que lo disfruten, compartan y comenten. ;)

"Si se puede imaginar... se puede programar."
Leer más...

String Cuidado con ese tipo!


El tipo System.String, que como todos sabemos representa una cadena, es un tipo algo especial con el que hay que tener un poco de cuidado a la hora de menejarlo. Veamos en primer lugar una definición más o menos formal del tipo System.String:
"El tipo System.String es un tipo por referencia e inmutable (de solo lectura) que representa una cadena de texto como una colección secuencial de caracteres Unicode (objetos System.Char)".
 Para este artículo nos centraremos en la primera parte de la definición, es decir, en "El tipo System.String es un tipo por referencia e inmutable (de solo lectura) ...".

¿Que quiere decir que es inmutable?
Un objeto inmutable es un objeto que no se puede modificar. Cuando creas, o cargas en menoria un objeto de este tipo, permanece con el mismo valor durente toda la vida del objeto. Veamos el siguiente fragmento de código:
            string miCadena "Un saludo";
            
miCadena +" para el lector";
Quizás pueda parecer que en la segunda linea de este fragmento estamos modificando el literal "Un saludo" pero esto no es así. Como ya dijimos antes, el objeto "Un saludo" es inmutable, por lo tanto, despúes de la concatenación, lo que se devuelve es un nuevo objeto de tipo System.String que contiene la modificación: "Un saludo para el lector".
Por lo tanto, cuando concatenamos cadenas de esta forma, tenemos en la memoria dos objetos, uno con el valor original y otro con la modificación. Es evidente, que sí esta operación la realizamos miles de veces, por ejemplo leyendo de una base de datos, el rendimiento de la aplicación se verá gravemente afectado. Por otro lado, si la operación solo se realiza una o dos veces (incluso tres o cuatro) no tiene tanta importancia.
Supongamos que tenemos una base de datos con todos los nombre de los lectores de este blog, y supongamos que son miles los nombres guardados (¡ojalá!...jeje). Ahora queremos leer de la base de datos todos los nombres y saludarles por pantalla. Creamos un método al que le pasamos cada nombre leido en un bucle.
        static void Saludar(string Nombre)
        {
            StringBuilder sb 
= new StringBuilder("Hola para ");
            
sb.Append(Nombre);
            
Console.WriteLine(sb.ToString());
        
}
Esta es la manera correcta de proceder, creando un objeto System.Text.StringBuilder y añadiendo cada nueva cadena por medio de su método Append(). Si queréis podéis descargaros un pequeño programilla que calcula el tiempo que se tarda en realizar concatenaciones con System.String y System.Text.StringBuilder en función de un número de iteraciones introducidas por el usuario.
String_vs_StringBuilder.rar (21,95 kb)

Más cosas a tener en cuenta.
¿Más cosas a tener en cuenta?. Ya dijimos que eran...¡unos tipos de cuidado!.
Cuando inicializamos variables de tipo Sytem.String y queremos darles un valor por defecto de cadena vacia es muy frecuente hacerlo con las comillas "".
    class Lector
    {
        
public string Nombre;
        public string 
Apellidos;
        public string 
Direccion;
        public string 
Telefono;
        public string 
Comentario;
        public string 
FechaComentario;

        public 
Lector()
        {
            Nombre 
"";
            
Apellidos "";
            
Direccion "";
            
Telefono "";
            
Comentario "";
            
FechaComentario "";
        
}

        
//...............

        //Aquí el resto de mienbros de la clase.

        //...............
    
}
No es recomendable hacerlo de esta forma. En este caso hemos creado (cargado en la menoria) 6 objetos diferentes de tipo cadena. Y seguramente luego "intentaremos" modificarlos al asignarles un valor determinado. Lo correcto, o por lo menos más recomendable, es hacerlo así:

        public Lector()
        {
            Nombre 
String.Empty;
            
Apellidos String.Empty;
            
Direccion String.Empty;
            
Telefono String.Empty;
            
Comentario String.Empty;
            
FechaComentario String.Empty;
        
}
Al utilizar el campo String.Empty que representa una cadena vacía, estamos apuntando todas las variables a un mismo objeto. De esta forma solo reservamos memoria para un único objeto gracias a que los tipos System.String son tipos por refencia.
Bueno...ya saben...¡cuidado con estos "tipos"!.



Espero que lo disfruten, compartan y comenten. ;)

Visita: http://rubitcorp.co/

"Si se puede imaginar... se puede programar."
Leer más...

Manejo de strings en C SHARP .NET


Hola csharpedianos, En este post veremos varios metodos aplicados al manejo de caracteres con la clase string.
Un string es una cadena de caracteres, y hay que saber dominar todos estos caracteres y hacer con ellos lo que nos venga en gana.
Es por eso que les traigo este post donde veremos algunas cosas interesantes que podemos hacer con esta clase string.

 Código en C# 

public static bool Contiene(string palabra, string cadena)
{
 for (int i = 0; i <= palabra.Length-cadena.Length; i++)
  //Si encontramos dos letras iguales
  if(palabra[i]==cadena[0])
  {
   bool contenida = true;
   //Recorremos la cadena desde la posición 1
   //y comparamos con la palabra a partir de 
   //la posición donde las dos letras iguales
   for (int j = 1; j < cadena.Length; j++)
    if (palabra[i + j] != cadena[j])
     contenida = false;
   //Si esta contenida
   if(contenida) 
    return true;
  }
 //Si no está contenida
 return false;
}

    public static bool EsPalindromo(string s)
      {
          //Si s está vacio o tiene longitud 1 retornamos true
          //Este es el caso base o condicion de parada recursiva
          if (s.Length == 0 || s.Length == 1) return true;

          //Quitamos las esquinas para ver si lo que queda
          //es palíndromo.
          string result = s.Substring(1, s.Length - 2);

          //Retornamos si los dos extremos de s son iguales 
          //y volvemos a llamar al metodo EsPalindromo
          return s[0] == s[s.Length - 1] && EsPalindromo(result);
      }

 public static string Invertir(string s)
      {
          string result = "";
          //Recorremos la cadena desde el final
          for (int k = s.Length - 1; k >= 0; k--)
              //Guardamos cada caracter en un nuevo string
              result = result + s[k];
          return result;
      }

public static string Reemplazar(string cadena, string x, string y)
      {
          string resp = cadena;
          for (int i = 0; i < cadena.Length; i++)
          {
              if (resp[i] == x[0])
              {
                  bool igual = true;
                  for (int j = 1; j < x.Length; j++)
                  {
                      if (resp[i + j] != x[j])
                          igual = false;
                  }
                  if (igual)
                  {
                      string alante = resp.Substring(0, i);
                      string atras = resp.Substring(i + x.Length);
                      resp = alante + y + atras;
                  }
              }
          }
          return resp;
      }
Es importante notar que aunque String, es una clase en C#, se puede tratar como un array de caracteres, y que el for se hace hasta palabra.Length-subcadena.Length, para que no de excepción.  También hay que decir que este ejercicio se puede hacer de otra forma más eficiente usando String Matching y algoritmos como KMP, pero no es el objetivo de este post.

Creo que el código está bien comentado, pero cualquier pregunta en los comentarios

Descarga aquí el código.



Espero que lo disfruten, compartan y comenten. ;)

"Si se puede imaginar... se puede programar."

Leer más...

Diferencias entre Char, Varchar, NChar y NVarchar en SQL Server


¿Cuál es la diferencia entre estos, y cuán importante es la diferencia?

Char y NChar 

Cuando se configura un campo de tipo Char o NChar estamos indicando campos de tamaño fijo. Es Decir, si configuramos una tabla de la siguiente forma

Campo1 Char(10),
Campo2 NChar(10)
 
La diferencia entre Char y NChar es el soporte a carácteres Unicode (los carácteres Unicode ocupan más de 1 byte). Por este motivo a la hora de almacenar algún valor, en el Campo1 siempre ocupará 10 bytes y en el Campo2 20 Bytes.

Varchar y Nvarchar

VARCHAR es la abreviación de variable-length character string.   Es una cadena de caracteres de texto que puede ser tan grande como el tamaño de página para la tabla de la base de datos. Los campos de tipo Varchar o NVarchar son de almacenamiento variable

El tamaño almacenado dependerá del valor que se quiere guardar, el número de caracteres sólo configura el tamaño máximo que este campo puede almacenar. 

Configuramos una tabla de la siguiente forma:

CampoVariable1 Varchar(10),
CampoVariable2 NVarchar(10)

El tamaño almacenado dependerá del valor que se quiere guardar, el número de caracteres sólo configura el tamaño máximo que este campo puede almacenar. En el caso del CampoVariable1 el tamaño máximo será de 10 bytes, y en el caso del CampoVariable2 el tamaño máximo será de 20 bytes.

El tamaño de una página de tabla es 8.196 bytes, y no hay una fila de una tabla puede ser tener de 8.060 caracteres. Esto a su vez limita el tamaño máximo de un VARCHAR a 8000 caracateres

La "N" en NVARCHAR significa uNicode. Esencialmente, NVARCHAR no es más que un VARCHAR que soporta caracteres de dos bytes.  Lo que representara una longitud máxima de 4000 caracteres. Lo que significa tener la capacidad de almacenar caracteres especiales en este tipo de datos.
Y para que sirve Unicode? Si la columna donde almacenamos el texto es Unicode quiere decir que no tendremos problemas para guardar y recuperar caracteres que se usan en otros idiomas como el español (á é í ó ú ñ), pero con el español los problemas de visualización no son muy frecuentes, con el resto de idiomas es el problema (como el chino o japonés).

3
Unicode o No Unicode
Dependiendo de la información que queremos almacenar en nuestra base de datos, tendremos que definir si permitimos o no valores Unicode (Por ejemplo diferentes idiomas como el Ruso, Japonés, chino, …). Existen tablas de codificación de caracteres (Encodings) que poseen carácteres específicos de Doble Byte. Esto puede afectarnos a la hora de utilizar campos de tipo Char o Varchar, ya que un texto de 10 carácteres podría superar los 10 bytes, haciendo imposible la insercción del valor a la base de datos.


Espero que lo disfruten, compartan y comenten. ;)

"Si se puede imaginar... se puede programar."


Leer más...

Monitorear el rendimiento de SQL SERVER



SQL Server Profiler
·         Muestra como SQL Server resuelve las queries internamente
·         Permite a los administradores ver como se ven las sentencias T-SQL  y como el servidor regresa los resultados.
·         Se puede:
o   Crear una traza basado en Templates
o   Verificar los resultados de la traza
o   Almacenar los resultados de la traza en un archivo o tabla
·         Capturar datos enviados al servidor que permite al programador verificar errores o datos incorrectos.

Windows System Monitor
·         Monitorear el uso de recursos.
·         System Monitor también llamado Performance Monitor.
·         Comparando SQL Server Profiler,  este monitorea eventos del motor de base de datos,  System Monitor monitorea el uso de recursos asociados con los procesos del servidor.
·         Se encuentra en el Panel de Control , Herramientas Administrativas, Monitor de rendimiento (en Español)   o bien Performance Monitor.

Activity Monitor
       Secciones:
1.       Vista General -  Muestra gráficamente el comportamiento del resto de secciones.
2.       Procesos – Muestra las actividades de los usuarios.  Que usuario esta impactando en que base.
3.       Recursos en Espera -  Espera el estado de la información. Que proceso está esperando un recurso.
4.       Data File  I/O -  Archivos de Data y Log  con información I/O
5.       Queries utilizadas -  Muestra las queries mas utilizadas recientemente.

Transact-SQL
·         sp_who 
·         sp_lock
·         sp_spaceused
·         sp_monitor

Windows Logs
·         Aplicación Externa a SQL Server
·         Podremos ver advertencias o errores ocurridos en los procesos de SQL Server.
·         Se encuentra en el Panel de Control , Herramientas Administrativas, Visor de Eventos(en Español)   o bien Events Log.

Default Trace
·         SQL Server “Caja Negra”
·         Para habilitarlo:
sp_configure 'default trace enabled', 1
RECONFIGURE
·         El trace que se creara por defecto será en la ruta donde esté instalado SQL Server. 
C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\Log
·         Buscamos el archivo de traza  con extension .trc generado.

Fuente:
Blog de Bernardo Robelo


Espero que lo disfruten, compartan y comenten. ;)

"Si se puede imaginar... se puede programar."
Leer más...

Verificar url o archivos remotos




 Trabajando en uno de los proyectos para la empresa donde laboro, me surgió la necesidad de verificar si un archivo existía teniendo solo su url, fue aquí donde comencé a investigar junto con mi amigo Edwin Rincon y encontramos una solución muy buena la cual les voy a compartir a continuación.

Pueden utilizar este método para comprobar que sus paginas web están funcionando de forma correcta o usarlo para comprobar links suministrados por otros usuarios, en fin, lo pueden usar para lo que necesiten.

Este método recibe 2 parámetros:

El primero es la url que se desea comprobar y el segundo es la cantidad de tiempo máximo que queremos que espere por una respuesta, vale aclarar que el tiempo lo damos en milisegundos, quiere decir que un segundo equivale a 1000 milisegundos, en este caso he colocado que espere solo 3 segundos, si en ese tiempo no recibo una respuesta por parte del servidor remoto entonces asumo que la url no existe, ustedes pueden poner el tiempo que quieran.


public static bool RemoteFileExists(string url, int timeout)
    {
        try
        {            
            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
           
            // El timeout es en milisegundos
            request.Timeout = timeout;
            // ************

            //Configurando el Request method HEAD, puede ser GET tambien.
            request.Method = "HEAD";
            //Obteniendo la respuesta
            HttpWebResponse response = request.GetResponse() as HttpWebResponse;
            //Regresa TRUE si el codigo de esdado es == 200
            return (response.StatusCode == HttpStatusCode.OK);
        }
        catch
        {
            //Si ocurre una excepcion devuelve false
            return false;
        }
    }
Esto nos sirve para verificar si un website esta funcionando o una pagina existe o para verificar archivos remotos, en mi caso la he usado para saber si una foto existe en un website.

Les dejo un proyecto de ejemplo para verificar paginas o archivos remotos:
Descargar Aquí.


Espero que lo disfruten, compartan y comenten. ;)

"Si se puede imaginar... se puede programar."

Leer más...

Visual studio 2012: Lanzamiento


El miércoles 12 de septiembre de 2012 Microsoft lanzo la nueva versión de la herramienta de desarrollo mas robusta, fácil y útil que puede existir, se trata de visual studio 2012 el cual ha cambiado un poco su apariencia física y su logo, ya no es el azul que estábamos acostumbrados a ver en la versión de visual studio 2010, ahora tiene un gris pálido (un poco feo en mi opinión) el cual regulan con azul que se deja ver de vez en cuando, aunque para aquellos desarrolladores medio góticos o emos, si van [Herramientas - Opciones] pueden cambiar por un tema Dark.

Pero mas allá de los cambios en la apariencia visual studio ha sufrido cambios importantes ya que ha agregado mejoras para linq, expresiones lambda, aplicaciones para WIN8 y el nuevo Framework 4.5.


Lo que mas me ha gustado es que es muy rápido y con solo dar clic sobre un aspx se mostrara estilo de un preview donde puedes ver todo el código html y editarlo.
A Continuación listare algunas de las mejoras de VS 2012:



Características de Visual Studio 2012 : 
1 – Desarrollo innovador de aplicaciones
2 – Gestión moderna del ciclo de vida de las aplicaciones
3 – Posee herramientas para una planificación y gestión de proyectos ágil, que mantienen a los equipos alineados e informados.
4 – También tiene herramientas y flujos de trabajo para romper las barreras en la integración funcional y de equipos de trabajo.


Características .NET Framework 4.5:

- Proporciona a los desarrolladores una forma rica y productiva de crear aplicaciones en el cliente (Windows Forms, WPF, Windows 8 Store Apps), on premise (Windows Server) y en la nube (Windows Azure).

- Sus nuevas capacidades incluyen mejoras de rendimiento y la posibilidad de hacer más sencilla la programación asincrónica y paralela. Además, ofrece funcionalidad de .NET y XAML para Windows 8 Store Apps.

- .NET Framework 4.5 en el servidor también proporciona ASP.NET, WIF (Windows Identity Foundation), Entity Framework y WCF (Windows Communication Foundation). Asimismo, para la nube, Windows Azure proporciona soporte completo para desarrollo .NET con Windows Azure SDK para .NET.


Muy pronto les estare hablando mas de mi experiencia con este nuevo VIsual Studio.



Espero que lo disfruten, compartan y comenten. ;)

"Si se puede imaginar... se puede programar."
Leer más...

Formatos con String.Format en C#



formatos en c sharp
Todas las aplicaciones que desarrollamos en algún momento necesitan formatear algún tipo de datos, y no se a ustedes pero a mi siempre se me olvidan los formatos y como obtener los resultados de una u otra forma, es por eso que decidí hacer este post, y recopilar la mayor cantidad de formatos posibles, para buscarlos cuando necesite y ustedes puedan copiarlos ;=).

Para formatear cadenas existe una clase especializada en el manejo de cadenas, esta clase se llama String, su nombre completo es System.String, ya que se encuentra en el namespace System.
En esta clase vamos a encontrar una función llamada Format que se encargará de reemplazar el valor de un dato (entero, real, una cadena, un carácter, hasta de un objeto), por el formato que se especifique en el parámetro.

En forma general, y aunque tiene varias sobrecargas, String.Format tiene la siguiente sintaxis:

Formatos para números:
  Tipo   Ejemplo   Resultado
Currency
 String.Format('{0:c}',2.5); 
2.5
Decimal (Numero Entero)
 String.Format('{0:d}',200); 
200
Scientific
 String.Format('{0:e}',254325.22); 
254325.22
General
 String.Format('{0:g}',20.50); 
20.50
Number (Número con comas para los miles)
 String.Format('{0:n}',2548241.50); 
2548241.50
Hexadecimal
 String.Format('{0:x}',2548241); 
2548241
Cantidad de decimales
 String.Format('{0:0.000}',254.623645); 
254.623645


Formato para Cadenas
  Tipo   Ejemplo   Resultado
Alineacion a la derecha
 String.Format('{0,30}',Identado a la derecha); 
Identado a la derecha
Alineacion a la izquierda
 String.Format('{0,-5}',Identado a la izquierda); 
Identado a la izquierda


Formato para Fechas
  Tipo   Ejemplo   Resultado
Día
 String.Format('{0:dd}', DateTime.Now ); 
12
Nombre del Día acortado
 String.Format('{0:ddd}', DateTime.Now ); 
Wed
Nombre del Día – largo
 String.Format('{0:dddd}', DateTime.Now ); 
Wednesday
Era
 String.Format('{0:gg}', DateTime.Now ); 
A.D.
Hora
 String.Format('{0:hh}', DateTime.Now ); 
09
Hora en formato de 24h.
 String.Format('{0:HH}', DateTime.Now ); 
09
Minutos
 String.Format('{0:mm}', DateTime.Now ); 
21
Meses
 String.Format('{0:MM}', DateTime.Now ); 
09
Abreviación del Mes
 String.Format('{0:MMM}', DateTime.Now ); 
Sep
Nombre Completo del Mes
 String.Format('{0:MMMM}', DateTime.Now ); 
September
Segundos
 String.Format('{0:ss}', DateTime.Now ); 
29
AM o PM
 String.Format('{0:tt}', DateTime.Now ); 
AM
Año en dos dígitos
 String.Format('{0:yy}', DateTime.Now ); 
12
Año en formato largo
 String.Format('{0:yyyy}', DateTime.Now ); 
2012
Short Date
 String.Format('{0:d}', DateTime.Now ); 
9/12/2012
Long Date
 String.Format('{0:D}', DateTime.Now ); 
Wednesday, September 12, 2012
Hora y Fecha en formato corto
 String.Format('{0:f}', DateTime.Now ); 
Wednesday, September 12, 2012 9:21 AM
Hora y Fecha en formato largo
 String.Format('{0:F}', DateTime.Now ); 
Wednesday, September 12, 2012 9:21:29 AM
Hora Universal
 String.Format('{0:u}', DateTime.Now ); 
2012-09-12 09:21:29Z



Si me hizo falta alguno por fa comentenlo y lo agrego.

Espero que lo disfruten, compartan y comenten. ;)

"Si se puede imaginar... se puede programar."
Leer más...

Obtener imagen de html o url en .NET



 Hola Csharpedianos, hace tiempo quería escribir este post pero no había encontrado un ejemplo digno de ser mostrado en nuestro blog, hasta que mi amigo Edwin Rincon [un excelente programador entre otras cosas] me dijo, "he tío mira lo que hice" e ilumino las palabras de este bendito post.

La idea es crear imagenes miniatura (Thumbnail) de una pagina web, teniendo solo su url.
Para que rayos me servirá eso?
Pues si estas leyendo este post es porque lo necesitas para algo o si no entonces?.
    
 Para cumplir el objetivo de obtener una imagen miniatura de una pagina web desde C#, lo primero que tenemos que hacer es descargarnos esta clase AQUÍ ).

Explicare los metodos uno a uno (Que comience la fiesta):

Lo primero que tenemos  es este metodo el cual se encarga de llamar los procedimientos necesarios para que nuestro resultado sea el esperado, este recibe los siguientes parametros:
Url:  La url de la pagina a la cual le queremos hacer la imagen en miniatura.
BrwoserWidth:  Ancho que queremos capturar de la pagina.
BrowserHeight:  Largo que queremos capturar de la pagina.
ThumbnailWidth: Este sera el ancho del que deseas la imagen resultante.
ThumbnailHeight: Este sera el largo del que deseas la imagen resultante.

public static Bitmap GetWebSiteThumbnail(string Url, int BrowserWidth, int BrowserHeight, int ThumbnailWidth, int ThumbnailHeight)
        {
            WebsiteThumbnailImage thumbnailGenerator = new WebsiteThumbnailImage(Url, BrowserWidth, BrowserHeight, ThumbnailWidth, ThumbnailHeight);
            return thumbnailGenerator.GenerateWebSiteThumbnailImage();
        }


Ahora tenemos una clase que sera la que contendra los procedimientos de consulta y captura de la imagen:

private class WebsiteThumbnailImage
        {

        }

Dentro de esta colocaremos las propiedades que utilizaremos:

  private string m_Url = null;
            public string Url
            {
                get
                {
                    return m_Url;
                }
                set
                {
                    m_Url = value;
                }
            }

            private Bitmap m_Bitmap = null;
            public Bitmap ThumbnailImage
            {
                get
                {
                    return m_Bitmap;
                }
            }

            private int m_ThumbnailWidth;
            public int ThumbnailWidth
            {
                get
                {
                    return m_ThumbnailWidth;
                }
                set
                {
                    m_ThumbnailWidth = value;
                }
            }

            private int m_ThumbnailHeight;
            public int ThumbnailHeight
            {
                get
                {
                    return m_ThumbnailHeight;
                }
                set
                {
                    m_ThumbnailHeight = value;
                }
            }

            private int m_BrowserWidth;
            public int BrowserWidth
            {
                get
                {
                    return m_BrowserWidth;
                }
                set
                {
                    m_BrowserWidth = value;
                }
            }

            private int m_BrowserHeight;
            public int BrowserHeight
            {
                get
                {
                    return m_BrowserHeight;
                }
                set
                {
                    m_BrowserHeight = value;
                }
            }

 Y 3 metodos necesarios para se encargan de crear un hilo y ejecutar las acciones asincronamente:

 public Bitmap GenerateWebSiteThumbnailImage()
            {
                Thread m_thread = new Thread(new ThreadStart(_GenerateWebSiteThumbnailImage));
                m_thread.SetApartmentState(ApartmentState.STA);
                m_thread.Start();
                m_thread.Join();
                return m_Bitmap;
            }

            private void _GenerateWebSiteThumbnailImage()
            {
                WebBrowser m_WebBrowser = new WebBrowser();
                m_WebBrowser.ScrollBarsEnabled = false;
                m_WebBrowser.Navigate(m_Url);
                m_WebBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(WebBrowser_DocumentCompleted);
                while (m_WebBrowser.ReadyState != WebBrowserReadyState.Complete)
                    Application.DoEvents();
                m_WebBrowser.Dispose();
            }

            private void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
            {
                WebBrowser m_WebBrowser = (WebBrowser)sender;
                m_WebBrowser.ClientSize = new Size(this.m_BrowserWidth, this.m_BrowserHeight);
                m_WebBrowser.ScrollBarsEnabled = false;
                m_Bitmap = new Bitmap(m_WebBrowser.Bounds.Width, m_WebBrowser.Bounds.Height);
                m_WebBrowser.BringToFront();
                m_WebBrowser.DrawToBitmap(m_Bitmap, m_WebBrowser.Bounds);
                m_Bitmap = (Bitmap)m_Bitmap.GetThumbnailImage(m_ThumbnailWidth, m_ThumbnailHeight, null, IntPtr.Zero);                
            }


 Nuestro ultimo paso sera crear un metodo en presentacion que sera el que segun nosotros hara todo y sera el que invocara la clase y guardara la imagen resultante:

Bitmap bmp = WebsiteThumbnailImageGenerator.GetWebSiteThumbnail(address,1000, 1500, width, height);
            bmp.Save(Server.MapPath("~") + "/thumbnail.jpg");

Les dejo un ejemplo funcional de lo aqui dicho :
Descarguenlo AQUI


Espero que lo disfruten, compartan y comenten. ;)

"Si se puede imaginar... se puede programar."
Leer más...

Serializar a JSON en .NET


En este articulo vamos a mostrar un ejemplo de como conseguir serializar clases de .NET en el formato de java script: JSON. Como verán a continuación es extremadamente simple.
Vamos a realizar con VS2008 un proyecto de tipo web site de ASP.NET. Utilizaremos como librería cliente jQuery, por lo que necesitamos añadimos la referencia a la librería – que podemos descargar desde el sitio oficial de jQuery http://www.jquery.com/. Tras descargar el archivo lo incluiremos en nuestro proyecto – en mi caso he incluido el archivo en la ruta “js/lib”.
<script src="js/lib/jquery.js" type="text/javascript"></script>
También podemos referenciar jQuery directamente desde los repositorios de Google o Microsoft.
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" 
        type="text/javascript"></script>
<script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.min.js" 
        type="text/javascript"></script>
Bien, una vez incluida la referencia a jQuery en el formulario (Default.aspx), diseñamos una sencilla página que tendrá  un formulario de búsqueda en la parte superior y en la parte inferior los resultados de dicha búsqueda.
Como utilizamos jQuery como librería de java script enlazamos el click de botón de búsqueda de forma no intrusiva (suponiendo que el botón buscar tenga btnBuscar como id) .
img1
<script language="javascript">

    $(document).ready(
        function() {
            $("#btnBuscar").click(
            btnBuscar_Click);
    });

    function btnBuscar_Click() {
       //De momento nada
    }

</script>

Por supuesto también podríamos haber enlazado el evento de la forma tradicional, es decir agregando el atributo onclick.
<input type="button" id="btnBuscar" value="Buscar" class="boton" onclick="btnBuscar_Click" />
Ahora nos centramos en la parte del servidor. Lo primero que necesitamos es una clase para serializarla en JSON, son los datos que vamos a devolver. Dada nuestra infinita imaginación usamos lo de siempre “DatosPersona” – nombre, apellidos, TipoDocumento y Documento. ¡Una alarde de creatividad!
class DatosPersona
{
    public string Nombre { get; set; }
    public string Apellidos { get; set; }
    public string TipoDocumento { get; set; }
    public string Documento { get; set; }   
}
A esta clase le añadimos un método ToJSON, que se va a encargar de serializar la clase al formato de java script.
class DatosPersona
{
    public string Nombre { get; set; }
    public string Apellidos { get; set; }
    public string TipoDocumento { get; set; }
    public string Documento { get; set; }

    public string ToJSON()
    {
        System.Web.Script.Serialization.JavaScriptSerializer jsonSerializer
            = new System.Web.Script.Serialization.JavaScriptSerializer();
        return jsonSerializer.Serialize(this);

    }
}
Como podemos ver es el framework quien hace todo el trabajo, nosotros solo tenemos que crear una instancia de la clase JavaScriptSerializer  y serializar el objeto. Más fácil imposible.
Ahora nos centramos en el flujo de la página, tenemos que detectar la accion de buscar en el Page_Load(ya veremos luego como)  y generar la respuesta en el formato JSON:
protected void Page_Load(object sender, EventArgs e)
 {
     string accion = Request["accion"];
     if (accion == "BUSCAR")
     {
         int codpersona = 0;
         if(Int32.TryParse (Request["codpersona"], out codpersona ))
         {
             string datos = ObtenerPersona(codpersona);
             Response.ContentType = "application/json"; 
             Response.Write(datos);
             Response.End();
         }
     }
 }

 string ObtenerPersona(int codigoPersona)
 { 
     /*
      * En el mundo real usariamos el codigo de persona
      * para buscar en una base de datos!
      */
     DatosPersona persona = new DatosPersona
     {
         Nombre = "www.devjoker.com",
         Apellidos = "Programacion y +",
         TipoDocumento = "NIF",
         Documento = "000000" + codigoPersona + "P"
     };

     return persona.ToJSON();

 }
Si analizamos el código vemos que debemos enviar al servidor dos parametros accion y codpersona. Eso lo hacemos en la función del lado del cliente btnBuscar_Click que anteriormente habíamos dejado en blanco. Para obtener los datos usamos el método getJson de jQuery, y para poner los datos en pantalla utilizamos un callback. Por supuesto para que el programa funcione los id asignados a los controles de pantalla deben coincidir ( txtCodigoPersona, lblNombre, lblApellidos, lblTipoDocumento, lblDocumento)
function btnBuscar_Click() {
    var param = {
        "accion": "BUSCAR",
        "codpersona": $("#txtCodigoPersona").val()
    };

    $.getJSON("Default.aspx", param, function(returndata) {
        $("#lblNombre").text(returndata.Nombre);
        $("#lblApellidos").text(returndata.Apellidos);
        $("#lblTipoDocumento").text(returndata.TipoDocumento);
        $("#lblDocumento").text(returndata.Documento);               
    });                        
}
El programa en acción quedaría de la siguiente manera:
img2  Si analizamos la respuesta Http podemos ver como nuestra clase se ha serializamos perfectamente en JSON

HTTP/1.1 200 OK
Server: ASP.NET Development Server/9.0.0.0
Date: Mon, 26 Apr 2010 14:11:19 GMT
X-AspNet-Version: 2.0.50727
Cache-Control: private
Content-Type: application/json; charset=utf-8
Content-Length: 105
Connection: Close

{"Nombre":"www.devjoker.com","Apellidos":"Programacion y +","TipoDocumento":"NIF","Documento":"0000004P"}
Como veis es un ejemplo muy simple pero también muy didáctico.

La fuente de esto ha sido: http://www.devjoker.com/contenidos/catss/459/Serializacioacuten-JSON-con-NET.aspx

Espero que lo disfruten, compartan y comenten. ;)

"Si se puede imaginar... se puede programar."
Leer más...

Optimizador de Querys: SQL SERVER


Dirán que soy intenso con el tema de SQL SERVER y optimizacion de la base de datos, pero es algo tan importante como el desarrollo de la aplicacion misma, ya que si esto falla, podremos tener muchos problemas con la funcionalidad y el rendimiento de nuestra aplicacion (a menos que no utilice base de datos).

Por esta razón insisto tanto en que tengamos vigilados cada una de las áreas de la base de datos y en este post les traigo un libro buenisiiiiimo que se llama "Inside the SQL Server Query Optimizer" y fue escrito por Benjamin Nevarez.
El libro esta en ingles y es muy bueno para optimizacion de querys.

Descarguenlo Aquí.



Espero que lo disfruten, compartan y comenten. ;)

"Si se puede imaginar... se puede programar."
Leer más...

Características descontinuadas en SQL Server 2012


Con la llegada de SQL Server 2012, la mayoría de los desarrolladores que día a día tenemos que convivir con el motor de base de datos, así como aquellos DBA’s (Administradores de Bases de Datos), nos hacemos la pregunta de si una versión actual soportará características anteriores de versiones como 2005 o 2008.
Todo cambio tecnológico tiene su riesgo, y no obstante con las versiones de SQL Server. A continuación les comparto las características que ya no tendrán disponibles en la versión 2012.
  • Active Directory Helper Service: Los componentes que han sido removidos dentro de la parte de directorio activo son: sp_ActiveDirectory_Obj, sp_ActiveDirectory_SCP y sp_ActiveDirectory_Start. Es importante señalar que no se encuentra ninguna característica en SQL Server 2012 que sustituya a los componentes anteriormente comentados.
En el caso de Reporting Services en SQL Server de 64 bits, cabe mencionar que desde la versión SQL Server 2008 R2, el componente ya no admitía servidores basados en Itanium, los cuales se ejecutaban anteriormente en Windows Server 2003 (si mal no recuerdo). Esto es sumamente importante ya que si queremos instalar o actualizar SQL Server en un equipo con dichas características tendremos que empezar por actualizar nuestro sistema operativo por un Windows 2008 Server R2 como mínimo.
SQL-DMO de SQL Server Express Installation
Se ha eliminado este soporte que se encontraba anteriormente en las versiones de SQL Server 2008 Express, (es aquí donde entran los expertos de SQL Server, a aclarar bien esta característica jeje)
También se han eliminado ciertas herramientas que anteriormente contabamos con SQL Server 2008 como son:
  • La herramienta de configuración de superficie (SAC).
  • Se realizaron ajustes y nuevas características al componente de configuración de SQL Server, así como al Management Studio, Reporting Services, etc.
Si quieres conocer más acerca de las consideraciones a tomar en cuenta sobre la instalación o actualización de tu SQL Server, puedes encontrar más detalle en el artículo de Discontinued SQL Server Features in SQL Server 2012 del cual es basado los comentarios emitidos en este post.

Espero que lo disfruten, compartan y comenten. ;)

"Si se puede imaginar... se puede programar."


Leer más...

Mejores practicas: SQL SERVER






Siempre es bueno llevar un conocimiento básico de los estándares y mejores prácticas en desarrollo y bases de datos.
A continuación les proporciono con una lista de “Best Practices” para SQL Server (Que aplican también para muchos otros DBMS):




 
1. No usar Select *. Siempre que se utiliza Select * todas las columnas en la tabla o unión se incluyen en el conjunto de resultados, así que el incluir todas las columnas aunque no sean necesarias provoca un exceso de entradas/salidas en el servidor y un consumo innecesario del ancho de banda de la red.

2. Siempre mandar llamar procedimientos almacenados. No hay que enviar declaraciones Select, Insert, Delete o Update a la base de datos; en vez de eso, siempre hay que llamar procedimientos almacenados pasándole los parámetros correspondientes.
El motivo de esta mejor práctica es el siguiente: cuando SQL Server recibe una consulta, como una declaración Select, lo primero que hace es compilarla, crear un plan de ejecución, y finalmente ejecutarlo; todos estos pasos consumen tiempo.
Cuando se invoca un procedimiento almacenado, este procedimiento almacenado puede ser compilado si es la primera vez que es llamado, o si cambian las estadísticas que le afecten, pero en caso contrario no es compilado y es almacenado en el caché; el plan de ejecución también es almacenado en el caché. El llamar un procedimiento almacenado ahorra tiempo de ejecución y
recursos, así que es una mejor práctica que no debe ser ignorada.

3. No grabar los procedimientos almacenados con un nombre con prefijo “sp_”. Cuando el nombre de un procedimiento almacenado comienza con “sp_”, SQL Server lo busca en el siguiente orden:
En la base de datos maestra En la base de datos determinada por los calificativos proporcionados (nombre de la base de datos o su dueño) En cada base de datos que tenga dbo como dueño, si el dueño no fue proporcionado.

4. Usar la cláusula Join con estándar ANSI. Para unir tablas es mejor usar la cláusula Join que hacer una unión por medio de la cláusula Where. A pesar de que a partir de SQL Server 7.0 las uniones de tablas usando Where pueden ser traducidas por el plan de ejecución a uniones explícitas, el hecho es que el compilador es quien hace esa conversión, lo cual le toma tiempo y recursos.

5. Evitar el uso de cursores en los procedimientos almacenados. Los cursores en SQL Server son recursos muy caros, lo cual hace mas lento el desempeño de las consultas. Se debe evitar en lo posible el uso de cursores.

6. Utilizar SET NOCOUNT ON. Al crear procedimientos almacenados, se puede mejorar el desempeño de ADO eliminando los valores innecesarios de la cantidad de renglones afectados, del conjunto de datos de salida, con solo agregar la instrucción SET NOCOUNT ON en el procedimiento almacenado.

7. Minimizar el uso de tablas temporales. Aunque las tablas temporales generalmente son una estructura en memoria, lo cual puede parecer que es una solución de acceso rápido, eso no significa que este enfoque mejore el desempeño; de hecho, esto empeorara el desempeño. El motivo de esto es que la estructura de una tabla temporal no la conoce de antemano el optimizador de consultas, por lo tanto el optimizador necesita recompilar el plan de ejecución una vez que la conoce; esto es, después de que la tabla temporal es creada. Muchas veces, el tiempo que le toma recompilar el procedimiento es mayor que el tiempo de la ejecución misma.

8. Usar tablas derivadas siempre que sea posible. Las tablas derivadas tienen un mejor desempeño. Considerando la siguiente consulta para encontrar el segundo salario mas alto de la tabla de Empleados:
SELECT MIN(Salary) FROM Employees WHERE EmpID IN ( SELECT TOP 2 EmpID FROM Employees ORDER BY Salary DESC )
La misma consulta puede ser re-escrita usando una tabla derivada, como se muestra a continuación, y será el doble de rápida que la consulta anterior:

SELECT MIN(Salary) FROM ( SELECT TOP 2 Salary FROM Employees ORDER BY Salary DESC ) AS A

9. Evitar el uso de caracteres comodín al inicio de una palabra al usar el identificador LIKE. Se debe intentar evitar el uso de caracteres comodín al inicio de una palabra al hacer una búsqueda usando el identificador LIKE, ya que eso ocasiona un rastreo en el índice (index scan), lo cual se contrapone con el objetivo de usar índices. El primero de los siguientes códigos genera un rastreo en el índice, mientras que el segundo genera una búsqueda en el índice (index seek):

SELECT LocationID FROM Locations WHERE Specialities LIKE „%pples?
SELECT LocationID FROM Locations WHERE Specialities LIKE „A%s?

También se deben evitar las búsquedas utilizando operadores de no igualdad (<> y NOT) ya que
éstos resultan en rastreos de índices y tablas.

10. Evitar el uso de sugerencias (hints). Las sugerencias sobrepasan la optimización de consultas y pueden prevenir que el optimizador de consultas escoja el plan de ejecución más rápido. Debido a cambios en el optimizador, las sugerencias que mejoraban el desempeño en versiones previas de SQL Server pueden no tener efecto o incluso empeorar el desempeño en SQL Server 7.0 y 2000. Además de esto, las sugerencias a las uniones pueden causar degradación del desempeño.
Las sugerencias a las uniones previenen que una consulta sea elegible para la auto-parametrización y subsecuente almacenamiento en caché del plan de ejecución. Cuando se usa una sugerencia a la unión, implica que se quiere forzar el orden de unión para todas las tablas en la consulta, aun y si las otras uniones no usan explícitamente una sugerencia.
Si la consulta que se está analizando contiene cualquier sugerencia, debe removerse y re-evaluar su desempeño.

11. Tratar de no usar tipos de datos TEXT o NTEXT para almacenar datos textuales grandes. El tipo de datos TEXT tiene ciertos problemas inherentes a él. Por ejemplo, no se puede grabar o actualizar datos de texto usando las instrucciones INSERT o UPDATE. En vez de eso, es necesario usar declaraciones especiales como READTEXT, WRITETEXT y UPDATETEXT.
También existen muchos errores asociados con la replicación de tablas que contienen columnas de tipo TEXT. Por eso, si no se necesita almacenar más de 8 KB de texto, es preferible usar los tipos de datos CHAR (8000) o VARCHAR (8000).

12.
De ser posible, no almacenar archivos binarios o de imagen (Binary Large Objects o BLOBs) en la base de datos. En vez de eso, almacenar la ruta al archivo binario o de imagen en la base de datos y usarla como apuntador al archivo actual almacenado en otra parte del servidor. Es mejor recuperar y manipular estos grandes archivos binarios fuera de la base de datos, y después de todo una base de datos no esta hecha para almacenar archivos.

13. Usar el tipo de datos CHAR para una columna solamente cuando no pueda contener valores nulos. Si una columna CHAR puede contener valores nulos, es tratada como una columna de ancho fijo en SQL Server 7.0+. Así que un CHAR (100) cuando sea nulo ocupara 100 bytes, resultando en un desperdicio de espacio. Para esta situación es mejor usar VARCHAR(100). Ciertamente las columnas de ancho variable tienen un poco más de overhead de procesamiento en comparación con lascolumnas de ancho fijo. Se debe escoger con cuidado entre CHAR y VARCHAR dependiendo del ancho de los datos que se van a almacenar.



Espero que lo disfruten, compartan y comenten. ;)

"Si se puede imaginar... se puede programar."
Leer más...

Limpiar los Textboxs de un WebForm en C SHARP



Hola Csharpedianos, en algunas ocasiones cosas tan sencillas como limpiar todos los textbox de un formulario nos complica la vida (y mas cuando son milesss) y nos puede tomar mucho tiempo hacerlo.

Aquí les traigo una forma de lograr esto con solo un método:


  Control strWebForm = Page.FindControl("form1");

        foreach (Control strControl in strWebForm.Controls)
        {
            if (strControl.GetType().ToString().Equals("System.Web.UI.WebControls.TextBox"))
            {
                ((TextBox)strControl).Text = string.Empty;
            }
        }



Aquí les dejo una apelación de ejemplo que llena y limpia todos los textbox del formulario:

Descargar Aquí.

Espero que lo disfruten, compartan y comenten. ;)

"Si se puede imaginar... se puede programar."

Leer más...

Donde se gasta el tiempo de una consulta SQL SERVER?



Ahora parece un buen momento para familiarizarse con Extended Events, y puede usar los scripts de este artículo como un punto de partida práctico para aprender cómo funcionan y suministrar  funcionalidad administrativa muy útil al mismo tiempo. Como sucede con cada característica nueva, lleva tiempo y práctica aprender acerca de los Extended Events, ganar confianza con ellos y explorar cómo personalizarlos para que se adapten a nuestras necesidades.
En general, mientras se procesa una consulta, puede estar en uno de dos estados:
usando recursos de servidor o esperando por recursos de servidor. Utilice los Eventos
Extendidos para ver dónde se gasta la mayor parte del tiempo de sus consultas
.

Son las palabras que leí en el libro que les traigo hoy, y a decir verdad me causo mucha curiosidad al punto que investigue todo lo que decía el libro y resulto ser muy practico e ilustrativo para las situaciones en que no sabemos porque una consulta se demora mucho o de vez en cuando se queda atascado un query.

 Descargar libro Aqui.


Espero que lo disfruten, compartan y comenten. ;)

"Si se puede imaginar... se puede programar."

Leer más...

Rastreo de parametros con procedimientos almacenados de SQL SERVER




Los usuarios afirman que de repente la ejecución de un procedimiento almacenado es muy lenta. Sin embargo, cuando se ejecuta dentro de SSMS con los mismos parámetros, se ejecuta con rapidez. Además, los usuarios afirman que, para algunas combinaciones de parámetros,  el procedimiento almacenado funciona bien. Si estás en este escenario, están descubriendo el lado oscuro del rastreo de parámetros.





¿Qué es el rastreo de parámetros?
Siempre que se invoca un procedimiento almacenado, el optimizador de consultas trata de volver a utilizar un plan de ejecución. Si existe un plan de ejecución coincidente en caché se reutiliza "a ciegas". Si no es así, se generará un nuevo plan. Durante la generación del plan, el optimizador analiza y optimiza todas las consultas en el procedimiento almacenado. Comprueba las posibilidades de generar físicamente un conjunto de resultados y considera varios factores: existencia de índices en las columnas que participan en cláusulas JOIN y WHERE, distribución de datos y el tamaño de tabla para las tablas involucradas, etc., a fin de estimar la selectividad de la consulta. Cuando se genera un plan de ejecución para un procedimiento almacenado, además de todos estos factores, el optimizador considera también los parámetros que se envían en la invocación de procedimiento. El optimizador "huele" estos parámetros en las consideraciones del plan. Es posible que los parámetros no tengan ninguna influencia sobre la estructura y la selectividad de la consulta resultante, pero generalmente, los valores de parámetro afectan significativamente esa selectividad y el plan de ejecución generado. ¿Esto es malo? Podría ser. Si los valores de parámetro para las llamadas posteriores al procedimiento almacenado tienen valores similares (de hecho, cuando sus valores no cambian la selectividad de las consultas de procedimiento) el rastreo de parámetro es importante. De lo contrario podría reducir drásticamente rendimiento. Tomemos el siguiente procedimiento almacenado en la base de datos de Adventure Works como ejemplo:
Listado 1: Creación de muestra de procedimiento almacenado


Este procedimiento almacenado devuelve cuatro columnas de la tabla Ventas.SalesOrderHeader para un determinado SalesOrderID. Vamos a invocarlo por primera vez con el parámetro 45671. Como la columna SalesOrderID es una clave principal agrupada de la tabla, el plan de ejecución para este procedimiento es simple: una búsqueda de índice agrupado. Consulte la figura 1.
¿Así pues, dónde está aquí el rastreo de parámetros? Si elige la opción Mostrar XML… de Plan de ejecución puede obtener una representación XML del plan de ejecución. Bajo el nodo ParameterList se puede ver que tiene un valor ParameterCompiledValue de 45671 y este parámetro fue considerado por la generación del plan.


Figura 1: Plan de ejecución para el procedimiento almacenado del Listado 1



Figura 2: Versión XML del plan de ejecución para el procedimiento almacenado del listado 1 (fragmento)

Si lo llamamos nuevamente con otros parámetros (por ejemplo 56781) podemos ver que Parameter-CompiledValue todavía tiene el valor 45671; sólo cambió ParameterRuntimeValue.


Figura 3: Versión XML del plan de ejecución para el procedimiento almacenado del listado 1 con un parámetro diferente (fragmento)
El plan de ejecución generado es óptimo para el valor del parámetro 45671. ¿Es esto un problema? ¡Para nada! Este plan también es óptimo para el valor 56781. En realidad, para este procedimiento almacenado, solo tiene sentido un plan ejecución: una búsqueda de índice agrupado. El procedimiento devuelve exactamente una fila o un conjunto vacío, si no hay ningún pedido para un Id de pedido determinado. El valor del parámetro para la primera invocación del procedimiento almacenado no afecta a la selectividad de la consulta resultante. Esa es la razón por la que, en este caso, el efecto del rastreo de parámetros puede ser ignorado. Por supuesto es importante definir qué fila debe devolverse pero no afecta a la manera de Cómo devolver esta fila.
Listado 2: Crear procedimiento almacenado con el operador de rango

Sin embargo, cuando son posibles diferentes planes de ejecución, los valores de los parámetros en la primera invocación pueden decidir qué se utilizará para todas las invocaciones posteriores. Consulte el listado de 2.
​Si los valores de parámetro para las llamadas posteriores al procedimiento almacenado tienen valores similares (de hecho, cuando sus valores no cambian la selectividad de las consultas de procedimiento) el rastreo de parámetro es importante. De lo contrario podría reducir drásticamente rendimiento

Ahora tenemos dos planes de ejecución razonable:


Figura 4: Plan de ejecución para el procedimiento almacenado dbo.getSalesOrderHeader.
​El rastreo de parámetro no se limita a procedimientos almacenados sólo, sino que todos los parámetros de consultas puede ser susceptibles del rastreo de parámetros: consultas estáticas con parametrización simple, auto o forzada, o consultas dinámica con sp_executesql.

Qué se utilizará, es decidido por el valor del parámetro OrderDate para la primera invocación del procedimiento almacenado. Si el valor del parámetro es altamente selectivo (pocas filas en el conjunto de resultados) se generará el segundo plan, de lo contrario se analizará toda la tabla (análisis de índice agrupado). En este caso, no podemos ignorar cómo afecta el rastreo de parámetros. Algunas invocaciones al procedimiento almacenado terminan con un plan no óptimo. Y, por lo general, es un problema. Podría ser que el plan de ejecución sea óptimo para valores del parámetro altamente selectivos, vamos a decir, 95% de llamadas con el valor "óptimo” del parámetro. En este caso podemos decir que un 5% tiene un problema pero, esto, desde el punto de vista de la lógica comercial, no es tan importante para la aplicación. Sin embargo, el problema es que el plan de ejecución no permanece para siempre en la memoria caché. Podría ser eliminado (por muchas razones) y no tenemos control sobre cuando ocurre esto. Así, después de que el plan se elimina de la caché, es una lotería si la siguiente invocación viene con un valor de parámetro esperado.
El rastreo de parámetro no se limita a procedimientos almacenados sólo, sino que todos los parámetros de consultas puede ser susceptibles del rastreo de parámetros: consultas estáticas con parametrización simple, auto o forzada, o consultas dinámica con sp_executesql. En este artículo describiremos este fenómeno en los procedimientos almacenados.

¿Cuándo es un problema el rastreo de parámetros?
Hay dos tipos de procedimientos almacenados propensos a dar problemas con el rastreo de l parámetros:
• Procedimientos almacenados con parámetros que participan en los operadores de rango
• Procedimientos almacenados con parámetros opcionales
El procedimiento dbo.getSalesOrderHeader pertenece al primer grupo, y describimos en este artículo cómo resolver el problema del rastreo de parámetros en esos procedimientos almacenados. En el siguiente número de SolidQ analizaremos el problema de rastreo de parámetros en  procedimientos almacenados con parámetros opcionales.
Por lo tanto, ya hemos visto que los dos planes de ejecución son posibles para este procedimiento almacenado. Si la primera invocación fue con el valor 01.07.2001 se devuelven todas las filas y de acuerdo con esto, ha sido elegido agrupado por el optimizador un análisis del índice como plan de ejecución óptima.
SQL Server debe realizar 1.406 lecturas lógicas para generar un conjunto de resultados. Sin embargo, cuando el procedimiento almacenado se ha invocado por primera vez con el valor 31.07.2005, una llamada con el parámetro 01.07.2001, ¡termina con lecturas 94.456 lógicas! La figura 5 muestra el tiempo de ejecución para todas las combinaciones de valor del parámetro y los planes de ejecución apropiados:


Figura 5: Tiempo de ejecución para valores de parámetros selectivos altos y bajos
  
Podemos ver que una llamada con un parámetro de selectividad baja se ejecuta tres veces mejor con su plan óptimo, mientras que una llamada con un parámetro de alta selectividad se ejecuta mejor con un plan de ejecución que incluya una búsqueda por índice. El problema que plantea el rastreo de parámetros pone en evidencia cuándo un procedimiento almacenado se ejecuta con un plan que no es óptimo.

Resolver el problema del rastreo de parámetros
Antes de empezar a resolver problemas de rastreo de parámetros, tenemos que definir lo que queremos hacer. A continuación veremos Cómo para lograrlo. Uno de los conceptos erróneos acerca de rastreo de parámetros es que la solución para el problema sea desactivar el efecto. Este efecto no siempre es malo: podría ser muy malo, pero al mismo tiempo es una característica y su desactivación resuelve algunos problemas, pero pueden degradar el rendimiento de consultas bien diseñadas.
Aunque el rastreo de parámetros es un problema de rendimiento, su solución debe incluir los requerimientos del negocio. Como se mencionó anteriormente, el proceso de optimización:
• Considera valores de parámetros en la primera invocación del procedimiento almacenado
• Usa un plan de ejecución en caché para todas las llamadas posteriores del procedimiento almacenado
Este es el comportamiento predeterminado del optimizador y si no estamos satisfechos con el resultado de la optimización tenemos que cambiar uno de estos factores. Podemos sugerir al optimizador (o forzarlo) a no a tener en cuenta los parámetros de entrada para la generación del plan o sugerir que no debe utilizar el plan generado para todas las llamadas posteriores. En el primer caso, definimos un plan de ejecución "genérico" o un plan que se genera sin conocimientos acerca de los valores de parámetro y el plan se utiliza para todas las invocaciones. O simplemente podemos forzar al optimizador a que utilice un plan de ejecución óptimo para todas las combinaciones de parámetros.
Así, antes de empezar a resolver el problema debemos definir el objetivo de la optimización, es decir, lo que significa realmente resolver el problema. En nuestro procedimiento almacenado, una solución sería utilizar un plan de ejecución genérico. Esto significa que todas las llamadas de procedimiento almacenado se ejecutarán con el plan de ejecución, basado en el índice agrupado. Esto significa que los valores del parámetro que causen una baja selectividad utilizarán el plan óptimo y los demás son elegidos como víctimas y siempre utilizarán un plan que no es óptimo. Si esto es aceptable desde la lógica del punto de vista comercial, hemos definido el objetivo: mediante un plan de ejecución óptima de selectividad baja.

Enfoque 1: Actuar sobre el parámetro de rastreo mediante un Plan para todas las combinaciones de parámetros
Al adoptar este enfoque indicamos al optimizador que use algún plan de ejecución específico (con la sustitución de parámetros de entrada) o que ignore los parámetros de entrada.
Sustitución de parámetros de entrada
Cuando tenemos una combinación de parámetros muy utilizada podemos forzar al optimizador a que utilice esa combinación, siempre que cree un plan de ejecución. En este caso, nos aseguramos de que esta combinación se realiza bien siempre, independientemente de la existencia del plan en la memoria caché. En nuestro caso, podemos decidir optimizar la ejecución de parámetros de baja selectividad y utilizar el plan con el índice agrupado (plan de azul en la figura 5). Esto significa que los valores de parámetro que causen baja selectividad utilizarán un plan óptimo y los demás son elegidos como víctimas y siempre se utilizará el plan óptimo. Esto es una decisión lógica de negocio y debe ser aceptable desde el punto de vista de la lógica de negocio. En este caso, el rastreo de parámetros no está deshabilitado; en su lugar nos referimos a los valores de parámetro de entrada. La sugerencia de consulta OPTIMIZE fuerza al optimizador a generar un plan de ejecución óptimo para el valor de la sugerencia de consulta en vez de para el valor enviado por la primera invocación.

Con la sugerencia de consulta sustituimos el valor del parámetro presentado y el rastreo de parámetros no está deshabilitado. El optimizador lo considera en el proceso de generación del plan; sólo cambiamos el valor del parámetro enviado. Se trata de una solución cuando queremos garantizar que la ejecución está bien para una combinación favorita de parámetros. Esto es útil en escenarios donde hemos identificado a la combinación de parámetros más importante, 


Figura 6: solución con un plan genérico de ejecución
y forzamos una ejecución con el plan óptimo para esta combinación, mientras se ignoran los problemas de rendimiento con otras combinaciones. En la figura 6 podemos ver que esta solución asegura que el plan de selectividad baja se utilizará para todas las llamadas de procedimiento almacenado. Consulte la figura 6.
Deshabilitar el rastreo de parámetros
Desactivación el rastreo de parámetros es útil cuando el procedimiento almacenado tiene varios parámetros y no hay una combinación favorita de parámetros. Si no se conocen los valores de parámetro en tiempo de compilación, no hay nada que se descubrir.
Así es cómo los excluimos de las consideraciones del plan de ejecución. El resultado de la desactivación del rastreo de parámetro es, generalmente, un plan de "promedio" – no óptimo, pero aceptable para todas las combinaciones de parámetros. Tenemos tres opciones para deshabilitar o neutralizar el rastreo de parámetros: sugerencias de consulta, reescritura de consultas y buscar trazas de la bandera 4136.
Con sugerencias de consulta
Para deshabilitar el rastreo de parámetros nuevamente podemos utilizar la sugerencia de consulta OPTIMIZE.

Esta vez el optimizador recibe una sugerencia para omitir los valores de los parámetros enviados. Por lo tanto, se desconoce el valor y el optimizador utiliza la densidad de los valores de la tabla para estimar la cardinalidad. Con el operador de rango, eso significa que se espera aproximadamente un 30% de filas en el resultado, los que generalmente significa un plan de ejecución promedio con análisis de índice agrupado. Esta opción está disponible en SQL Server 2008.
Reescritura de consultas
El mismo efecto puede lograrse reescribiendo algo de código en el procedimiento almacenado. Consulte el listado 3,página 49.

Listado 3: Modificación de procedimiento almacenado mediante el uso de Variables locales

Introducimos una variable local y le asignamos el valor del parámetro. Dado que el optimizador compila el procedimiento almacenado en un proceso por lotes, el valor del argumento en la cláusula WHERE no se conoce. Por lo tanto, tenemos el mismo plan que con la sugerencia UNKNOWN.
Bandera de seguimiento 4136
En octubre de 2010, como parte de la actualización acumulativa, Microsoft proporcionó una opción para deshabilitar el rastreo de parámetros a nivel de instancia (KB980653). Cuando la bandera de seguimiento 4136 está habilitada, el rastreo de parámetros está deshabilitado para toda la instancia. Esto tiene el mismo efecto que poner la sugerencia  OPTIMIZE FOR UNKNOWN en todos los procedimientos almacenados y consultas enviadas al motor de base de datos. Esto suena muy restrictivo y peligroso y por lo tanto, todavía hay excepciones donde este indicador de traza no tiene ningún efecto: consulta que utilicen OPTIMIZE FOR o sugerencias de consulta RECOMPILE y procedimientos almacenados definidos con la opción WITH RECOMPILE.
Aunque esto aporta la flexibilidad necesaria y no rompe con nuestros esfuerzos de optimización ya implementados, el indicador de traza 4136 afecta a toda la instancia del servidor y debe considerarse como un último recurso para resolver problemas de rastreo de parámetros.
El enfoque con sugerencias de consulta tiene ventajas sobre la opción con variables locales porque las sugerencias de consulta no afectan a la lógica empresarial en un procedimiento almacenado y pueden aplicarse fuera del procedimiento. Combinando la sugerencia de consulta con otra gran característica de SQL Server: -las guías de planificación - podemos resolver problemas de rastreo de parámetros sin cambiar el código de la aplicación. Esto es muy importante para los sistemas en los que no se permiten cambios en el código o cuando un cambio de código pequeño es inaceptablemente caro (proyecto-recompilación, pruebas, implementación etc...).

Método 2: Un Plan óptimo para cada combinación de parámetro
Cuando se requiere que cada combinación debe tener un plan óptimo, la desactivación de rastreo de parámetros no nos facilita la tarea. Tenemos dos opciones para implementarlo: indicar al optimizador que genere (recompile) un nuevo plan para cada procedimiento almacenado o reescribir el procedimiento almacenado mediante el uso de otro procedimiento almacenado (procedimiento almacenado de árbol de decisión).
​Combinando la sugerencia de consulta con otra gran característica de SQL Server: -las guías de planificación - podemos resolver problemas de rastreo de parámetros sin cambiar el código de la aplicación.
Recompilar el Plan de ejecución
Esto puede hacerse con la sugerencia de consulta OPTION (RECOMPILE) o mediante la inclusión de la opción WITH RECOMPILE en la definición del procedimiento almacenado.
Listado 4: Procedimiento almacenado modificado cambiando la definición de procedimiento




Listado 5: Modificación de procedimiento almacenado mediante el uso de la sugerencia de consulta



En ambos casos se genera un nuevo plan para cada invocación de procedimiento. La diferencia es que OPTION (RECOMPILE) se realiza a nivel de instrucción y no se regeneran todas las sentencias del procedimiento almacenado, sino sólo las marcadas con esta opción. En nuestro caso es lo mismo, tenemos sólo una declaración. En el próximo número de SolidQ veremos las ventajas de compilar a nivel de instrucción. La figura 7 muestra que el plan de recompilar combina los planes iniciales para parámetros selectivos bajos y altos y es óptimo para todos los parámetros.


Figura 7: Solución con un plan óptimo para cada combinación de parámetros
Árbol de decisiones del procedimiento almacenado
Un procedimiento almacenado de árbol de decisiones decide que sub-procedimiento debería llamar basándose en los parámetros enviados. Vamos a mostrar esta solución. Consulte el listado de 6.
El procedimiento determina si la fecha enviada es de más de 10 días atrás. Si es así, llama a un procedimiento almacenado para parámetros de selectividad baja, de lo contrario se selecciona la versión para fechas con alta selectividad. Los sub-procedimientos tienen el mismo cuerpo de procedimiento y son idénticos al procedimiento almacenado inicial dbo.GetSalesOrder-Header. La figura 8 muestra los planes de ejecución para parámetros de alta y baja selectividad.
Listado 6: Modificar procedimientos almacenados mediante un procedimiento almacenado de árbol de decisión



Figura 8: Tiempo de ejecución para parámetros selectivos altos y bajos para el procedimiento almacenado de árbol de decisión.
Esta solución permite la reutilización de planes de ejecución y desde un punto de vista del rendimiento es mejor que la versión utilizando la opción recompile. Sin embargo, este enfoque está abierto a problemas de mantenimiento. Para cada combinación donde queremos reutilizar un plan existente necesitaríamos un sub-procedimiento. Por lo tanto, la solución sería inmanejable. Otro problema de mantenimiento es que las decisiones sobre lo que es altamente selectivo no son tan fáciles y deberían ser evaluadas y comprobadas regularmente para ver si siguen siendo apropiadas. Podemos combinar ambos enfoques creando suficiente sub-procedimientos para cubrir los planes más comunes y uno con la opción recompile para todas las demás combinaciones. Aún así, el número de procedimientos para cubrir los planes más comunes puede hacerse rápidamente inmanejable.
En este artículo hemos visto lo que es el rastreo de parámetro y cuándo y por qué resulta un problema. Hemos hablado de diferentes soluciones para problemas de rastreo de parámetros con procedimientos almacenados y del  uso de operadores de rango. El mes que viene veremos por qué los procedimientos almacenados con parámetros opcionales son propensos al problema del rastreo de parámetros y ofreceremos nuevamente varias soluciones.

Aqui les dejo lo mismo pero en pdf.

Espero que lo disfruten, compartan y comenten. ;)

"Si se puede imaginar... se puede programar."
 
Leer más...
Google