terça-feira, 2 de dezembro de 2014

O que não fazer ao utilizar o dbUseArea

O que não fazer ao montar uma query

É muito comum por falta de experiência, por pressa ou falta de conhecimento, independentemente da linguagem esquecermos de fazer uma análise melhor dos dados que puxamos em nosso banco de dados.

Certo dia estava naquela correria para montar um Web Service para cancelamento de notas fiscais e sai fazendo daquele jeito.

Depois fui fazer uma manutenção no programa e encontrei a seguinte linha :

//PREENCHENDO OS ITENS DA NOTA FISCAL (SD1) 
cQuery := " SELECT * FROM " + RetSqlName("SD1") // * FROM é coisa porca. Depois vou arrumar
cQuery += "    WHERE D1_FORNECE = '"+ cfornecedor + "'" 
cQuery += "    AND D1_LOJA = '"     + cLoja       + "'" 
cQuery += "    AND D1_DOC = '"      + cNota       + "'" 
cQuery += "    AND D1_SERIE = '"    + cSerie      + "'"                    
cQuery += "    AND D_E_L_E_T_ = ' '" 


Na linha destacada acima, veja que utilizei o SELECT * FROM ao invés de mencionar o nome dos campos como D1_FORNECE, D1_LOJA, D1_DOC, D1_SERIE, etc....

Parece preciosismo mas não é, um usuário rodando este programa a perca é imperceptível mas quando rodamos em um ambiente com muitos usuários teremos uma boa perca de performance.

Um comentário:

  1. Duas outras dicas são:
    - sempre filtrar a filial, para que o banco utilize um índice na busca.
    - utilize o R_E_C_N_O_ no SELECT, e posicione o registro. Assim todos os campos estarão disponíveis para você.
    Exemplo:

    Local cQuery := ""
    Local cAliasTRB := ""

    //
    // ....
    //

    cQuery := " SELECT SD1.R_E_C_N_O_ SD1RecNo "
    cQuery += " FROM " + RetSqlName("SD1") + " SD1 "
    cQuery += " WHERE SD1.D_E_L_E_T_ = ' ' "
    cQuery += " AND SD1.D1_FILIAL = '" + xFilial("SD1") + "' " // Procure sempre filtrar a filial.
    cQuery += " AND SD1.D1_FORNECE = '" + cFornecedor + "' "
    cQuery += " AND SD1.D1_LOJA = '" + cLoja + "' "
    cQuery += " AND SD1.D1_DOC = '" + cNota + "' "
    cQuery += " AND SD1.D1_SERIE = '" + cSerie + "' "

    cAliasTRB := GetNextAlias()
    dbUseArea(.T., "TOPCONN", TCGenQry(,, cQuery), cAliasTRB, .F., .T.)

    Do While (cAliasTRB)->(!eof())
    SD1->(dbGoTo((cAliasTRB)->SD1RecNo))

    //
    // ... faça sua lógica aqui usando o SD1 diretamente.
    //

    (cAliasTRB)->(dbSkip())
    EndDo

    (cAliasTRB)->(dbCloseArea())

    ResponderExcluir