Select demorando

Fórum sobre Banco de Dados e RDDs para Clipper/[x]Harbour.

Moderador: Moderadores

Avatar do usuário
Poka
Usuário Nível 4
Usuário Nível 4
Mensagens: 569
Registrado em: 25 Out 2004 21:26
Localização: Leme/SP

Select demorando

Mensagem por Poka »

Olá à todos,

alguém tem uma solução melhor? tá demorando.

pagarb é a tabela
ela já esta com o ìndice docum+codfor+tpnota+serie+ordem

Código: Selecionar todos

   str:="select b.valor , b.dc , b.nrecibo , d.valor ,";
   +"(select sum(b.valor) from "+pagarb +" b where b.docum||b.codfor||b.tpnota||b.serie||b.ordem =  '"+xchave+"'  and b.dc  = 'C'    and trim(b.nrecibo)=''  )   ,";
   +"(select sum(b.valor) from "+pagarb +" b where b.docum||b.codfor||b.tpnota||b.serie||b.ordem =  '"+xchave+"'  and b.dc  = 'D'    and trim(b.nrecibo)=''  )   ,";
   +"(select sum(b.valor) from "+pagarb +" b where b.docum||b.codfor||b.tpnota||b.serie||b.ordem =  '"+xchave+"'  and b.dc  = 'C'    and trim(b.nrecibo)<>''  )   ,";
   +"(select sum(b.valor) from "+pagarb +" b where b.docum||b.codfor||b.tpnota||b.serie||b.ordem =  '"+xchave+"'  and b.dc  = 'D'    and trim(b.nrecibo)<>''  )   ";
   +" from "+pagarb+" b INNER JOIN "+pagard +" d on d.docum||d.codfor||d.tpnota||d.serie||d.ordem =  '"+xchave+"'"  ;
			+" group by  b.valor,b.dc, b.nrecibo , d.valor;"
Poka
Editado pela última vez por Itamar M. Lins Jr. em 04 Mai 2026 18:42, em um total de 1 vez.
Razão: Editar para adicionar a tag [code][/code]
alxsts
Colaborador
Colaborador
Mensagens: 3146
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil
Curtiram: 1 vez

Re: Select demorando

Mensagem por alxsts »

Olá!

Facilitaria bastante a análise e ajuda se você postasse o código SQL já concatenado, entre as tags code e /code...
[]´s
Alexandre Santos (AlxSts)
alxsts
Colaborador
Colaborador
Mensagens: 3146
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil
Curtiram: 1 vez

Re: Select demorando

Mensagem por alxsts »

Olá!
alxsts escreveu: 04 Mai 2026 18:18 Facilitaria bastante a análise e ajuda se você postasse o código SQL já concatenado, entre as tags code e /code..

Código: Selecionar todos

select b.valor , b.dc , b.nrecibo , d.valor ,
       (select sum(b.valor) from "+pagarb +" b where b.docum||b.codfor||b.tpnota||b.serie||b.ordem = '"+xchave+"' and b.dc = 'C' and trim(b.nrecibo)='' ) ,
       (select sum(b.valor) from "+pagarb +" b where b.docum||b.codfor||b.tpnota||b.serie||b.ordem = '"+xchave+"' and b.dc = 'D' and trim(b.nrecibo)='' ) ,
       (select sum(b.valor) from "+pagarb +" b where b.docum||b.codfor||b.tpnota||b.serie||b.ordem = '"+xchave+"' and b.dc = 'C' and trim(b.nrecibo)<>'' ),
       (select sum(b.valor) from "+pagarb +" b where b.docum||b.codfor||b.tpnota||b.serie||b.ordem = '"+xchave+"' and b.dc = 'D' and trim(b.nrecibo)<>'' ) 
  from "+pagarb+" b 
  INNER JOIN "+pagard +" d
          on d.docum||d.codfor||d.tpnota||d.serie||d.ordem = '"+xchave+"'
  group by b.valor,b.dc, b.nrecibo , d.valor
Foi isto que eu quis sugerir. Não alterei nada. Pode deletar o outro tópico.

Talvez melhore com una ou mais subqueries. Estas colunas mencionadas nas cláusulas WHERE tem índices? Dependendo se tem ou não, cada SUM destes pode ter que ler milhares de linhas, degradando a performance.

Qual banco de dados e versão utilizada? Dependendo, pode-se usar algumas CTEs (Common Table Expressions).
[]´s
Alexandre Santos (AlxSts)
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20482
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP
Curtiram: 2 vezes

