sexta-feira, 21 de outubro de 2011

Order, when e otimizações

Esse tema, meio polêmico deixa muita gente nervosa, de cabelo em pé, e reflete um pouco a respeito das pesquisas e acessos realizados na base de dados, que sempre são uma preocupação grande devido ao desempenho desejado na aplicação, pois, Genexus oferece a programação de cláusulas condicionais, when, tanto em order quanto em where, oferecendo um mecanismo bastante interessante e flexível para acesso ao banco, mas o uso indiscriminado pode trazer complicações.

A idéia é que além do efeito visual obtido em uma navegação, no preenchimento de grids, por exemplo, tenhamos também um bom desempenho, ou seja, sempre um pequeno número de registros ordenados e processados corretamente.  Desta forma sem ler o resultado da navegação gerada, você estará correndo grandes riscos em sua aplicação, visto que o usuário não gostará muito de esperar minutos para que uma resposta seja apresentada na interface.

Um exemplo de programação que utiliza when pode ser vista a seguir.

     for each
          order ManualTitle when not &ManualTitle.IsEmpty()
          order ProcessId when &ProcessId<>0
          where ProcessId = & ProcessId when & ProcessId<>0
          where ManualTitle like '%'+&ManualTitle+'%' when not &ManualTitle.IsEmpty()

Ela diz que se houver titulo fornecido ordena-se e filtra-se por titulo, se houver processo, o mesmo, ordena-se e filtra-se por processo.  Mas o fato é que o resultado final não é bom, pois no mapa de navegação teremos a pesquisa à tabela toda (Navigation Filters), ou seja, lentidão.


Um pequeno detalhe, pois quando optar por programar com a cláusula when, todas as ordenações devem ser colocadas o when, caso contrário teremos um erro de sintaxe.

     for each
          order UserManualTitle
          order ProcessId when &ProcessId<>0

error: Expecting 'EndFor' command to close the 'For Each' block (Events, Line: 50, Char: 9#62ea5034-c4dd-4bb2-ad33-56cd112159d7)
error: '{0}' is an unexpected expression. (Events, Line: 50, Char: 25#1b09b22d-3400-46a8-8934-b7f4000a0192)
error: Unexpected command 'where' (Events, Line: 51, Char: 3#ea102e2d-fc92-4228-94bb-3cb856efd2b8)
error: '{0}' is an unexpected expression. (Events, Line: 51, Char: 9#7d0a990c-475e-4292-875e-65313180b500)
error: Unexpected command 'where' (Events, Line: 52, Char: 3#45f8ec05-0b6e-4b58-a4ac-8ed937fec794)


O operador like também contribui para uma situação de pesquisa não otimizada na base.
 
Uma saída (existem outras) para essa situação é criar um índice composto por várias ordenações, usando vírgulas, e eliminando-se a cláusula when quando for possível.

     for each
          order ProcessId, UserManualTitle
          where ProcessId = &ProcessId
          where UserManualTitle like '%'+&UserManualTitle+'%'

O resultado é uma pesquisa melhor, otimizada e mais rápida, apesar do efeito visual final não ser muito bom, visto que a consulta dependeria de dados para ser processada, desta forma o usuário teria uma interface vazia onde teria que fornecer informações para ver alguma coisa.



Considere otimizada o fato de Start from e Loop while apresentar valores condicionais ao invés de FirstRecord e NotEndOfTable.  Pode parecer meio estranha a principio, mas o resultado é muito melhor, principalmente na web onde tudo é mais lento, e o fato do usuário determinar o que quer ver, já significa que não perderá tempo com informações inúteis.

Enfim, cuidado com a cláusula when, principalmente em sistemas Web, caso contrário seu chefe vai colocar o exército chines atrás de voce.