Set Filter demorando para filtrar registros pela estação

Projeto [x]Harbour - Compilador de código aberto compatível com o Clipper.

Moderador: Moderadores

porter
Usuário Nível 5
Usuário Nível 5
Mensagens: 1057
Registrado em: 10 Dez 2009 16:44
Localização: OLIMPIA-SP

Set Filter demorando para filtrar registros pela estação

Mensagem 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.
alxsts
Colaborador
Colaborador
Mensagens: 3092
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil

Set Filter demorando para filtrar registros pela estação

Mensagem 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()?
[]´s
Alexandre Santos (AlxSts)
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Set Filter demorando para filtrar registros pela estação

Mensagem 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.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
porter
Usuário Nível 5
Usuário Nível 5
Mensagens: 1057
Registrado em: 10 Dez 2009 16:44
Localização: OLIMPIA-SP

Set Filter demorando para filtrar registros pela estação

Mensagem 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.
Kapiaba
Colaborador
Colaborador
Mensagens: 1908
Registrado em: 07 Dez 2012 16:14
Localização: São Paulo
Contato:

Set Filter demorando para filtrar registros pela estação

Mensagem 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.
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Set Filter demorando para filtrar registros pela estação

Mensagem 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
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Kapiaba
Colaborador
Colaborador
Mensagens: 1908
Registrado em: 07 Dez 2012 16:14
Localização: São Paulo
Contato:

Set Filter demorando para filtrar registros pela estação

Mensagem 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.
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Set Filter demorando para filtrar registros pela estação

Mensagem 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.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Set Filter demorando para filtrar registros pela estação

Mensagem 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.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Set Filter demorando para filtrar registros pela estação

Mensagem 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.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Set Filter demorando para filtrar registros pela estação

Mensagem 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.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Kapiaba
Colaborador
Colaborador
Mensagens: 1908
Registrado em: 07 Dez 2012 16:14
Localização: São Paulo
Contato:

Set Filter demorando para filtrar registros pela estação

Mensagem 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.
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Set Filter demorando para filtrar registros pela estação

Mensagem 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.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
alaminojunior
Colaborador
Colaborador
Mensagens: 1717
Registrado em: 16 Dez 2005 21:26
Localização: Ubatuba - SP

Set Filter demorando para filtrar registros pela estação

Mensagem 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
Compilador xHarbour 1.2.3 + Embarcadero C++ 7.30
MySQL c/ SQLRDD
HwGui + GTWVG
Kapiaba
Colaborador
Colaborador
Mensagens: 1908
Registrado em: 07 Dez 2012 16:14
Localização: São Paulo
Contato:

Set Filter demorando para filtrar registros pela estação

Mensagem 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.
Responder