Página 1 de 2
Set Filter demorando para filtrar registros pela estação
Enviado: 01 Jul 2024 13:44
por porter
Olá pessoal,
Estou usando o Set Filter para filtrar arquivo DBF e índices CDX, mas pela rede na estação, está muito lento, estou filtrando os registros e mostrando em um TBrowse, estou fazendo dessa forma, gostaria de saber se tem uma forma diferente, para filtrar mais rápido.
Código: Selecionar todos
nroDoPedido = 581390
INDEX ON PEDIDO TO INroPedido
SET FILTER TO PEDIDO = nroDoPedido
GOTO TOP
Harbour 3.2.0dev
Console
Obrigado.
Set Filter demorando para filtrar registros pela estação
Enviado: 01 Jul 2024 14:10
por alxsts
Olá!
Talvez melhore usando:
Código: Selecionar todos
LOCAL bFilter := { || PEDIDO = nroDoPedido }
INDEX ON PEDIDO TO INroPedido
GOTO TOP
SET FILTER TO Eval( bFilter )
Mas... se você tem a tabela indexada pela coluna desejada e tem a chave desejada, por que não usar um DbSeek()?
Set Filter demorando para filtrar registros pela estação
Enviado: 01 Jul 2024 16:21
por JoséQuintas
O filtro vai ser sempre assim, só do pedido atual, pra mexer nos produtos?
Troque por SET SCOPE TO NumeroPedido
Não esqueça de retornar a vazio depois do uso.
Nota: Imagino que no exemplo está indexando na hora, mas no uso deve usar índice já pronto, o índice deve ser pelo número do pedido mesmo, e se usar Str(), use também no SET SCOPE.
Set Filter demorando para filtrar registros pela estação
Enviado: 02 Jul 2024 10:29
por porter
Olá alxsts,
O arquivo DBF, tem uma coluna indexada, eu consigo filtrar pelo DbSeek, o que não estou conseguindo, é na hora de mostrar esses registros filtrados, no Tbrowse, estou conseguindo mostrar no Tbrowse, somente pelo Set Filter.
Set Filter demorando para filtrar registros pela estação
Enviado: 02 Jul 2024 12:36
por Kapiaba
Código: Selecionar todos
FUNCTION Filter_Num()
LOCAL cAlias, nroDoPedido := 581390, nPedido
nPedido := nroDoPedido
cAlias := ALIAS()
/*
INDEX ON PEDIDO TO INroPedido
SET FILTER TO PEDIDO = nroDoPedido // NUNCA USE ISSO.
GOTO TOP
*/
// FILTRO DIRETO NA MEMORIA:
INDEX ON PEDIDO TAG 04 TO PEDITEMP FOR ( .NOT. EOF() ) .AND. ;
( cAlias )->PEDIDO >= nPedido .AND. ;
( cAlias )->PEDIDO <= nPedido MEMORY // TEMPORARY
GO TOP
/*
OrdDestroy( "PEDITEMP" ) // FECHA O MEMORY/TEMPORARY
GO TOP
*/
RETURN NIL
// FIN / END - kapiabafwh@gmail.com
Regards, saludos.
Set Filter demorando para filtrar registros pela estação
Enviado: 02 Jul 2024 21:44
por JoséQuintas
Mesmo que na memória, essa criação de índice vai demorar demais.
Opção 1:
O que mencionei SET SCOPE TO nPedido
Pode até fazer GOTO TOP e GOTO BOTTOM que vai ficar limitado ao número do pedido, por isso rápido.
E por isso mencionei de lembrar de desativar o SET SCOPE no final, senão fica preso a esse intervalo
Opção 2:
Eu fazia isto há muitos anos atrás, com SIXCDX no Clipper e depois no Harbour, pode considerar como um sub-index.
Código: Selecionar todos
SEEK nPedido
INDEX ON qualquerchave TO TEMP WHILE nPedido == PEDIDO
Isso vai criar um índice somente com o que se refere a esse pedido, extremamente rápido, porque vai usar o DBF já indexado por pedido, e só usar o bloco que interessa.
Não sei se pode variar conforme a RDD usada, faça seu próprio teste.
Pode usar set index additive pra acrescentar esse índice na lista, e depois precisa remover da lista.
Lembrando: os outros índices precisarão ser atualizados em caso de alteração, então precisam ser mantidos abertos, além do temporário.
Nota:
Pra outras situações, há o SET SCOPE inicial e final, por exemplo, pra um intervalo de datas.
Nota 2:
INDEX FOR -> usa todos os registros pra fazer filtro, vai processar o arquivo inteiro
INDEX WHILE -> processa daquela posição em diante, enquanto a condição for válida
Set Filter demorando para filtrar registros pela estação
Enviado: 03 Jul 2024 10:49
por Kapiaba
José Quintas:
Mesmo que na memória, essa criação de índice vai demorar demais.
Negativo, é tão ou mais rápido que o ORDSCOPE()
https://linguagemclipper.com.br/dicas/c ... er-harbour
Gracias, tks.
Regards, saludos.
Set Filter demorando para filtrar registros pela estação
Enviado: 03 Jul 2024 12:59
por JoséQuintas
Kapiaba escreveu:Negativo, é tão ou mais rápido que o ORDSCOPE()
Do jeito que mostrou não é não.
PENSE.
Tem um DBF na rede com 1 milhão de registros.
Vai criar um índice na memória que vai trazer 1 milhão de registros pela rede.
O tempo de criação vai ser no mínimo o tempo de trazer 1 milhão de registros pela rede.
Como trazer 1 milhão de registros pela rede pode ser mais rápido do que trazer apenas 10 ?
Impossível.
Uma coisa é criar o índice mais rápido, a outra coisa é ter que ler os registros um por um pra poder criar o índice.
É só comparar com um array.
Criar e acessar array é rápido? sim
Mas se o array é criado a partir do DBF, precisa processar o DBF, e se isso não for rápido, de nada adianta o array.
Não generalize o uso de arquivo em memória.
É mais rápido, mas não faz milagres.
Set Filter demorando para filtrar registros pela estação
Enviado: 03 Jul 2024 13:26
por JoséQuintas
Código: Selecionar todos
PROCEDURE Main
LOCAL nCont
SetMode(33,100)
CLS
dbCreate( "temp.dbf", { ;
{ "CODIGO", "N", 10, 0 }, ;
{ "NOME", "C", 30, 0 } } )
USE temp
FOR nCont = 1 TO 1000000
APPEND BLANK
REPLACE field->CODIGO WITH nCont, NOME WITH "XXX"
NEXT
USE
USE temp
INDEX ON field->CODIGO TO temp
USE
? Seconds()
USE TEMP INDEX temp
SET SCOPE TO 1
GOTO TOP
DO WHILE ! Eof()
SKIP
ENDDO
? Seconds()
Inkey(0)
RETURN
49007.06
49007.06
Um milhão de registros, menos de 1 centésimo de segundo, contado ANTES de abrir o arquivo/índice.
Set Filter demorando para filtrar registros pela estação
Enviado: 03 Jul 2024 13:42
por JoséQuintas
NÃO É a comparação com índice em memória, apenas comparando com SET FILTER.
E arquivo LOCAL, onde o cache do windows faz diferença.
Código: Selecionar todos
PROCEDURE Main
LOCAL nCont
SetMode(33,100)
CLS
dbCreate( "temp.dbf", { ;
{ "CODIGO", "N", 10, 0 }, ;
{ "NOME", "C", 30, 0 } } )
USE temp
FOR nCont = 1 TO 1000000
APPEND BLANK
REPLACE field->CODIGO WITH nCont, NOME WITH "XXX"
NEXT
USE
USE temp
INDEX ON field->CODIGO TO temp
USE
? Seconds()
USE TEMP INDEX temp
? LastRec()
SET SCOPE TO 1
GOTO TOP
DO WHILE ! Eof()
SKIP
ENDDO
? Seconds()
USE TEMP INDEX temp
SET FILTER TO field->CODIGO=1
GOTO TOP
DO WHILE ! Eof()
SKIP
ENDDO
? Seconds()
Inkey(0)
RETURN
49686.84
1000000
49686.84
49690.52
Arquivo local, cache do Windows ajuda ao máximo.
SET SCOPE -> menos de 1 centésimo de segundo
FILTER -> quase 4 SEGUNDOS. 400 vezes mais demorado
O índice em memória deve ser mais rápido que esse filter, mas mais demorado que o SET SCOPE.
Isso considerando LOCAL, porque em rede a diferença vai ser muito maior.
Set Filter demorando para filtrar registros pela estação
Enviado: 03 Jul 2024 14:13
por JoséQuintas
Código: Selecionar todos
PROCEDURE Main
LOCAL nCont, cTemp := "\\serverjpa\rede\temp"
SetMode(33,100)
CLS
dbCreate( cTemp, { ;
{ "CODIGO", "N", 10, 0 }, ;
{ "NOME", "C", 30, 0 } } )
USE (ctemp)
FOR nCont = 1 TO 1000000
APPEND BLANK
REPLACE field->CODIGO WITH nCont, NOME WITH "XXX"
NEXT
USE
USE (ctemp)
INDEX ON field->CODIGO TO (cTemp)
USE
? Seconds()
USE (cTemp) INDEX (ctemp)
? LastRec()
SET SCOPE TO 1
GOTO TOP
DO WHILE ! Eof()
SKIP
ENDDO
USE
? Seconds()
USE (cTemp) INDEX (ctemp)
? LastRec()
SET SCOPE TO 1
INDEX ON field->CODIGO TO (cTemp+"2") WHILE .T.
USE
? Seconds()
USE (cTemp) INDEX (cTemp)
SET FILTER TO field->CODIGO=1
GOTO TOP
DO WHILE ! Eof()
SKIP
ENDDO
? Seconds()
Inkey(0)
RETURN
Em rede
50764.53
1000000
50764.53 -> menos de 1 centésimo de segundo para SCOPE
1000000
50764.55 -> 2 centésimos de segundo pra sub-índice, aproveitando o SCOPE
50769.86 -> mais de 5 segundos para filter, 500 vezes mais demorado
Com certeza vai variar conforme tamanho do arquivo, quantidade de campos, uso compartilhado, antivírus, velocidade da rede, etc.
Aqui duas máquinas W10 servidor e terminal, rede 1 gigabit, esqueci de abrir compartilhado.
O tamanho ficou pequeno
Código: Selecionar todos
03/07/2024 14:06 41.000.099 temp.dbf
03/07/2024 14:06 20.483.072 temp.ntx
03/07/2024 14:06 2.048 temp2.ntx
Agora só acrescentar aí o temporário em memória.
Não uso arquivo em memória, e nem quero tentar, se não me engano depende de acrescentar lib de contrib pra funcionar e posso acabar testando errado.
Quando testei arquivo em memória há muitos anos atrás, acabou usando um formato especial do Windows quando o nome do arquivo tem dois pontos, onde fica tudo escondido numa pasta especial.
Set Filter demorando para filtrar registros pela estação
Enviado: 10 Jul 2024 13:18
por Kapiaba
Mister Quintas, não fale besteira, o senhor não está usando o comando MEMORY ou TEMPORARY. O senhor está criando INDICES no HD. MEMORY / TEMPORARY cria o índice na MEMÓRIA AUXILIAR da máquina em tempo REAL.
Regards, saludos.
Set Filter demorando para filtrar registros pela estação
Enviado: 10 Jul 2024 15:59
por JoséQuintas
Kapiaba escreveu:MEMÓRIA AUXILIAR da máquina em tempo REAL.
Mostrei o teste, e comentei de você adicionar o teste usando temporário em memória pra comparar.
Fiz a parte que eu sabia, agora cabe a você acrescentar a parte que sabe.
Não vou inventar teste do que não uso.
Set Filter demorando para filtrar registros pela estação
Enviado: 10 Jul 2024 16:39
por alaminojunior
Pode usar o Set Scope to "nPedido" e para isso a coluna que guarda o numero do pedido deve ser indexada.
ou
outra função que é super rápida: OrdWildSeek()
Eu usava no tempo em que minhas tabelas eram DBF´s
Exemplo com HWGUI
Código: Selecionar todos
Function busca_ncms
Local cDbf:= select(), nova:= {{"",""}}
select cdncm000
ordsetfocus("indncm02")
dbgotop()
do while ordwildseek("*"+alltrim(vEdit1)+"*",.t.) // aqui com * no início e fim, ele retorna .t. quando ocorre a string em qualquer parte da string
aadd(nova,{ncmcod,ncmdsc})
enddo
nova:= aSORT( nova,,,{|X,Y| X[1] < Y[1] } )
oBrowseMsul1:aArray:= nova
CreateArList(oBrowseMsul1,nova)
oBrowseMsul1:Refresh()
oBrowseMsul1:SetFocus()
Select(cDbf)
return
Set Filter demorando para filtrar registros pela estação
Enviado: 11 Jul 2024 14:24
por Kapiaba
Pronto Mister Quintas:
Código: Selecionar todos
// C:\FWH\SAMPLES\QUINTAS.PRG - kapiabafwh@gmail.com - 11/07/2024 - Joao.
#include "FiveWin.ch"
ANNOUNCE RDDSYS
REQUEST DBFCDX, DBFFPT
FUNCTION Main()
FIELD CODIGO, NOME
LOCAL nCont, cTemp := "\\serverjpa\rede\temp"
LOCAL nCodIni := 5000 // PODE SE DIGITAR EM UM GET
LOCAL nCodFin := 19999 // PODE SE DIGITAR EM UM GET
LOCAL cAlias
RDDSETDEFAULT("DBFCDX")
RDDREGISTER( "DBFCDX", 1 ) // RDT_FULL -> 20/10/2022 Joao
SET CENTURY ON
SET DATE BRITISH
SET TIME FORMAT TO "HH:MM:SS"
SET EPOCH TO YEAR( DATE() ) - 30
SET SOFTSEEK OFF
SET WRAP ON
SETCANCEL( .F. )
SET CONFIRM OFF
SET DELETED ON
SET _3DLOOK ON
SET UNIQUE OFF
SET ESCAPE OFF
SET EXACT ON
SET EXCLUSIVE OFF
SET MULTIPLE OFF
SET OPTIMIZE ON
IF .NOT. FILE( "QUINTAS.DBF" )
DbCreate( "QUINTAS.DBF", { { "CODIGO", "N", 10, 00 }, ;
{ "NOME" , "C", 50, 00 } } )
CLOSE DATABASE
ENDIF
USE QUINTAS ALIAS QUINTAS EXCLUSIVE NEW
IF EOF()
FOR nCont = 1 TO 1000000
SYSREFRESH()
APPEND BLANK
REPLACE CODIGO WITH nCont
REPLACE NOME WITH "QUINTAS " + ALLTRIM( STR( nCont ) ) + ;
" MEMORY / TEMPORARY - EXAMPLO SIMPLES"
NEXT
ENDIF
IF .NOT. FILE( "QUINTAS.CDX" ) // DEMORADO. FAZER APENAS NO INDEXADOR.
INDEX ON FIELD->CODIGO TAG 01 TO QUINTAS // INDICE NORMAL NO HD.
ENDIF
cAlias := ALIAS()
GO TOP
// FILTRO NA MEMORIA AUXILIAR EM TEMPO REAL
// EU PREFIRO ESTE FILTRO, POIS POSSO CONTROLAR DE VARIAS FORMAS INTERNAMENTE,
INDEX ON CODIGO TAG 02 TO PEDITEMP FOR ( .NOT. EOF() ) .AND. ;
( cAlias )->CODIGO >= nCodIni .AND. ;
( cAlias )->CODIGO <= nCodFin MEMORY // TEMPORARY
GO TOP
// ? Seconds() // 51851.51
BROWSE()
OrdDestroy( "PEDITEMP" ) // FECHA O MEMORY/TEMPORARY
GO TOP
// OS DOIS FILTROS SAO RAPIDERRIMOS.
SET ORDER TO 01 // CODIGO
// USANDO ORDSCOPE() VIA .CDX
ORDSCOPE( 0, nCodIni )
ORDSCOPE( 1, nCodFin )
GO TOP
// ? Seconds() // 52031.30
BROWSE()
// FECHAR O SCOPE()
ORDSCOPE( 0, NIL )
ORDSCOPE( 1, NIL )
GO TOP
CLOSE DATABASES
RETURN NIL
// FIN / END - kapiabafwh@gmail.com
Regards, saludos.