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.