Page 1 of 2
TxBrowse y ADS query - SOLUCIONADO
Posted: Tue Jul 17, 2012 12:15 pm
by rolando
Buen día,
Uso ADS y, hasta ahora, luego de realizar un query a la DBF, lo que hacía era pasar a un array lo obtenido del query (en mi caso en sqlarea).
Código simplificado:
Code: Select all
if ADSExecuteSQLDirect( cConsulta1 )
sqlarea->(dbgotop())
do while sqlarea->(!eof())
Aadd(aArray , {alltrim(str(sqlarea->TALON)) , alltrim(sqlarea->NOMBRE)} )
sqlarea->( DbSkip())
enddo
xBrowse(aArray)
Esto funciona bien ya que luego en el xBrowse hago un "oBrw:SetArray( aArray , .t. )" y le asigno el array para hojear
Ahora se me presenta que los datos obtenidos de una DBF (siempre con un query), son muchos y el query es respondido casi en forma instantánea quedando los datos en "sqlarea", tal como lo compruebo con este código simplificado en el que me mustra los diez primeros datos:
Code: Select all
sqlarea->(dbgotop())
for f = 1 to 10
msginfo(sqlarea->TALON+" "+sqlarea->NOMBRE)
sqlarea->( DbSkip())
next
Pero como decía antes, como los datos tomados son muchos (más de 10000), el armado del array tarda muchísimo (casi dos minutos).
Por esto consulto: ¿hay alguna forma en que pueda
"asignarle" el resultado del query en forma directa al xBrowse?. Como si fuese una oDBF o similar para de esta manera evitar el armado del array con el resultado del query que es lo que más demora la ejecución del xBrowse.
Gracias.
Rolando
Re: TxBrowse y ADS query - Necesito Ayuda
Posted: Tue Jul 17, 2012 4:19 pm
by Raymundo Islas M.
Rolando,
Yo no uso ADS pero en MySQL ya que tienes los datos en un recordset con solo usar aDatos := oRS:GetRows() te pasa casi al instante los datos en un arreglo y lo he hecho con mas de 25,000 registros.
Cuestion de que cheques si el recordset de ADS maneje las mismas propiedades que MySQL.
Saludos
Re: TxBrowse y ADS query - Necesito Ayuda
Posted: Tue Jul 17, 2012 5:05 pm
by Patricio Avalos Aguirre
rolando
trata de no usar aadd ya que eso es lo que te hace que se relentice
prueba usar este codigo
Code: Select all
sqlarea->(dbgotop())
aArray := array(sqlarea->(lastrec()),2)
i := 0
sqlArea->( dbEval( { || aEval( aArray[++i], { |x,y| aArray[i,y] := FieldGet( y ) } ) } ) )
Re: TxBrowse y ADS query - Necesito Ayuda
Posted: Tue Jul 17, 2012 5:56 pm
by carlos vargas
La manera correcta es la que indica Patricio, haces de una sola vez el arreglo teniendo el numero de filas obtenidas en la consulta
y volcarlo usando un dbeval. el usar aadd por cada fila es muy lento.
Reymundo, el aDatos := oRS:GetRows() es usando record set de odbc, donde getRows en un metodo de objeto RecordSet?
respeta los tipo tipos de datos de harbour?
salu2
carlos vargas
Re: TxBrowse y ADS query - Necesito Ayuda
Posted: Tue Jul 17, 2012 5:59 pm
by RSalazarU
Rolando:
Yo uso el resultado de las consultas como si fuera una tabla DBF, esa es la "magia" del RDD.
Si has usado xBrowse para mostrar una DBF, haz lo mismo con la consulta ADS.
Mirando tu codigo, debes tener una instruccion previa :
Code: Select all
ADSCreateSQLStatement(cAlias,2,nConnect)
Tienes que usar
cAlias en forma similar al alias que se usa cuando se abre una DBF.
Code: Select all
DbUseArea( .T., "DBFCDX" , "Orders", cAlias )
Debes usar
sqlArea en el xBrowse para mostrar la consulta, asi evitas el uso de array; sqlArea es el alias de la consulta/tabla.
Avanzando un poco mas hacia MySql y otros manejadores de bases de datos,
si no me equivoco, deberiamos crear un RDD que nos permitiria manejar las tablas de la forma similar a como lo hacemos con las DBF.
Al hacer esto
NO NOS ESTARIAMOS QUEDANDO ATRAS con el majeno tradicional de las DBFs y
NO PERDERIAMOS la potencia de SQL.
Yo uso
ADSRDD y tengo unas consultas SQL
"espectaculares" que me costaria mucho hacerlas por el metodo tradicional.
Esperando no molestar a nadie, yo creo que los que estan creando/desarrollando las lib que permiten el acceso a MySql deberian orientarlas hacia el desarrollo de un RDD.
Estudiar y comprender los RDD es algo muy complejo y mucho trabajo, pero vale la pena.
Atentamemnte,
Rolando
Cochabamba, Bolivia.
Re: TxBrowse y ADS query - Necesito Ayuda
Posted: Tue Jul 17, 2012 6:49 pm
by Marcelo Via Giglio
Rolando,
como te explico tu tocayo
prueba tan solo esto en tu código (claro con todo lo previo como ADSCreateSQLStatement ......)
Code: Select all
ADSExecuteSQLDirect( cConsulta1 )
xbrowse()
veras la magia del RDDADS, ya que una consulta la devuelve como un cursor (qeu puede ser una tabla ADT o DBF según lo pidas), este es estático cuando la información de la consulta proviene de mas de una fuente de información, es decir un join, o columnas creadas por ti, ya sea por valores calculados o otro tipo de información. Y creará un cursor dinámico si es que la información solo proviene exclusivamente de una sola tabla.
Ahora cual la diferencia de estos cursores, uno estático su modificación no implica modificación de la tabla origen, por otro lado una modificación en un cursor dinámico implicara la modificación del origen.
Prueba y nos comentas
saludos
Marcelo
Re: TxBrowse y ADS query - Necesito Ayuda
Posted: Tue Jul 17, 2012 7:42 pm
by Patricio Avalos Aguirre
Estimados
El unico problema que he visto en usar este metodo directo de la consulta a un xbrowse que no puedes usar indice
eso por lo menos yo no he podido
alguno de ustedes ha podido?
Re: TxBrowse y ADS query - Necesito Ayuda
Posted: Wed Jul 18, 2012 12:09 am
by rolando
Gracias a todos por responder.
Patricio: probé con tu código y es tres segundos más lento que usando aadd().
Raymundo: no encontré información respecto a lo que propones.
Rolando: Probé como indica Marcelo, pero como son más de 30000 registros y en cada unos hay 27 campos, lo que tarda en armarse el xbrowse() antes de ser mostrado es una eternidad.
Tú sugieres que use el sqlarea como si fuera un alias pero no entiendo como asignarlo a la xBrowse. Creo que con:
Code: Select all
DbUseArea( .T., "DBFCDX" , "Orders", cAlias )
Estaría indicando que el area activa es el de la ORDERS.DBF y no veo la relación para asignarle el sqlarea al xBrowse.
Lo que quisiera lograr es que responda en tiempo tal cual lo hace el Architect cuando se hace un query, es "INSTANTANEO" y además, en el browse que sale en la parte inferior se puede avanzar o retroceder en forma rápida. ¿Como lo hace?.
Saludos
Rolando
Re: TxBrowse y ADS query - Necesito Ayuda
Posted: Wed Jul 18, 2012 2:43 am
by Marcelo Via Giglio
Rolando,
muestra mas de tu código, si tarda en mostrar el xBrowse, no es porque tarde en armarse, yo supongo que es por la consulta SQL
saludos
Marcelo
Re: TxBrowse y ADS query - Necesito Ayuda
Posted: Wed Jul 18, 2012 1:07 pm
by rolando
Hola Marcelo,
Adjunto una prueba (código resumido) del query y el xBrowse.
Te comento que al query lo ejecuta en forma instantánea (tal como si fuese al Architect), esto lo detecto por el msgsound() que sale después de la consulta.
Luego de ello, se abre un xBrowse vacío cuya imagen parpadea unas cuantas veces y tarda un par de minutos en mostrarse el contenido. Cuando el contenido es mostrado, el desplazamiento entre celdas es muy lento.
Es de destacar que los registros que cumplen con la condición del query son alrededor de 30000, pero ese mismo query hecho en el architect, es mostrado al instante en su browse propio y el desplazamiento entre celdas es instantáneo. También destaco que si cambio el query y, la cantidad de registros encontrados baja a 5000, el xBrowse "se arma" más rápido y el desplazamiento entre celdas es también más rápido.
Esto lo uso en red local.
Code: Select all
#INCLUDE "FIVEWIN.Ch"
#include "xbrowse.ch"
#include "ADS.CH"
REQUEST HB_LANG_ES
REQUEST DBFCDX, DBFFPT
REQUEST ADS,ADSKeyCount,ADSKeyNo,OrdKeyCount,OrdKeyNo, AdsGetRelKeyPos, AdsSetRelKeyPos,DBFCDX
Function PruebaADS()
local cCarpetaInstalacion:="\\Pcdellocal\D\RJCtaller" , cFechaDesde:="01/01/1976" , cFechaHasta:="01/07/2012"
local cServer := cCarpetaInstalacion+"\DBF's\"
local lConect:=.f.
cConsulta1:="Select TALON, NOMBRE, DIRECCION, LOCALIDAD, BARRIO, CODPOSTAL, TELEFONO1, TELEFONO2, "+;
"CELULAR, EMAIL, ARTEFACTO, MARCA, MODELO, SERIE, UBICADO, FECHAIN, "+ ;
"FECHALIQUI, FINALIZADO, RETIRO, FECHA_COM, DETALLECL, DETALLETA, "+;
"ESTADO, DEALER, GARANTIZA, STATUS from TRABAJOS where "+;
"(FECHAIN>='"+cFechaDesde+"' and FECHAIN<='"+cFechaHasta+"'"+;
" or "+;
"FECHALIQUI>='"+cFechaDesde+"' and FECHALIQUI<='"+cFechaHasta+"'"+;
" or "+;
"RETIRO>='"+cFechaDesde+"' and RETIRO<='"+cFechaHasta+"')"
ADSSETDATEFORMAT("DD/MM/YYYY") // agregado por sugerencia foro fwh
RddRegister("ADS",1)
RddSetDefault("ADS")
AdsSetServerType ( 2 )
SET FILETYPE TO CDX
DbSelectArea( 0 ) // agregado por MArio
AdsConnect( cServer , 2 )
IF ! ADSCreateSQLStatement("SQLarea",2) // 2 == ADS_CDX
MsgAlert( "ADSCreateSQLStatement('SQLarea',2)" )
RETU .F.
ENDIF
if ADSExecuteSQLDirect( cConsulta1 )
msgsound(cCarpetaInstalacion+"\Sonidos\laser.wav") // con esto detecto que el query es respondido al instante
sqlarea->(dbgotop())
// sqlarea->(xBrowse()) // esto funciona igual
xBrowse() // es muy larga la espera para visualizar el xBrowse
endif // de if ADSExecuteSQLDirect( cConsulta1 )
AdsDisconnect()
sqlarea -> ( dbclosearea() )
Return nil
Gracias.
Rolando
Re: TxBrowse y ADS query - Necesito Ayuda
Posted: Wed Jul 18, 2012 1:23 pm
by Patricio Avalos Aguirre
Rolando:
Al parecer es problema de la consulta
trata de acotar la consulta colocando parentesis "(" ya que si la primera cumple la condicion ya no evalua la siguiente
lo otro es crear un indice por fechain, fechaliqui y retiro, prueba y nos cuenta
Code: Select all
cConsulta1:="Select TALON, NOMBRE, DIRECCION, LOCALIDAD, BARRIO, CODPOSTAL, TELEFONO1, TELEFONO2, "+;
"CELULAR, EMAIL, ARTEFACTO, MARCA, MODELO, SERIE, UBICADO, FECHAIN, "+ ;
"FECHALIQUI, FINALIZADO, RETIRO, FECHA_COM, DETALLECL, DETALLETA, "+;
"ESTADO, DEALER, GARANTIZA, STATUS from TRABAJOS where "+;
"(FECHAIN>='"+cFechaDesde+"' and FECHAIN<='"+cFechaHasta+"')"+;
" or ("+;
"FECHALIQUI>='"+cFechaDesde+"' and FECHALIQUI<='"+cFechaHasta+"')"+;
" or "+;
"(RETIRO>='"+cFechaDesde+"' and RETIRO<='"+cFechaHasta+"')"
pd. has probado la consulta en el architec al desplazarte por el browse has notado que tambien demora?
Re: TxBrowse y ADS query - Necesito Ayuda
Posted: Wed Jul 18, 2012 2:09 pm
by rolando
Patricio,
Ya había probado colocando paréntesis, y lo hice nuevamente pero no varía nada. Como dije, el query es inmediatamente ejecutado (lo compruebo con un msgsound() que me indica cuando terminó).
Respecto del Architect, Es de destacar que los registros que cumplen con la condición del query son alrededor de 30000, pero ese mismo query hecho en el architect,
es mostrado al instante en su browse propio y el desplazamiento entre celdas es instantáneo.
Gracias.
Rolando
Re: TxBrowse y ADS query - Necesito Ayuda
Posted: Wed Jul 18, 2012 3:15 pm
by carlos vargas
aca un ejemplo que usa una consulta volcada a un dbf temporal, crea indices temporales
y luego mostrado en un browse
Code: Select all
PROCEDURE RepCobros_XRuta()
LOCAL cSql
LOCAL cTitulo, cNomRuta
LOCAL nNumRuta, lTodos, dFecIni, dFecFin
LOCAL aRetorno := NIL
aRetorno := Seleccionar2_RutaRango()
IF aRetorno = NIL
RETURN
ELSE
nNumRuta := aRetorno[ 1 ]
lTodos := aRetorno[ 2 ]
dFecIni := aRetorno[ 3 ]
dFecFin := aRetorno[ 4 ]
ENDIF
IF ADSRunSQL( "TEMP", "SELECT NOMBRE FROM RUTAS WHERE NUM_RUTA=%1", { nNumRuta } )
cNomRuta := RTrim( TEMP->NOMBRE )
TEMP->( DBCloseArea() )
ELSE
RETURN
ENDIF
IF lTodos
cSql := RepCobros_Sql( 3 )
IF !ADSRunSQL( "TEMP", cSql, { nNumRuta } )
RETURN
ENDIF
cTitulo := "Lista de cobro de la ruta: " + cNomRuta
ELSE
cSql := RepCobros_Sql( 4 )
IF !ADSRunSQL( "TEMP", cSql, { nNumRuta, dFecIni, dFecFin } )
RETURN
ENDIF
cTitulo := "Lista de cobro de la ruta: " + cNomRuta + "/ [ Desde el: " + DToC( dFecIni ) + " hasta el: " + DToC( dFecFin ) + "]"
ENDIF
TEMP->( RepCobros_Lista( cTitulo ) )
TEMP->( DBCloseArea() )
RETURN
Code: Select all
STATIC FUNCTION RepCobros_Sql( n )
LOCAL cSql
cSQL := "SELECT {static} MOV.NUM_PRES, MOV.NUM_CLIE, CLI.NOMBRE, CLI.CEDULA, MOV.FECHA, MOV.HABER, MOV.SALDO, "
cSQL += " CIU.NOMBRE AS CIUDAD, RUT.NOMBRE AS RUTA "
cSQL += " FROM MOVIMIENTOS AS MOV "
cSQL += " LEFT OUTER JOIN CLIENTES AS CLI ON CLI.NUM_CLIE=MOV.NUM_CLIE "
cSQL += " LEFT OUTER JOIN CIUDADES AS CIU ON CIU.NUM_CIUD=CLI.NUM_CIUD "
cSQL += " LEFT OUTER JOIN RUTAS AS RUT ON RUT.NUM_RUTA=CLI.NUM_RUTA "
DO CASE
CASE n == 1
cSql += "WHERE MOV.HABER>0 AND MOV.DEBE=0 AND CLI.NUM_CIUD=%1 "
CASE n == 2
cSql += "WHERE MOV.HABER>0 AND MOV.DEBE=0 AND CLI.NUM_CIUD=%1 AND MOV.FECHA BETWEEN %2 AND %3 "
CASE n == 3
cSql += "WHERE MOV.HABER>0 AND MOV.DEBE=0 AND CLI.NUM_RUTA=%1 "
CASE n == 4
cSql += "WHERE MOV.HABER>0 AND MOV.DEBE=0 AND CLI.NUM_RUTA=%1 AND MOV.FECHA BETWEEN %2 AND %3 "
CASE n == 5
cSql += "WHERE MOV.HABER>0 AND MOV.DEBE=0 AND MOV.FECHA BETWEEN %1 AND %2 "
ENDCASE
cSql += "ORDER BY CLI.NOMBRE"
RETURN cSql
Code: Select all
STATIC PROCEDURE RepCobros_Lista( cTitulo )
LOCAL oDlgLis, oBrwLis, oSaySeek
LOCAL cOldAlias := Alias()
LOCAL cFileTemp := cTempFile( GetEnv( "TEMP" ), "dbf" )
DBSelectArea( "TEMP" )
WaitOn( "Procesando datos..." )
CursorWait()
COPY TO (cFileTemp) VIA "DBFCDX"
TEMP->( DBCloseArea() )
USE (cFileTemp) NEW ALIAS "TEMP" VIA "DBFCDX"
IF NetErr()
RETURN
ENDIF
INDEX ON NUM_PRES TAG NUM_PRES TEMPORARY
INDEX ON NUM_CLIE TAG NUM_CLIE TEMPORARY
INDEX ON NOMBRE TAG NOMBRE TEMPORARY
INDEX ON CEDULA TAG CEDULA TEMPORARY
OrdSetFocus( "NOMBRE" )
DBGoTop()
WaitOff()
CursorArrow()
DEFINE DIALOG oDlgLis NAME "DLG_LISTACOBR" OF oMainWnd TITLE cTitulo ICON GetIcon() FONT oFontD
REDEFINE XBROWSE oBrwLis ID 101 OF oDlgLis ALIAS "TEMP" FONT oFontD
ADD TO oBrwLis DATA TEMP->NUM_PRES TITLE "N° Pres." SIZE 055 PICTURE "@L 999999" TAG "NUM_PRES"
ADD TO oBrwLis DATA TEMP->NUM_CLIE TITLE "N° Clie." SIZE 055 PICTURE "@L 999999" TAG "NUM_CLIE"
ADD TO oBrwLis DATA TEMP->NOMBRE TITLE "Nombre de cliente" SIZE 250 TAG "NOMBRE"
ADD TO oBrwLis DATA TEMP->CEDULA TITLE "Cedula" SIZE 120 TAG "CEDULA"
ADD TO oBrwLis DATA TEMP->FECHA TITLE "Fecha"+FINL+"cobro" SIZE 080 CENTER
ADD TO oBrwLis DATA TEMP->HABER TITLE "Cobro C$" SIZE 090 PICTURE "99,999,999.99"
ADD TO oBrwLis DATA TEMP->SALDO TITLE "Saldo C$" SIZE 090 PICTURE "99,999,999.99"
oBrwLis:SetRdd()
oBrwLis:MyConfig()
oBrwLis:nFreeze := 4
oBrwLis:lHScroll := TRUE
oBrwLis:nHeaderHeight := 40
oBrwLis:bSeek := {|c| DBSeek( Upper( c ) ) }
REDEFINE BUTTON ID 102 OF oDlgLis ACTION oBrwLis:ToExcel( )
REDEFINE SAY oSaySeek ID 104 OF oDlgLis COLOR CLR_HCYAN, CLR_BLUE
REDEFINE BUTTON ID 201 OF oDlgLis ACTION oDlgLis:end() CANCEL
ACTIVATE DIALOG oDlgLis CENTER ON INIT ( oBrwLis:oSeek := oSaySeek )
IF !Empty( cOldAlias )
DBSelectArea( cOldAlias )
ENDIF
RETURN
Re: TxBrowse y ADS query - Necesito Ayuda
Posted: Wed Jul 18, 2012 3:55 pm
by lucasdebeltran
Hola,
Un tema pendiente de xBrowse es el de su optimización de velocidad en general, que se nota especialmente con dbfs en modo local grandes y en lans, así como particularmente en ADS y SQLRDD.
En el foro de inglés tienes un post con este problema y valiosas consideraciones de usuarios con mucha experiencia con Ads.
A mi me han ayudado además mucho aquí con ADS, mucho mejor que los míticos René Flores y Nicolás del Pozo la verdad.
Un saludo
Re: TxBrowse y ADS query - Necesito Ayuda
Posted: Wed Jul 18, 2012 4:10 pm
by RSalazarU
Rolando:
La solucion esta en el codigo que muestra Carlos Vargas, usá la clausula
{static} en la consulta.
aca esta el ejemplo que da Carlos
Code: Select all
cSQL := "SELECT {static} MOV.NUM_PRES, MOV.NUM_CLIE, CLI.NOMBRE, CLI.CEDULA, MOV.FECHA, MOV.HABER, MOV.SALDO, "
Si no lo haces, lo que ADSRDD hace es colocar un filtro a la tabla
y te muestra la misma tabla en otra area (incluso puedes modificarla y _ se veran reflejados en la tabla original); por lo tanto y como sabemos los filtros en tablas grandes son mostrados con lentitud en cualquier Browse.
Al colocar la clausula
{static} estas creando un
cursor estatico, es decir creando una tabla en un archivo temporal.
Es mucha la explicacion, por lo que espero este entendido.
Atentamente,
Rolando.
Cochabamba, Bolivia.