Página 1 de 1
Select demorando
Enviado: 04 Mai 2026 17:17
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
Re: Select demorando
Enviado: 04 Mai 2026 18:18
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...
Re: Select demorando
Enviado: 04 Mai 2026 23:35
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).
Re: Select demorando
Enviado: 05 Mai 2026 18:30
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.
Re: Select demorando
Enviado: 05 Mai 2026 18:37
por JoséQuintas
Não conheço o x || y || z
Re: Select demorando
Enviado: 05 Mai 2026 18:54
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
Re: Select demorando
Enviado: 06 Mai 2026 16:38
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
Re: Select demorando
Enviado: 06 Mai 2026 18:07
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?
Re: Select demorando
Enviado: 06 Mai 2026 20:19
por Poka
Obrigado Alexandre, vou fazer o teste aqui.
Poka
Re: Select demorando
Enviado: 06 Mai 2026 21:54
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.
Re: Select demorando
Enviado: 07 Mai 2026 20:07
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
Re: Select demorando
Enviado: 11 Mai 2026 23:21
por alxsts
Olá!
Chamou minha atenção esta frase na resposta da IA:
alxsts escreveu: 06 Mai 2026 18:07
## Por que isso fica mais rápido?
1. SARGability: Ao usar coluna = :valor, o Firebird usa o índice da chave primária ou estrangeira.
Recorrendo novamente a ela:
SARGability (uma contração de Search ARGument ABLE) refere-se à capacidade de uma consulta SQL utilizar índices do banco de dados para recuperar dados com eficiência. Consultas "sargable" permitem que o SGBD faça um Index Seek (busca direta no índice), sendo muito mais rápidas do que Index Scans (varredura completa).
Pontos-chave sobre SARGability:
O que torna uma consulta sargable:
O uso de operadores como =, >, <, >=, <=, BETWEEN, LIKE 'texto%' (iniciando com).
O que torna uma consulta non-sargable:
Uso de funções na coluna indexada na cláusula WHERE (ex: WHERE YEAR(Data) = 2024), conversão de tipos de dados, ou uso de LIKE '%texto'.
Vantagens:
Reduz o consumo de I/O, diminui o uso da CPU e melhora drasticamente o desempenho de consultas em grandes tabelas.
Origem:
O conceito foi criado por pesquisadores da IBM, indicando que uma cláusula WHERE pode ser otimizada via índices.
Exemplos Práticos:
Não Sargable:
WHERE YEAR(DataVenda) = 2023 (O banco não usa o índice em DataVenda).
Sargable: WHERE DataVenda >= '2023-01-01' AND DataVenda < '2024-01-01' (O banco usa o índice, se existente).
Re: Select demorando
Enviado: 12 Mai 2026 22:02
por Fernando queiroz
Eu aconselharia separar o resumo das somas do SELECT principal. Do jeito atual, ele agrupa por b.valor, b.dc, b.nrecibo, d.valor, então pode gerar várias linhas e ainda obriga o Firebird a agrupar mais dados do que precisa.
Também tem dois possíveis erros:
FROM PAGARB bINNER JOIN PAGARD d
deveria ser:
FROM PAGARB b
INNER JOIN PAGARD d
E aqui tem diferença entre :order e :ordem:
d.ordem = :order
provavelmente deveria ser:
d.ordem = :ordem
A versão mais performática e limpa seria assim:
SELECT
d.valor AS valor_pagard,
SUM(CASE
WHEN b.dc = 'C' AND COALESCE(TRIM(b.nrecibo), '') = ''
THEN b.valor ELSE 0
END) AS soma_c_vazio,
SUM(CASE
WHEN b.dc = 'D' AND COALESCE(TRIM(b.nrecibo), '') = ''
THEN b.valor ELSE 0
END) AS soma_d_vazio,
SUM(CASE
WHEN b.dc = 'C' AND COALESCE(TRIM(b.nrecibo), '') <> ''
THEN b.valor ELSE 0
END) AS soma_c_cheio,
SUM(CASE
WHEN b.dc = 'D' AND COALESCE(TRIM(b.nrecibo), '') <> ''
THEN b.valor ELSE 0
END) AS soma_d_cheio
FROM PAGARD d
LEFT JOIN PAGARB b ON
b.docum = d.docum
AND b.codfor = d.codfor
AND b.tpnota = d.tpnota
AND b.serie = d.serie
AND b.ordem = d.ordem
WHERE
d.docum = :docum
AND d.codfor = :codfor
AND d.tpnota = :tpnota
AND d.serie = :serie
AND d.ordem = :ordem
GROUP BY
d.valor;
Índices recomendados no Firebird 2.5:
CREATE INDEX IDX_PAGARD_CHAVE ON PAGARD
(DOCUM, CODFOR, TPNOTA, SERIE, ORDEM);
CREATE INDEX IDX_PAGARB_CHAVE ON PAGARB
(DOCUM, CODFOR, TPNOTA, SERIE, ORDEM);
Se PAGARB tiver muitos registros por documento, pode ajudar também:
CREATE INDEX IDX_PAGARB_CHAVE_DC ON PAGARB
(DOCUM, CODFOR, TPNOTA, SERIE, ORDEM, DC);
O ponto principal: não agrupar por b.valor, b.dc e b.nrecibo, porque isso quebra a soma em várias linhas. Agrupe somente pelo que vem da PAGARD, ou nem agrupe se PAGARD retornar apenas uma linha.