[firebase-br] Consulta demorando 2 horas como resolvo.

Jáber Lima jaber em confesoft.com.br
Seg Jun 6 08:10:18 -03 2011


Grande Eduardo....
Parabéns pela explanação...
Acredito que ajudou a muita gente, principalmente iniciantes como eu, a 
compreender melhor o funcionamento do FB.

[ ]'s

Jáber Sancho Coelho de Lima
Cel: (66)9613-2594
Fax: (66)3426-2171
Msn: jabertecnico em hotmail.com
Skype: jabertecnico


Em 04/06/2011 19:19, Eduardo Bahiense escreveu:
> Olá Luciano
>
> Desculpe se chego atrasado nesta thread, mas uso o FB em ambientes de 
> alta requisição e, por ter certeza de sua performance e segurança, 
> sinto-me na obrigação de analisar esse caso.
> Primeiramente, permita-me organizar essa consulta, pois, código SQL 
> deve ser tratado como qualquer linguagem de programação: indenta-se 
> para dar melhor entendimento, especialmente se a submetemos a terceiros.
>
> select
>     cm.codigo,
>     cm.codigo_barras,
>     cm.codigo_fabricante,
>     cm.cod_fornecedor,
>     cm.mercadoria,
>     cf.fornecedor,
>     Max(Case When(Gp.filial = 1) Then Gp.preco_g_vista End) As Preco_AS,
>     Max(Case When(Gp.filial = 2) Then Gp.preco_g_vista End) As Preco_MT
> from
>     cadastro_mercadorias cm
>     inner join cadastro_fornecedor cf on (cf.codigo = cm.cod_fornecedor)
>     Inner Join grade_produtos GP on (Gp.cod_produto = CM.codigo)
> Where
>     exists (select
>                 cc.codigo_barras
>             from
>                 cadastro_mercadorias cc
>             where
>                 cc.codigo_barras = cm.codigo_barras
>             group by
>                 1
>             having count(cc.codigo_barras) > 1
>             )
> group by
>     1, 2, 3, 4, 5, 6
> order by
>     cm.codigo_barras
>
> Bem, a primeira coisa que chama a atenção nessa consulta é o "order 
> by", no 2º campo. Como o Eduardo J. já mencionou, o próprio "group by" 
> já ordena, assim, um
> "group by 2,1,3,4,5,6", ou um
>     select
>         cm.codigo_barras,
>         cm.codigo,
>         ...
>     group by
>         1, 2, 3, 4, 5, 6
>
> evitaria o "order by", resultando em melhor performance, especialmente 
> se o resultado dessa consulta envolver milhares de linhas.
>
> Fora essa questão, a cláusula "select" está ok, nada a comentar.
> Quanto aos "joins", é preciso saber se há índices em:
>     cadastro_fornecedor.codigo
>     grade_produtos.cod_produto
> para que essas junções não tenha problema de performance.
> Outra coisa a se considerar é que "inner join" quando o lado direito 
> possui pouca correlação, pode ser muito penoso.
> Se você está usando "inner join" é porque está esperando que haja 
> produtos sem código de fornecedor ou sem código de grade_produto, 
> assim, você poderia, testar a performance com "left join" com uma 
> clasa "where" do tipo:
>     where
>         cm.cod_fornecedor is not null
>         and CM.codigo is not null
>         and exists(...)
>
> Verificadas essas questões, passamos para a cláusula "where" em si:
>
> Um "where exists(...)", por si só, obriga a busca natural, ou seja sem 
> índices, assim, todos os registros de "cadastro_mercadorias" serão, 
> obrigatoriamente lidos, e uma outra segunda consulta será executada 
> (select do exists) para cada linha de "cadastro_mercadorias".
> Bem, considerando o fato de que cada linha em "cadastro_mercadorias" 
> vai gerar um segunda consulta, esta deve ser cuidadosa quanto à 
> performance, então, vamos dar uma olhada:
>
>     select
>         cc.codigo_barras
>     from
>         cadastro_mercadorias cc
>     where
>         cc.codigo_barras = cm.codigo_barras
>     group by
>         1
>     having count(cc.codigo_barras) > 1
>
> Primeiramente, temos que analisar se há um índice em 
> "cadastro_mercadorias.codigo_barras", porque se não houver índice, 
> para cada linha percorrida em "cadastro_mercadorias", haverá uma 
> varredura em todas as linhas dessa mesma tabela para pesquisar esse 
> "where".
> Verificado o índice, observe que exists(...) não depende de um campo, 
> basta "select 1", ao invés de "select cc.codigo_barrsas". Não que isso 
> seja determinante na performance, mas se estamos falando em otimizar...
> O group by neste subselect também é totalmente dispensável, se o 
> construirmos dessa forma:
>
> where (
>     select
>         count(1)
>     from
>         cadastro_mercadorias cc
>     where
>         cc.codigo_barras = cm.codigo_barras
> ) > 1
>
> Se houver índices adequados, mesmo não sendo a melhor construção, você 
> não deveria ter problemas de performance, e isso nos remete a uma 
> afirmativa sua:
>
> "Ele vai retornar produtos com o codigo de barras duplicados. eu sei 
> que deve ter SQLs mais simples para esse proposito só que agora achei 
> interessante o porque o PostGreSQL ser tão mais veloz".
>
> Acho improvável que o PG consiga performance muito melhor nas mesmas 
> condições de volume de dados e planejamento de índices. O mais 
> provável é que você tenha movido dados do PG para o FB sem trazer o 
> planejamento de índices, contudo, se o que você quer e identificar 
> produtos com código de barras duplicados, dentro da estrutura inicial 
> que você informou
>
> select
>     cm.codigo_barras,
>     cm.codigo,
>     cm.codigo_fabricante,
>     cm.cod_fornecedor,
>     cm.mercadoria,
>     cf.fornecedor,
>     Max(Case When(Gp.filial = 1) Then Gp.preco_g_vista End) As Preco_AS,
>     Max(Case When(Gp.filial = 2) Then Gp.preco_g_vista End) As Preco_MT
> from
>     cadastro_mercadorias cm
>     inner join cadastro_fornecedor cf on (cf.codigo = cm.cod_fornecedor)
>     Inner Join grade_produtos GP on (Gp.cod_produto = CM.codigo)
> group by 1,2,3,4,5,6
> having count(*) > 1
>
> Observe apenas que você está pedindo se há codigos de barras duplicado 
> para cada conjunto fornecedor/fabricante/mercadoria.
>
> Dá para conversar muito sobre tudo isso, mas já falei demais para um 
> post.
>
> Sucesso,
>
> Eduardo
>
>
>
>
>
>
> ______________________________________________
> FireBase-BR (www.firebase.com.br) - Hospedado em www.locador.com.br
> Para saber como gerenciar/excluir seu cadastro na lista, use: 
> http://www.firebase.com.br/fb/artigo.php?id=1107
> Para consultar mensagens antigas: http://firebase.com.br/pesquisa
>




Mais detalhes sobre a lista de discussão lista