none
Refresco de la GUI muy lento RRS feed

  • Pregunta

  • Hola, tengo una aplicación que consta de algunas pestañas en las que tengo, en total, tres DataGridView y unas veinte Labels a las cuales actualizo a través de una consulta que hago por código a una base MySQL cada 5 segundos, para eso uso un Timer que llama a las rutinas que actualizan los diferentes DatagridView.

    El problema que estoy teniendo es que se suele ralentizar la GUI, es decir por unos segundos no responde a las acciones del usuario, muchas de ellas también implican una serie de consultas a la base de datos.Las funciones y rutinas las tengo dentro del Form principal, supongo que por eso ocurre esto.

    ¿Que puedo hacer para que la GUI funcione mas fluida?


    The Real Blue

    miércoles, 29 de mayo de 2013 13:44

Todas las respuestas

  • que antidad de registros cargas en los grid? porque una cosa son 10 0 20 y otra que cargues 100 o mil

    ademas no puedes esperar milagros, son 5 seg es muy poco tiempo entre cada actualizacion

    es decir por unos segundos no responde a las acciones del usuario

    es que deberias trabjar con thread, o sea lanzar la actualizacion en un hilo separado para no bloquear la UI

    podrias usar quizas el BackGroundWorker

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina

    miércoles, 29 de mayo de 2013 13:54
  • Una idea para ello sería realizar las consultas a la bbdd a través de otro hilo de ejecución que no sea el principal. usa para ello System.Threading


    Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó vótala como útil. Saludos

    miércoles, 29 de mayo de 2013 14:03
  • Por defecto son 35 registros pero se pueden llegar a pedir hasta 99 por cada DatagridView.

    The Real Blue

    miércoles, 29 de mayo de 2013 14:07
  • Es lo que estaba pensando pero no tengo mucha experiencia con el tema de hilos separados, por ejemplo no se si debo crear una clase o un modulo o si es algo distinto.

    Por otro lado si lanzo el hilo desde una parte del código de la GUI, ¿Esta no se quedaría esperando la respuesta del hilo?

    ¿O si presionan un botón distinto la GUI pasa a atender al nuevo evento que genero el ultimo botón presionado y luego vuelve al punto en que llamo al hilo?


    The Real Blue

    miércoles, 29 de mayo de 2013 14:12
  • Por otro lado si lanzo el hilo desde una parte del código de la GUI, ¿Esta no se quedaría esperando la respuesta del hilo?

    claro esa es la idea del hilo, realizar una tarea sin bloquear otra, o sea lanzarias la peticion de datos a la db pero no bloquearias la UI al usuario mientras esto se realiza

    en estos articulos se trata el tema

    http://social.msdn.microsoft.com/Forums/es-ES/vcses/thread/131ffa73-9e24-46f3-b493-986aecae488c/


    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina

    miércoles, 29 de mayo de 2013 14:15
  • ¿O si presionan un botón distinto la GUI pasa a atender al nuevo evento que genero el ultimo botón presionado y luego vuelve al punto en que llamo al hilo?

    si tienes alguna accion que podria afectar a la tarea del thread entonces deberias anularla

    si hay algun boton que podria interferir cuando lanzas el hilo podrias deshabilitar ese boton

    pero esto no causaria que la UI se bloquee y pareciera que se colgo la aplicacion


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina

    miércoles, 29 de mayo de 2013 14:16
  • Hola,puedes escribir el código del manejador de timer?? A lo mejor lo que te interesa es optimizar eso...y otra pregunta, tienes algún código que maneje algun evento del datagridview que realices consultas a la bbdd?


    Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó vótala como útil. Saludos

    miércoles, 29 de mayo de 2013 14:17
  • Gracias por la info, ya me pongo a leer.

    The Real Blue

    miércoles, 29 de mayo de 2013 14:20
  • Creo que como interferir no, pero si que genera otra consulta distinta a la base de datos.

    The Real Blue

    miércoles, 29 de mayo de 2013 14:21
  • No termino de entender tu pregunta, ¿Necesitas ver el código que estoy utilizando en el Timer?

    Respecto a la segunda pregunta, si, los tres DataGridView usan el evento CellMouseDoubleClick para capturar los datos de esa linea y desglosarla en Labels en un UserControl personalizado.


    The Real Blue

    miércoles, 29 de mayo de 2013 14:25
  • Me refería a que como don pocos registros tal vez con optimizar los accesos a bbdd y el posterior proceso podría ayudar a solventar mucho el problema, por eso te pedía el código. Mi segunda pregunta viene dada porque a lo mejor en algún evento del gridview como el cellformatting pudieras estar accediendo a la bbdd ya que eso ralentiza mucho pero parece que no es tu caso... 

    Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó vótala como útil. Saludos

    miércoles, 29 de mayo de 2013 14:30
  • Me refería a que como don pocos registros tal vez con optimizar los accesos a bbdd y el posterior proceso podría ayudar a solventar mucho el problema, por eso te pedía el código. Mi segunda pregunta viene dada porque a lo mejor en algún evento del gridview como el cellformatting pudieras estar accediendo a la bbdd ya que eso ralentiza mucho pero parece que no es tu caso... 

    Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó vótala como útil. Saludos

    Lo que estoy viendo es que la base tiene motor MyISAM y tal vez deba mudarme a Innodb porque una de las tablas tiene mucha concurrencia, tanto de lectura como de escritura y dado que MySAM lockea la tabla en cada consulta creo que eso debe hacer que la GUI de mi aplicación se congele pues no es la única aplicación que accede a esa tabla, también hay una pagina Web y una aplicación JAVA que hacen consultas a esa misma tabla la cual es muy pesada, del orden de los  10G.

    De todos modos sigo con la idea de generar Threads.


    The Real Blue


    miércoles, 29 de mayo de 2013 14:57
  • Si, esa es mi primera respuesta y la de Leandro. Sigue en ello. Suerte.

    Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó vótala como útil. Saludos

    miércoles, 29 de mayo de 2013 15:06
  • la aplciacion no se congela por el tipo de estructura que tenga tu db

    sino porque la accion de ir a consultar la db de por si requiere procesamiento y mientras ado.net trabaja con los datos este toma el control quitandoselo a la UI

    pero es algo que tiene que ver con el acceso a datos, si usarias sql server, oracle, etc sucederia lo mismo

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina

    miércoles, 29 de mayo de 2013 15:09
  • Hola,

    Yo creo que tu problema pasa por lo que tarda la consulta a la base de datos.

    Vos tenes que traer de la base 35 registros, pero cuantos registros tiene la tabla ?.

    Tal vez te este faltando definir indices en la tabla para que la busqueda de esos 35 registros sea mas rapida.


    Victor Koch

    miércoles, 29 de mayo de 2013 18:11
  • La tabla tiene 4 primary key, unos 100M de registros(rows) y alrededor de 30 columnas.

    The Real Blue

    jueves, 30 de mayo de 2013 13:15
  • Y supongo que la consulta se raliza a través de esos 4 campos no?? Para que use el indice

    Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó vótala como útil. Saludos

    jueves, 30 de mayo de 2013 13:23
  • Y supongo que la consulta se raliza a través de esos 4 campos no?? Para que use el indice

    Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó vótala como útil. Saludos

    Depende de como este configurado el programa usa dos o tres campos, pero la query, al menos desde mi punto de vista, es bastante compleja porque es un JOIN de 4 tablas, es decir la tabla grande que comente arriba y tres tablas chicas de no mas de 30K registros.

    Dos de los 5 DataGridView se rellenan usando querys similares.


    The Real Blue

    jueves, 30 de mayo de 2013 14:44
  • Hola

    Porque no mostras la query y que indices tienen las tablas que intervienen.  


    Victor Koch

    jueves, 30 de mayo de 2013 19:24
  • Hola

    Porque no mostras la query y que indices tienen las tablas que intervienen.  


    Victor Koch

    Las tablas involucradas y sus Primary Key son:

      
                 clientes.NotifyQueue PK-->    accountID,deviceID,ruleID,timestamp,statusCode,messageID
                    clientes.StatusCode PK-->     accountID,deviceID,statusCode               
                    clientes.Account PK-->       accountID
                    clientes.Device  PK-->        accountID,deviceID


    Una de las Query es:

    cmd.CommandText = "SELECT NotifyQueue.accountID,NotifyQueue.deviceID,NotifyQueue.ruleID,NotifyQueue.timestamp," & _
                         " UCASE(NotifyQueue.deviceID) AS 'Patente',HEX(NotifyQueue.statusCode)AS 'Evento',subject AS 'Evento',FROM_UNIXTIME(NotifyQueue.timestamp,'%d/%m/%Y %H:%i:%s')" & _
                    "AS 'Fecha Reporte',Account.description AS 'Empresa',StatusCode.foregroundColor AS 'Color'" & _
                    "FROM(clientes.NotifyQueue, clientes.StatusCode,clientes.Account,clientes.Device)WHERE StatusCode.statusCode=NotifyQueue.statusCode AND Account.accountID=NotifyQueue.accountID AND StatusCode.accountID='sysadmin' AND fechaAtendido IS NULL AND operador IS NULL " & _
                    " AND assignedUserID='" & GrupoUsuario & "' AND Device.deviceID=NotifyQueue.deviceID AND Device.accountID=NotifyQueue.accountID ORDER BY timestamp ASC LIMIT " & Limit & ";"

    ¿Crees que se puede mejorar para hacer la consulta mas rápidamente?


    The Real Blue


    viernes, 31 de mayo de 2013 13:54
  • Creo que tienes alguna relación mal, te falta hacer la relacion de statuscode con notifyqueue con deviceid y accountid.... prueba esta consulta en tu servidor ok??

    SELECT NotifyQueue.accountID,NotifyQueue.deviceID,NotifyQueue.ruleID,NotifyQueue.timestamp, 
    UCASE(NotifyQueue.deviceID) AS 'Patente',HEX(NotifyQueue.statusCode)AS 'Evento',subject AS 'Evento',FROM_UNIXTIME(NotifyQueue.timestamp,'%d/%m/%Y %H:%i:%s')
    AS 'Fecha Reporte',Account.description AS 'Empresa',StatusCode.foregroundColor AS 'Color'
    FROM
    clientes.NotifyQueue 
    INNER JOIN clientes.Account ON Account.accountID=NotifyQueue.accountID
    INNER JOIN clientes.StatusCode ON StatusCode.statusCode=NotifyQueue.statusCode 
    	AND StatusCode.deviceID=NotifyQueue.deviceID 
    	AND StatusCode.accountID=NotifyQueue.accountID
    INNER JOIN clientes.Device ON Device.deviceID=NotifyQueue.deviceID 
    	AND Device.accountID=NotifyQueue.accountID
    
    WHERE AND  AND StatusCode.accountID='sysadmin' AND fechaAtendido IS NULL AND operador IS NULL  
      AND assignedUserID='GrupoUsuario' 
    ORDER BY timestamp ASC LIMIT Limit;


    Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó vótala como útil. Saludos

    viernes, 31 de mayo de 2013 14:09
  • Tu consulta cuanto tarda??

    Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó vótala como útil. Saludos

    viernes, 31 de mayo de 2013 14:17
  • Hola,

    Supongo que la tabla NotifyQueue es la tabla con 100M de registros y los campos FechaAtendido y Operador son de esa tabla, si es asi deberias tener un indice por cada uno de esos campos.

    Tambien estoy suponiendo que el campo assignedUserID pertenece a la tabla Account, tambien deberias tener un indice por ese campo.

    Si lo que supongo es asi proba con esta SQL:

    cmd.CommandText = "SELECT NotifyQueue.accountID,NotifyQueue.deviceID,NotifyQueue.ruleID,NotifyQueue.timestamp," & _
                      " UCASE(NotifyQueue.deviceID) AS 'Patente',HEX(NotifyQueue.statusCode) AS 'Evento',subject AS 'Evento',FROM_UNIXTIME(NotifyQueue.timestamp,'%d/%m/%Y %H:%i:%s')" & _
                      " AS 'Fecha Reporte',Account.description AS 'Empresa',StatusCode.foregroundColor AS 'Color'" & _
                      " FROM NotifyQueue, StatusCode, Account, Device" & _
                      " WHERE NotifyQueue.fechaAtendido IS NULL AND NotifyQueue.operador IS NULL AND StatusCode.accountID='sysadmin' AND Account.assignedUserID='" & GrupoUsuario & "'" & _
                      " AND StatusCode.statusCode=NotifyQueue.statusCode AND Account.accountID=NotifyQueue.accountID " & _
                      " AND Device.deviceID=NotifyQueue.deviceID AND Device.accountID=NotifyQueue.accountID ORDER BY NotifyQueue.timestamp ASC LIMIT " & Limit 


    Victor Koch

    viernes, 31 de mayo de 2013 15:59
  • Creo que tienes alguna relación mal, te falta hacer la relacion de statuscode con notifyqueue con deviceid y accountid....

    Es que esas columnas no figuran en las tablas que dices.

    The Real Blue

    viernes, 31 de mayo de 2013 19:33
  • Hola,

    Tambien estoy suponiendo que el campo assignedUserID pertenece a la tabla Account, tambien deberias tener un indice por ese campo.Victor Koch

    No assignedUserID pertenece a la tabla Device.


    The Real Blue

    viernes, 31 de mayo de 2013 19:38
  • Hola

    Porque no mostras la query y que indices tienen las tablas que intervienen.  


    Victor Koch

    Las tablas involucradas y sus Primary Key son:

      
                 clientes.NotifyQueue PK-->    accountID,deviceID,ruleID,timestamp,statusCode,messageID
                    clientes.StatusCode PK-->     accountID,deviceID,statusCode               
                    clientes.Account PK-->       accountID
                    clientes.Device  PK-->        accountID,deviceID

    Aqui indicas expesamente los campos que te dije que creo que te faltan por realizar los join y me respondiste que no pertenecen  a la tabla....

           AND StatusCode.deviceID=NotifyQueue.deviceID 
    	AND StatusCode.accountID=NotifyQueue.accountID


    Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó vótala como útil. Saludos

    sábado, 1 de junio de 2013 6:37
  • Ah, ok, interprete mal tu respuesta cuando dijiste

    Creo que tienes alguna relación mal, te falta hacer la relacion de statuscode con notifyqueue con deviceid y accountid.... prueba esta consulta en tu servidor ok??

    Como vi deviceID y accountID en la misma oración interprete que statusCode era una columna también a la que te referías y esa solo esta en la tabla StatusCode.

    El lunes pruebo tu query, gracias.


    The Real Blue

    sábado, 1 de junio de 2013 20:45