sábado, 29 de septiembre de 2012

SqlServer, plan de consulta y optimización (Tuning) (2)

SqlServer, plan de consulta y optimización (Tuning) (2)


Datos correlacionados

En la entrada anterior hablamos sobre cuando puede fallar el optimizador, que podría hacer fallar el path suboptimo pensado por el motor.
Se me ha hecho muy fácil engañar algunos motores y hacerles meter la pata, con sql server se complica un poco mas y las situaciones por donde podemos hacer "pinchar" al optimizador son pocas. Una de ellas es tener datos correlacionados.
Para el ejemplo de la entrega vamos a manejarnos con una tabla de vehiculos con campos marca, modelo y motor, la tabla seria la siguiente:

Tabla


CREATE TABLE [dbo].[Vehiculo](
[IdVehiculo] [int] IDENTITY(1,1) NOT NULL,
[Dominio] [char](20) NOT NULL,
[Observacion] [text] NOT NULL,
[Marca] [char](20) NOT NULL,
[Modelo] [char](20) NOT NULL,
[Motor] [char](20) NOT NULL,
 CONSTRAINT [PK_Vehiculo] PRIMARY KEY CLUSTERED
(
[IdVehiculo] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

En la misma insertamos aproximadamente 100000 VW GOL POWER con motor VW 1.6, insertamos también alrededor de 50000 de otros vehículos, de otras marcas y modelos 


¿Porque es difícil que se equivoque el sql server?


El sql server maneja estadísticas para tablas con mas de 500 registros con una buena precisión, el sql server sabe en muchos casos, y por ejemplo para nuestra tabla de vehículo  cuantos FIAT, cuando VW o cuantos FORD hay, sabe también cuantos GOL POWER hay y cuantos PALIO (Las estadisticas las fue generando a medida que se ejecutaron selects con condiciones de selección aplicadas a los campos).
Si pidiéramos al sqlserver que nos retorne todos los vehículos PALIO el mismo sabría con buena precisión cuantos hay, escogería una estrategia de búsqueda adecuada.

Lo que no sabe y no puede saber es la correlación que existe entre, por ejemplo, el modelo GOL POWER y la marca VW, hay una relación estricta entre marca y modelo y sí alguien podría decir,

-El problema es que la base esta mal diseñada, deberías tener tabla de modelos y tabla de marcas, ambas relacionadas

Si es cierto para este caso, la realidad es que las bases con las que nos toca trabajar no siempre están bien diseñadas y ademas hay casos donde la relación es muy estrecha pero no definitiva.
Por ejemplo si preguntáramos Franceses que hablan Francés obtendríamos a casi todos los Franceses, pero no necesariamente a todos.
En cualquier caso si pidiéramos al SqlServer que nos retorne todos los VW que son GOL POWER es probable que lo pongamos en un aprieto a la hora de estimar la cantidad de registros que retornaría la consulta, una mala estimación de este tipo desencadena una serie de malas decisiones a la hora de elegir la estrategia de join, la estrategia de búsqueda etc.

En las ultimas versiones de sql server (2008 o superior) existe la posibilidad de explicarle al motor la situación mediante indices especiales, es una opción valida pero algo oscura.
Me da la sensación que esos indices tan específicos pueden generar problemas entre implementaciones o durante el ciclo de vida de la base de datos si no se tiene control de su existencia y de su carácter especifico.

Miren todos como se equivoca el sql server



En la siguiente imagen se puede ver la pésima estimación que hace el sqlserver .






















Si examinamos el plan de consulta el mismo espera recibir algo así como 1125 filas, veamos que fue lo que efectivamente recibimos luego de ejecutar la consulta...















La consulta devolvió 100001 registros, la diferencia es importante en una tabla con 150000 registros, y como se menciono antes ya no se puede esperar mucho del plan de consulta después de semejante error.

En la próxima entrada vamos a ver como este error degenera en la perdida de rendimiento de la consulta.




viernes, 28 de septiembre de 2012

SqlServer, plan de consulta y optimización (Tuning) (1)

SqlServer, plan de consulta y optimización (Tuning) (1)


De mi parte, siempre di la derecha al plan de consulta que el motor escogía, si el rendimiento no es el esperado sera porque diseñe mal la base o porque me faltan indices o directamente porque el software esta trabajando de manera incorrecta. Tengo desarrollos completos, algunos de tiempo real con bastante exigencia al motor donde la cantidad de planes de consulta forzados en todo los módulos del software es 0.

Hace mucho años trabajando para una compañía bastante grande observaba horrorizado como se había instalado la cultura de crear la consulta e indicar porque indice ir.
Meses después tuve mi revancha cuando nos mandaron a todos a hacer un curso de tuning de sql, y si no fue lo primero, lo segundo que dijo el instructor fue “No fuercen el plan de consulta, es muy probable que no tengan el conocimiento y la cantidad de información necesaria para hacerlo”
Los mismo dice microsoft en su msdn, traducción mediante “Típicamente sqlserver encuentra el mejor plan posible, no lo cambie salvo que sea un experto programador o experto administrador de base de datos”.

Probablemente todos nos sentimos expertos programadores, sea así o no, con eso no alcanza. Ademas de la experiencia se necesita conocimiento del modelo, de los indices y de la distribución y naturaleza de la información, en la mayoría de los casos conocer todo esto es poco probable y casualmente el sqlServer (Correctamente configurado) en sus estadísticas tiene esta información con un nivel de confiabilidad superior al 80%.

Entonces si no hay posibilidades de mejora y el motor es perfecto ¿Por que existen los hints?
Bueno de hecho el motor sí se equivoca, poco, pero se equivoca con especial énfasis en las siguientes situaciones:


  1. Datos correlacionados
  2. Poda por heuristica
  3. Bug optimizador
  4. Estadísticas no actualizadas


¿Entonces modifico o no el plan de consulta?

Entiendo que modificar el plan de consulta es la solución mas tentadora a un problema de rendimiento, generalmente parece ser también la solución menos probable hasta puede ofrecer mejoras marginales en muchos casos.
En posteriores entradas voy a intentar desgranar situaciones donde malos diseños, bugs del optimizador, datos correlacionados, podas o malas estadísticas puedan hacer que el sql se equivoque groseramente.




martes, 25 de septiembre de 2012

Desarrollo WAP en Visual Web Developer 2010


Primero, si buscan los templates para desarrollo wap en visual studio 2010 notaran que ya no existen. Los componentes aun vienen pero la gente de microsoft argumenta que ya no tiene sentido incorporar al IDE los mismos, o disponibilizar templates dado que es un tipo de desarrollo obsoleto.
Cualquier dispositivo móvil moderno soporta html básico, el soporte para desarrollo WAP no parece ser una necesidad.
Esto es casi cierto, me ha tocado desarrollar una pequeña aplicación para dispositivos móviles, y los dispositivos móviles no soportaban html, solo WAP.

¿Como podemos encarar este desarrollo?
¿Sera necesario instalar un viejo Visual Studio 2003?
No necesariamente, veamos los pasos para un efectivo desarrollo.

1.Descargar templates



Primero tenemos que descargar los templates para forms WAP, estos template pueden ayudar, se pueden descargar de aquí:


Luego descomprimir y seguir las instrucciones, las cuales básicamente dicen de colocar los templates en la carpeta

[My Documents]\Visual Studio 2010\Templates\ItemTemplates\Visual C#

o si prefiere

C:\Users\FulanoDeTal\Documents\Visual Studio 2010\Templates\ItemTemplates\Visual Web Developer

2.Si todo fue bien cree una Aplicación WEB ASP.NET vacía




 3.Luego Agregar->Nuevo elemento y seleccione Mobile Web Form.




Ahora tenemos nuestro mobile web form, el cual vamos a editar y efectivamente puede ser accedido desde equipos que solo manejan WAP.

La mala noticia:

No estará disponible el diseño visual.




La buena noticia:

Tampoco es estrictamente necesario, la interfaces WAP son tan pobres y la cantidad de componentes tan pocos que no debería quitarnos el sueño no tener el tan cómodo diseñador visual, especialmente para quienes no son totalmente del palo web.

4.Diseñar


Bien, como dijimos no tenemos diseñador visual, ¿Como hacemos?
Bueno ayudarse con el asistente de VS para ir armando el formulario, es muy similar a un formulario html. Colocar el carácter “<” escribir “mob” y alli aparecerán las opciones de componente, como es de esperar muy pocos pero suficientes para lo que tenemos que hacer, que también seguramente sera muy simple (No se le puede pedir mucho a una aplicación WAP).




Recordar agregar las referencias al asembly con los componentes mobile...puedes usar con copia local si te trae problemas



El código abajo muestra como quedaría el formulario. Observe que he creado dos textbox, los he identificado como Runat=”Server”, les he puesto un ID como corresponde y otras propiedades adicionales cuando fue necesario.
También puse un command, algo asi como el botón de asp.net en webforms, he declarado también y codificado la función DoClick y se la he asignado al OnClick del comando. Si no me he equivocado con los nombre cuando se haga click sobre el boton se deberia ejecutar mi evento DoClick. A no tener miedo de usar los textbox del lado servidor, ya están disponibles como indica el código.


<%@ Page Language="C#" AutoEventWireup="true" Inherits="WAPTEST.WAPLogin" Codebehind="WAPLogin.aspx.cs" %>
<%@ Register TagPrefix="mobile" Namespace="System.Web.UI.MobileControls" Assembly="System.Web.Mobile" %>

<html xmlns="http://www.w3.org/1999/xhtml" >
<body>
<mobile:Form id="Form1" runat="server">
Usuario: <mobile:TextBox Runat="server" ID="tbUsuario"></mobile:TextBox>
Password: <mobile:TextBox Runat="server" ID="tbPassword" Password="True"
></mobile:TextBox>
<mobile:Command ID="btnAceptar" Runat="Server" OnClick="DoClick">Aceptar</mobile:Command>
</mobile:Form>
</body>
</html>



  




using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.Mobile;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.MobileControls;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

namespace WAPTEST
{
public partial class WAPLogin : System.Web.UI.MobileControls.MobilePage
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }
    protected void DoClick(object sender, EventArgs e)
    {
      //Codificar aca....
      //Se tiene acceso a los controles sin problemas por ej.  
      //string s = tbUsuario.Text; es perfectamente posible. 

    }



}
}


Aca el resultado en un navegador


Aca en un navegador wap