- Criado por Wesley Avelino De Carvalho, última alteração em 23 set, 2019
Índice:
Objetivo:
A partir da versão 12.1.23 implementamos uma melhoria na execução de relatórios do RM Reports que tende a evitar que relatórios possam gerar o que chamamos de "produto cartesiano". Esta melhoria poderá acarretar inconsistências em relatórios quando houverem bandas com mais de uma tabela e o relacionamento entre seus campos estiverem incorretos.
Detalhes da melhoria:
Esta alteração obtém ganho de performance na execução dos relatórios. Explicaremos os cenários antes e pós alteração.
No exemplo do cenário anterior utilizaremos a seguinte estrutura no relatório;
1) - Banda pai (Detalhe1) = Ligada na tabela PFUNC
1.1) - Banda filha (SubDetalhe1)= Ligada na tabela PFDEPEND
Em cada banda utilizamos os seguintes controles (no exemplo são utilizados controles de campo da base);
1) - Banda pai:
[PFUNC.CODCOLIGADA, PFUNC.CHAPA, PFUNC.SALARIO e PPESSOA.CPF]
Neste exemplo temos um controle da tabela principal ligado a outro controle da tabela secundária (PPESSOA.CPF).
1.1) - Banda filha:
[PFDEPEND.CODCOLIGADA e PFDEPENDE.NOME]
Filtro do relatório utilizados na banda pai do relatório.
1) - Banda pai: PFUNC.CODCOLIGADA = 1
AND PPESSOA.CPF = '0027515458'
Neste caso temos uma parte do filtro ligado a tabela secundária da banda pai.
Quando o relatório é executado, o mecanismo de execução vai gerar duas sentenças sql’s dinamicamente baseadas nas configurações das bandas e controles.
Nesse exemplo serão geradas duas sentenças sql’s:
- A) - Primeira sentença: relacionada a banda pai;
SELECT PFUNC.CODCOLIGADA,
PFUNC.CHAPA,
PFUNC.SALARIO,
PPESSOA.CPF
FROM PFUNC
LEFT OUTER JOIN PPESSOA (NOLOCK) ON (PFUNC.CODPESSOA = PPESSOA.CODIGO)
WHERE PFUNC.CODCOLIGADA = 1
AND PPESSOA.CPF = '0015154515'
Na sentença acima, o mecanismo adiciona uma clausula (Left Outer Join) para tabela PPESSOA. Isso ocorre devido ao controle "CPF" existente na banda pai pois o mesmo não existe na tabela principal da banda "PFUNC".
- B) - Segunda sentença: relacionada a banda filha:
SELECT PFDEPEND.CODCOLIGADA,
PFDEPENDE.NOME
FROM PFDEPEND
INNER JOIN PFUNC (NOLOCK) ON (PFUNC.CODCOLIGADA = PFDEPEND.CODCOLIGADA
AND PFUNC.CHAPA = PFDEPEND.CHAPA)
WHERE PFUNC.CODCOLIGADA = 1
Perceba que a query acima retornará todos os dependentes de todos os funcionários da Coligada 1. Nesse caso, teremos considerado consumo de memória e performance.
Primeira sentença: Relacionada a banda pai;
SELECT PFUNC.CODCOLIGADA,
PFUNC.CHAPA,
PFUNC.SALARIO,
PPESSOA.CPF
FROM PFUNC
LEFT OUTER JOIN PPESSOA (NOLOCK) ON (PFUNC.CODPESSOA = PPESSOA.CODIGO)
WHERE PFUNC.CODCOLIGADA = 1
AND PPESSOA.CPF = '0015154515'
Nada muda em relação à query executada atualmente.
Segunda sentença: Relacionada a banda filha;
SELECT PFDEPEND.CODCOLIGADA,
PFDEPENDE.NOME
FROM PFDEPEND
INNER JOIN PFUNC (NOLOCK) ON (PFUNC.CODCOLIGADA = PFDEPEND.CODCOLIGADA
AND PFUNC.CHAPA = PFDEPEND.CHAPA)
LEFT OUTER JOIN PPESSOA (NOLOCK) ON (PFUNC.CODCOLIGADA = PPESSOA.CODCOLIGADA
AND PFUNC.CODPESSOA = PPESSOA.CODIGO)
WHERE PFUNC.CODCOLIGADA = 1
AND PPESSOA.CPF = '0015154515'
Nesta execução, a query de Dependentes retornará somente dependentes ligados ao Funcionário com CPF "0015154515"
Em resumo com a passagem da clausula "LEFT OUTER JOIN PPESSOA" da query ligada a banda pai para a query ligada a banda filha, somente os dependentes que participam da listagem do relatório serão recuperados da base. Isso melhorará consideravelmente a performance e memória do Host.
Depois do ajuste, percebermos um cenário que poderá trazer dados desnecessários no relatório, ficando a sensação de inconsistência no RM Reports.
No exemplo utilizaremos a seguinte estrutura no relatório;
1) - Banda pai (Detalhe1) = Ligada na tabela "PFUNC"
1.1) Banda filha (SubDetalhe1)= Ligada na tabela "PFDEPEND"
Em cada banda contem os seguintes controles (utilizados controles de campo da base);
1) - Banda pai:
[PFUNC.CODCOLIGADA, PFUNC.CHAPA, PFUNC.SALARIO, ABATFUN.DATA]
Neste exemplo temos um controle da tabela principal ligado a outro controle da tabela secundária (ABATFUN.DATA).
1.1) - Banda filha: [PFDEPEND.CODCOLIGADA, PFDEPENDE.NOME]
Quando o relatório é executado, o mecanismo de execução vai gerar duas sentenças sql’s dinamicamente baseadas nas configurações das bandas e controles. Nesse caso serão geradas duas sentenças sql.
Primeira sentença: Relacionada a banda pai;
SELECT PFUNC.CODCOLIGADA,
PFUNC.CHAPA,
PFUNC.SALARIO,
ABATFUN.DATA
FROM PFUNC
LEFT OUTER JOIN ABATFUN (NOLOCK) ON (PFUNC.CODCOLIGADA = ABATFUN.CODCOLIGADA
AND PFUNC.CHAPA = ABATFUN.CHAPA)
WHERE PFUNC.CODCOLIGADA = 1
AND ABATFUN.DATA < :DATAATUAL
Nada muda em relação à query que será executada depois da melhoria.
Segunda sentença: Relacionada a banda filha;
SELECT PFDEPEND.CODCOLIGADA,
PFDEPENDE.NOME
FROM PFDEPEND
INNER JOIN PFUNC (NOLOCK) ON (PFUNC.CODCOLIGADA = PFDEPEND.CODCOLIGADA
AND PFUNC.CHAPA = PFDEPEND.CHAPA)
LEFT OUTER JOIN ABATFUN (NOLOCK) ON (PFUNC.CODCOLIGADA = ABATFUN.CODCOLIGADA
AND PFUNC.CHAPA = ABATFUN.CHAPA)
WHERE PFUNC.CODCOLIGADA = 1
AND ABATFUN.DATA < :DATAATUAL
Neste cenário, a primeira sql, ao ser executada, retornará dados repetidos para o funcionário, visto que, existirá várias batidas para um único funcionário. Isso gera o que chamamos de "produto cartesiano". A query de dependentes retornará os dependentes ligados ao funcionário que possua batidas < que "DATAATUAL", gerando também, produto cartesiano para os dependentes.Sendo assim, ao gerar o relatório, na banda de dependentes, aparecerá vários dependentes repetidos de acordo com as batidas de um determinado funcionário.
Produto: Framework
Versão: 12.1.23 ou superiores
Processo: Execução de Relatórios