Re: Select demorando

Mensagem por JoséQuintas »

Parece que está multiplicando uma consulta pela quantidade de registros na tabela.
E se entrar em loop, vai ser consulta infinita.
E ainda relaciona isso com mais consulta.

Nem quero tentar entender isso.

Mais prático o usuário se entender com a IA, explicando o que quer.
Com certeza a pesquisa desperdiça tempo, talvez tempo demais.
José M. C. Quintas
Harbour 3.2, mingw, multithread, gtwvg, fivewin 25.12, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui), (hmg3), (hmg extended), (oohg), PNotepad, ASP, (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: 20482
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP
Curtiram: 2 vezes

Re: Select demorando

Mensagem por JoséQuintas »

Não conheço o x || y || z
José M. C. Quintas
Harbour 3.2, mingw, multithread, gtwvg, fivewin 25.12, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui), (hmg3), (hmg extended), (oohg), PNotepad, ASP, (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/
alxsts
Colaborador
Colaborador
Mensagens: 3146
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil
Curtiram: 1 vez

Re: Select demorando

Mensagem por alxsts »

Olá!
JoséQuintas escreveu: 05 Mai 2026 18:37 Não conheço o x || y || z
Em alguns SGBD, como Oracle e PostgreSQL, este é o operador de concatenação de strings. O mesmo que
x + y + z
[]´s
Alexandre Santos (AlxSts)
Avatar do usuário
Poka
Usuário Nível 4
Usuário Nível 4
Mensagens: 569
Registrado em: 25 Out 2004 21:26
Localização: Leme/SP

Re: Select demorando

Mensagem por Poka »

Boa tarde
Realmente, faltou muitas informações.
Uso Firebird 2.5
Quintas, || é para concatenar os campos.
Alexandre, não sei como excluir o anterior.
Nessa função a variável xchave ja vem concatenada com docum+codfor+tpnota+serie+ordem.
No select a variavel pagarB e pagarD é o nome da tabela que pode ser pagard001...e pagarD001... para cada empresa da empresa ususaria,
pode deixar dentro do select mesmo, esqueci de corrigir:
"from pagarb b " e não "from "+pagarB+" b"

Só pesquiso uma duplicata nesse select que pode varios lançamentos de baixa.
esse select tá demorando uns 50 segundos. a tabela é pequena +- 5.000 registros.
Aqui to mexendo com duas tabelas, pagarD e pagarB;
pagarD, salva as duplicatas
pagarB salva as baixas.
campo nrecibo e campo DC contem ou nao um nr de recibo (para controle)
esse select pega o valor (d.valor em pagarD).
E em pagarB os totais dos valores em b.valor.
total dos creditos se campo NRECIBO estiver em branco e campo DC = "C"
total dos creditos se campo NRECIBO estiver preenchido e campo DC = "C"
total dos debitos se campo NRECIBO estiver em branco e campo DC = "D"
total dos debitos se campo NRECIBO estiver preenchido e campo DC = "D"
Resolvi da seguinte maneira, fiz varios selects para cada sum. Ficou rapido 2 ou3 segundos, mas, melhor se fosse num select só. Com certeza estou escrevendo o select errado.


Poka
alxsts
Colaborador
Colaborador
Mensagens: 3146
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil
Curtiram: 1 vez

Re: Select demorando

Mensagem por alxsts »

Olá!

Perguntei para a IA do Google:
Como melhorar a performance deste SELECT em Firebird 2.5? A performance está lenta...
Resposta:
O principal motivo da lentidão é o uso de concatenação de campos (||) e funções (como trim) nas cláusulas WHERE e JOIN. Isso impede o Firebird de usar índices, forçando o banco a ler registro por registro (Natural Scan).

Aqui estão os passos para resolver:

## 1. Pare de concatenar no JOIN e no WHERE
Em vez de b.docum||b.codfor... = '"+xchave+"', você deve passar os valores individualmente para cada coluna. O Firebird 2.5 não consegue otimizar uma string concatenada contra um índice composto.

## 2. Use "Conditional Aggregation" (Soma Condicional)
Em vez de fazer 4 sub-selects na mesma tabela, você faz uma única varredura e separa os valores usando CASE WHEN. Isso reduz drasticamente o I/O do disco.

## 3. Exemplo de Query Otimizada
Assumindo que você possa passar os valores da chave separados no seu código:

Código: Selecionar todos

SELECT 
    b.valor, 
    b.dc, 
    b.nrecibo, 
    d.valor,
    -- Agrupamento das somas em uma única leitura
    SUM(CASE WHEN b.dc = 'C' AND (b.nrecibo IS NULL OR TRIM(b.nrecibo) = '') THEN b.valor ELSE 0 END) as soma_c_vazio,
    SUM(CASE WHEN b.dc = 'D' AND (b.nrecibo IS NULL OR TRIM(b.nrecibo) = '') THEN b.valor ELSE 0 END) as soma_d_vazio,
    SUM(CASE WHEN b.dc = 'C' AND (b.nrecibo <> '') THEN b.valor ELSE 0 END) as soma_c_cheio,
    SUM(CASE WHEN b.dc = 'D' AND (b.nrecibo <> '') THEN b.valor ELSE 0 END) as soma_d_cheio
FROM PAGARB bINNER JOIN PAGARD d ON 
    d.docum = :docum AND d.codfor = :codfor AND d.tpnota = :tpnota AND d.serie = :serie AND d.ordem = :order
WHERE 
    b.docum = :docum AND b.codfor = :codfor AND b.tpnota = :tpnota AND b.serie = :serie AND b.ordem = :ordem
GROUP BY 1, 2, 3, 4
## Por que isso fica mais rápido?

1. SARGability: Ao usar coluna = :valor, o Firebird usa o índice da chave primária ou estrangeira.

2. Menos leituras: Os sub-selects originais faziam o banco "correr" a tabela PAGARB várias vezes. Com o CASE WHEN, ele lê uma vez só.

3. Índice Composto: Se você ainda não tem, crie um índice nas tabelas PAGARB e PAGARD contendo as colunas (DOCUM, CODFOR, TPNOTA, SERIE, ORDEM).

Dica extra: No Firebird 2.5, evite TRIM dentro do WHERE se possível. Se o campo nrecibo puder ser gravado apenas como vazio ou preenchido (sem espaços extras), a comparação direta b.nrecibo = '' é mais veloz.
Você tem um índice composto criado com esses campos exatos ou eles são índices individuais?
[]´s
Alexandre Santos (AlxSts)
Avatar do usuário
Poka
Usuário Nível 4
Usuário Nível 4
Mensagens: 569
Registrado em: 25 Out 2004 21:26
Localização: Leme/SP

Re: Select demorando

Mensagem por Poka »

Obrigado Alexandre, vou fazer o teste aqui.



Poka
alxsts
Colaborador
Colaborador
Mensagens: 3146
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil
Curtiram: 1 vez

Re: Select demorando

Mensagem por alxsts »

Olá!
Poka escreveu: 06 Mai 2026 20:19 Obrigado Alexandre, vou fazer o teste aqui.
Gostaria de saber se funcionou e se melhorou a performance.
Poka escreveu: 04 Mai 2026 17:17 ela já esta com o ìndice docum+codfor+tpnota+serie+ordem
Não sei como está criando o índice, mas não pode ser como em Clipper, concatenado campos.

Sintaxe do Firebird:

Código: Selecionar todos

CREATE INDEX idx_pagarB ON pagarB(DOCUM, CODFOR, TPNOTA, SERIE, ORDEM);
--
CREATE INDEX idx_pagarD ON pagarD(DOCUM, CODFOR, TPNOTA, SERIE, ORDEM);

Poka escreveu: 06 Mai 2026 16:38 Alexandre, não sei como excluir o anterior.
Logado no fórum, abra a mensagem que deseja excluir. Na primeira linha da mensagem, lado direito, vai ver um botão com um "X". Clique nele e confirme.
[]´s
Alexandre Santos (AlxSts)
Avatar do usuário
Poka
Usuário Nível 4
Usuário Nível 4
Mensagens: 569
Registrado em: 25 Out 2004 21:26
Localização: Leme/SP

Re: Select demorando

Mensagem por Poka »

Boa noite.

Alexandre, o índice está correto, sem concatenar, estão separados por virgula.

A rotina com o case traz instantâneo, porém não traz somado por grupo (sum).
Se tiver 10 lançamentos na baixa, traz 10 lançamentos, não agrupados.
Fiz diversas alterações, mas não resolveu.

Vou mexer amanhã novamente, depois posto aqui, mas para trazer os dados ficou instantâneo.


Obrigado

Poka
Responder