Hola. Tengo un programa que efectura una busqueda de la siguiente manera:
tengo un listbox con un keyseek, donde puedo buscar a medida que escribo, y debajo un get para ingresar un texto, y un boton que dice "FILTRAR"; si pongo en el get, "tornillo", por ejemplo, hago un RAT de tornillo sobre la base del listbox, y muestro solo eso. El problema es que esto lo uso para articulos; cuando trabajo con bases de 200, 300, 1000, 2000, funciona perfecto, pero tengo negocios donde hay mas de 30000 productos, y cuando uno aprieta "BUSCAR", el programa tarda varios minutos en efectuar la busqueda. ¿se les ocurre como hacer esto mas rapido?
SET FILTER TO RAT(UPPER(ALLTRIM(XFILTRO)),UPPER(BUSQ->DESCRIP))<>0
XFILTRO lo escribe el usuario, y la accion se ejecuta al apretar un boton; BUSQ es la base que muestro en el listbox.
sobre la base que muestro en el listbox; funciona de 10, pero arriba de los 15000 productos, tarda muchisimo.
Basicamente tengo que filtrar, o mostrar solamente productos que en una parte de la descripcion tengan un cierto texto, que el usuario puede tipear por pantalla.
Gracias.
busqueda lenta
Re: busqueda lenta
você faz atualização de indices regularmente no sistema?
Poste o código da sua busca, e já posso adiantar que busca incremental não é uma boa idéia....
Poste o código da sua busca, e já posso adiantar que busca incremental não é uma boa idéia....
Email: SamirSSabreu@gmail.com
MSN: SamirAbreu@hotmail.com
Skype: SamirAbreu
xHarbour 1.1.0 + FwXh 8.02
xHarbour 1.2.1 + Fwhh 10.6
MSN: SamirAbreu@hotmail.com
Skype: SamirAbreu
xHarbour 1.1.0 + FwXh 8.02
xHarbour 1.2.1 + Fwhh 10.6
-
- Posts: 149
- Joined: Thu Jun 21, 2007 3:26 pm
Re: busqueda lenta
Mantengo un indice que actualizo regularmente. Te copio la funcion. Gracias...!!!
funcion de busqueda:
// -----------------------------------------------------------------------
FUNCTION Buscaparam(xtipo, xvalor, xorden, xvta, xcododes, XUSERID)
local olbx, odlg
local obt1, obt2, obt3, xrta
local xok
LOCAL oString
LOCAL XBUSCA, OBUSCA
LOCAL OFNTARIAL
local xorden1, oorden1, xloncc, xcoti1, XHINCHA
DEFINE FONT OFNTARIAL
OFNTARIAL:=FUENTE(XUSERID)
if xcododes='C'
xorden1:=1
else
xorden1:=2
endif
oString = ""
sele 99
use &empre\monedas.sx shared
loca for monedas->moneda="DO"
if !eof()
xcoti1:=monedas->cotizacion
else
xcoti1:=3.3
endif
SELE 99
USE C:\TEMPO\F2F3
F2F3->MARCA:=0
USE
XRTA:=SPACE(16)
XBUSCA:=SPACE(40)
xok:=0
oString := ""
xloncc:=1
DEFINE DIALOG oDlg RESOURCE "REPORT_BUSQUEDA"
REDEFINE RADIO oorden1 VAR xorden1 ID 102,103 of oDlg ;
ON CHANGE (busqORDEN(Xtipo, XORDEN1, XORDEN, xvta, xloncc, olbx))
SetKey( VK_RETURN, { || xrta:=BUSQ->CODCPT, xok:=1, ODLG:END() } )
use &empre\CONLIQ index &empre\conliq alias BUSQ shared
go top
REDEFINE LISTBOX olbx FIELDS BUSQ->CODCPT,BUSQ->DESCRIP ;
HEADERS "Concepto","Descripcion" ;
FIELDSIZES 80, 200 ;
ID 101 OF oDlg ;
ON DBLCLICK ( xrta:=BUSQ->CODCPT, xok:=1, ODLG:END() ) ;
ON CLICK ( xrta:=BUSQ->CODCPT )
oLbx:bkeyChar :={|nKey| KeySeek(nKey,oLbx,390) , ;
oLbx:SetFocus(),oLbx:Refresh() }
REDEFINE GET oBUSCA VAR xBUSCA ID 130 of oDlg FONT OFNTARIAL
REDEFINE BUTTON oBt3 ACTION (FILTRAR(XBUSCA,XTIPO),OLBX:GOTOP(),OLBX:REFRESH()) ID 118 of oDlg
REDEFINE BUTTON oBt1 ACTION ( xok:=1, odlg:end() ) ID 1 of oDlg
REDEFINE BUTTON oBt1 ACTION ( xok:=2, odlg:end() ) ID 2 of oDlg
ACTIVATE DIALOG oDlg centered
y el filtro hace esto:
SELE 390
SET FILTER TO RAT(UPPER(ALLTRIM(XFILTRO)),UPPER(BUSQ->DESCRIP))<>0
GO TOP
y un UPSTABLE sobre olbx
El problema es que CONLIQ (la base de datos), tiene 40000 registros...
Gracias.
funcion de busqueda:
// -----------------------------------------------------------------------
FUNCTION Buscaparam(xtipo, xvalor, xorden, xvta, xcododes, XUSERID)
local olbx, odlg
local obt1, obt2, obt3, xrta
local xok
LOCAL oString
LOCAL XBUSCA, OBUSCA
LOCAL OFNTARIAL
local xorden1, oorden1, xloncc, xcoti1, XHINCHA
DEFINE FONT OFNTARIAL
OFNTARIAL:=FUENTE(XUSERID)
if xcododes='C'
xorden1:=1
else
xorden1:=2
endif
oString = ""
sele 99
use &empre\monedas.sx shared
loca for monedas->moneda="DO"
if !eof()
xcoti1:=monedas->cotizacion
else
xcoti1:=3.3
endif
SELE 99
USE C:\TEMPO\F2F3
F2F3->MARCA:=0
USE
XRTA:=SPACE(16)
XBUSCA:=SPACE(40)
xok:=0
oString := ""
xloncc:=1
DEFINE DIALOG oDlg RESOURCE "REPORT_BUSQUEDA"
REDEFINE RADIO oorden1 VAR xorden1 ID 102,103 of oDlg ;
ON CHANGE (busqORDEN(Xtipo, XORDEN1, XORDEN, xvta, xloncc, olbx))
SetKey( VK_RETURN, { || xrta:=BUSQ->CODCPT, xok:=1, ODLG:END() } )
use &empre\CONLIQ index &empre\conliq alias BUSQ shared
go top
REDEFINE LISTBOX olbx FIELDS BUSQ->CODCPT,BUSQ->DESCRIP ;
HEADERS "Concepto","Descripcion" ;
FIELDSIZES 80, 200 ;
ID 101 OF oDlg ;
ON DBLCLICK ( xrta:=BUSQ->CODCPT, xok:=1, ODLG:END() ) ;
ON CLICK ( xrta:=BUSQ->CODCPT )
oLbx:bkeyChar :={|nKey| KeySeek(nKey,oLbx,390) , ;
oLbx:SetFocus(),oLbx:Refresh() }
REDEFINE GET oBUSCA VAR xBUSCA ID 130 of oDlg FONT OFNTARIAL
REDEFINE BUTTON oBt3 ACTION (FILTRAR(XBUSCA,XTIPO),OLBX:GOTOP(),OLBX:REFRESH()) ID 118 of oDlg
REDEFINE BUTTON oBt1 ACTION ( xok:=1, odlg:end() ) ID 1 of oDlg
REDEFINE BUTTON oBt1 ACTION ( xok:=2, odlg:end() ) ID 2 of oDlg
ACTIVATE DIALOG oDlg centered
y el filtro hace esto:
SELE 390
SET FILTER TO RAT(UPPER(ALLTRIM(XFILTRO)),UPPER(BUSQ->DESCRIP))<>0
GO TOP
y un UPSTABLE sobre olbx
El problema es que CONLIQ (la base de datos), tiene 40000 registros...
Gracias.
Re: busqueda lenta
Prueba con algo como esto (indices temporales)
(Vas a tener que analizarlo un poquito, y no envío el recurso, pero te debe servir de algo
(Vas a tener que analizarlo un poquito, y no envío el recurso, pero te debe servir de algo
Code: Select all
memvar cOrden,cIndice,cIndkey,lUnique
*********************************************************************************************************************
function consulta(oCampo,cNomCampo,oDlgAnt,Clave)
*********************************************************************************************************************
local oDlg ,;
oLbx ,;
bSelect ,;
bfiltro ,;
cRfiltro ,;
bCancel ,;
bActivos ,;
cAlias :="CONSUL",;
xGetdata ,;
oButOk ,;
oButCancel,;
oGetFiltro,;
cGetFiltro:=space(38),;
nOldArch :=select(),;
cFiltro ,;
cDfiltro ,;
cDispfield ,;
cArch :="CONSUL",;
cTitulo :="Consulta",;
lExiste :=.t.,;
lUArch :=.t.,;
oCbx,;
lCbx,;
oSay ,;
oFKey
PRIVATE cOrden,cIndice,cIndKey,lUnique:=.f.
DEFAULT oDlgAnt:=oWnd
oFKey:=tvkey():NEW // CLASE TVKEY (control de teclas de funcion)
cursorwait()
cNomCampo :=Upper(cNomCampo)
cFiltro :=""
cDfiltro :=""
cDispfield:=""
bSelect :=""
cRfiltro :=""
IF Pcount()<4
Clave:=""
ENDIF
DEFINE DIALOG oDlg ;
FONT oFontGen;
RESOURCE "Consulta" OF oDlgAnt
oDlg:lHelpIcon:=.f.
do case
case cNomcampo="MTITU"
n_use(DDIR+"TITULAR","=",compartido,1,,"CONSUL")
CONSUL->(DBSETORDER("ORD1"))
CONSUL->(DBGOTOP())
cTitulo :="Consulta de Titulares"
cfiltro :=""
cDfiltro :=""
xGetdata :=""
cDispfield:="CONSUL->NOMBRE"
cIndice :=DDIR+'TITULAR'
cOrden :="ORD1"
cIndKey :="_field->CEDLETRA+STR(_FIELD->CEDULA,10)+_FIELD->TIPPER"
bSelect :={ || xGetdata:=CONSUL->CEDLETRA+'-'+STRZERO(CONSUL->CEDULA,10),;
oCampo:varput(xGetdata),;
oCampo:Refresh(),;
oDlg:End }
bCancel :={ || xGetdata:="",;
oDlg:End }
REDEFINE LISTBOX oLbx ;
FIELDS CONSUL->CEDLETRA+'-'+STRZERO(CONSUL->CEDULA,10),CONSUL->NOMBRE;
ALIAS cAlias ;
HEADERS "Cédula","Nombre";
FIELDSIZES 85,150;
ID 401 OF oDlg
OTHERWISE
lExiste:=.f.
endCase
if lExiste
SETKEY(VK_ESCAPE, { || eval(bCancel) })
SETKEY(VK_F4, { || IIF(oButOk:lActive .AND. !EMPTY(cDispfield),eval(bFiltro),) })
oLbx:bLdblClick :={ || eval(bSelect) }
oLbx:bKeyDown :={ | nKey | IIF(nKey==VK_RETURN,EVAL(bSelect),IIF(nKey==VK_ESCAPE,EVAL(bCancel),)) }
oLbx:cMsg:="Doble Click o [Enter] => Selecciona"
bFiltro:={|| oButOk:Disable(),;
oButCancel:Disable(),;
cGetFiltro:=LEE_FILTRO(oDlg,cGetFiltro),;
oGetFiltro:varput(cGetFiltro),;
oGetFiltro:Refresh(),;
oButOk:Enable(),;
oButCancel:Enable(),;
Valfiltro(cGetFiltro,oDlg,cDfiltro,cRfiltro,cDispfield,cAlias,oLbx),oLbx:setfocus(.t.)}
REDEFINE BUTTON oButOk ID 101 OF oDlg;
MESSAGE "Indicar Busqueda";
PROMPT "[F4]-Buscar";
ACTION eval(bFiltro);
WHEN !EMPTY(cDispfield)
REDEFINE BUTTON oButCancel ID 102 OF oDlg;
PROMPT "[Esc]-Salir";
MESSAGE "Cancela la Ayuda";
ACTION (eval(bCancel))
oDlg:cTitle:=ctitulo
REDEFINE GET oGetFiltro VAR cGetFiltro ID 201 OF oDlg;
PICTURE '@!';
MESSAGE "Coloque Valor a Buscar, Pulse Ok, (Escape=>Sale, en Blanco=>TODOS)";
VALID val_val({||oLbx:setfocus(.t.)});
WHEN .F.
cursorarrow()
IF LEN(ALLTRIM(CLAVE))<>0
SEEK(CLAVE)
ENDIF
oLbx:nHeaderHeight := 31 && Da la altura del header
oLbx:Set3DStyle()
ACTIVATE DIALOG oDlg CENTER
select("consul")
close
else
xGetData:=""
msgalert("No Existe Ayuda Para Este Campo","Atención...")
endif
if nOldArch<>0
select(nOldArch)
endif
oFKey:End()
return IIF(xGetdata=NIL,"",xGetdata)
*********************************************************************************************************************
static function Valfiltro(filtro,oDlg,d_filtro,crfiltro,disp_field,cArch,oLbx)
creafil(filtro,d_filtro,crfiltro,disp_field,cArch,oLbx)
oDlg:refresh()
return .t.
*********************************************************************************************************************
procedure creafil(filtro,d_Filtro,cRfiltro,disp_field,cArch,oLbx)
*********************************************************************************************************************
local bEval,bFiltro,breval
IF len(alltrim(filtro))=0
(cArch)->(dbsetfilter())
(cArch)->(dbgotop())
ordlistclear()
ordlistadd(cIndice)
(cArch)->(ordsetFOCUS(cOrden))
IF len(alltrim(d_filtro))=0
(cArch)->(dbsetfilter())
ELSE
(cArch)->(dbsetfilter(d_filtro))
ENDIF
ELSE
IF crfiltro=nil
crfiltro:=""
ENDIF
bEval:={ || &disp_field }
bfiltro:=alltrim(filtro)
(cArch)->(dbsetfilter())
(cArch)->(dbgotop())
ordlistclear()
ordlistadd(cIndice)
(cArch)->(ordsetFOCUS(cOrden))
DELFILE("C:\","TMFILT.CDX")
IF len(alltrim(crfiltro))=0
IF lUnique
INDEX ON &cIndkey to C:\TMFILT.CDX for bFiltro$eval(bEval) UNIQUE
ELSE
INDEX ON &cIndkey to C:\TMFILT.CDX for bFiltro$eval(bEval)
ENDIF
ELSE
breval:={ || &crfiltro }
IF lUnique
INDEX ON &cIndkey to C:\TMFILT.CDX for bFiltro$eval(bEval) .and. eval(breval) UNIQUE
ELSE
INDEX ON &cIndkey to C:\TMFILT.CDX for bFiltro$eval(bEval) .and. eval(breval)
ENDIF
ENDIF
ENDIF
(cArch)->(dbgotop())
oLbx:refresh()
RETURN
*********************************************************************************************************************
STATIC FUNCTION LEE_FILTRO(oDlgAnt,cGetFiltro)
*********************************************************************************************************************
LOCAL oDlg,oGetFiltro
DEFINE DIALOG oDlg ;
FONT oFontGen;
RESOURCE "Consul_filtro" OF oDlgAnt;
oDlg:lHelpIcon:=.f.
REDEFINE GET oGetFiltro VAR cGetFiltro ID 201 OF oDlg;
PICTURE '@!';
MESSAGE "Coloque Valor a Buscar, Pulse Enter, (Esc=>Sale, En Blanco=>TODOS)";
VALID val_val({||oDlg:End()})
oGetFiltro:bKeyDown:={ |nKey| iiF(nKey==VK_RETURN,oDlg:END(),)}
oGetFiltro:bLDblClick:= {|| oDlg:End()}
ACTIVATE DIALOG oDlg
RETURN cGetFiltro
Saludos
Angel, Valencia, Venezuela
xH .997 - FW 7.9 - BCC55 - WorkShop - MySql
Angel, Valencia, Venezuela
xH .997 - FW 7.9 - BCC55 - WorkShop - MySql
- FranciscoA
- Posts: 1964
- Joined: Fri Jul 18, 2008 1:24 am
- Location: Chinandega, Nicaragua, C.A.
Re: busqueda lenta
Hecha un vistazo a estos post. Talvez te sirvan de algo.
http://forums.fivetechsupport.com/viewt ... =6&t=12307
http://forums.fivetechsupport.com/viewt ... f=6&t=9987
Saludos
http://forums.fivetechsupport.com/viewt ... =6&t=12307
http://forums.fivetechsupport.com/viewt ... f=6&t=9987
Saludos
Francisco J. Alegría P.
Chinandega, Nicaragua.
Fwxh1204-MySql-TMySql
Chinandega, Nicaragua.
Fwxh1204-MySql-TMySql
-
- Posts: 149
- Joined: Thu Jun 21, 2007 3:26 pm
Re: busqueda lenta
Vi este POST, y me interesa, pero no entiendo bien el funcionamiento; ¿alguien tiene algun ejemplo? como para cargar un dbf en memoria y filtrar con at() todos los registros que contengan cierto texto en un campo. Gracias.
La función At() es extremadamente rápida ya que practicamente esta implementada al 100% en el propio microprocesador.
Lo que es lento es ir leyendo los registros de uno en uno. La solución a esto, aunque suene increible, es cargar de una vez toda la DBF en memoria usando MemoRead() y entonces hacer el At():
cDatos = MemoRead( "nombre.dbf" )
nPos = At( "lo que busco", cDatos )
Dividiendo el valor devuelto por At() por el tamaño de un registro (+ el tamaño de la cabecera) sabemos inmediatamente en que registro estamos. El siguiente At() se haría a partir de donde se encontró la primera ocurrencia.
Está técnica la implementamos en su día en una base de datos "documental" y los resultados fueron espectaculares. Espero que te sirva
Si la base de datos es extremadamente grande, se iría leyendo en bloques grandes de memoria.
La función At() es extremadamente rápida ya que practicamente esta implementada al 100% en el propio microprocesador.
Lo que es lento es ir leyendo los registros de uno en uno. La solución a esto, aunque suene increible, es cargar de una vez toda la DBF en memoria usando MemoRead() y entonces hacer el At():
cDatos = MemoRead( "nombre.dbf" )
nPos = At( "lo que busco", cDatos )
Dividiendo el valor devuelto por At() por el tamaño de un registro (+ el tamaño de la cabecera) sabemos inmediatamente en que registro estamos. El siguiente At() se haría a partir de donde se encontró la primera ocurrencia.
Está técnica la implementamos en su día en una base de datos "documental" y los resultados fueron espectaculares. Espero que te sirva
Si la base de datos es extremadamente grande, se iría leyendo en bloques grandes de memoria.
Re: busqueda lenta
diegopolverelli,
el problema te lo origina claramente el SET FILTER que son claramente muy lentos y más todavía si tu aplicativo funciona en RED. Para ello, una solución muy eficaz y ultrarápida son la utilización de indices CDX (no NTX) y la sustitución de los SET FILTER TO por ORDSCOPE. Hacen búsquedas y filtros de forma instantaneas.
Para más información sobre su funcionamiento busca en este foro por ORDSCOPE
Un saludo.
LORENZO
el problema te lo origina claramente el SET FILTER que son claramente muy lentos y más todavía si tu aplicativo funciona en RED. Para ello, una solución muy eficaz y ultrarápida son la utilización de indices CDX (no NTX) y la sustitución de los SET FILTER TO por ORDSCOPE. Hacen búsquedas y filtros de forma instantaneas.
Para más información sobre su funcionamiento busca en este foro por ORDSCOPE
Un saludo.
LORENZO