FieldByName ou Fields

Vamos aos fatos então, iremos para o Delphi e ver oque cada código diz para nos
Implementação do FindFields do Objeto em FFields
function TFields.FindField(const FieldName: string): TField;
var
I: Integer;
begin
for I := 0 to FList.Count - 1 do begin
Result := FList.Items[I];
if AnsiCompareText(Result.FFieldName, FieldName) = 0 then Exit;
end;
Result := nil;
end;
Nesse código podemos observar que se uma determinada tabela conter 200 campos e temos na posição 200 um campo calculado com o qual precisamos fazer uma soma do tipo:
Campo calculado na posição 100
valor := 0;
while not DataSet.Eof do begin
Valor := valor + DataSet.FieldByName('campo_calculado').asCurrency;
DataSet.Next;
end;
Se tivermos neste DataSet 200.000 registros, teremos que passar pela linha de código
Valor := valor + DataSet.FieldByName('Campo_Calculado').asCurrency;
200.000 vezes. Um processamento razoável. Mas e o FieldByName? Observem que na implementação do método FindField da classe TField é utilizado um for de 0 até o número de campos para se encontrar o campo desejado e assim retornar o valor. Sendo, o nosso campo desejado, o campo de número 100, cada chamada de FieldByName - em nosso caso - ocasionaria um processamento de uma repetição 100 vezes até que o campo seja encontrado. Agora vamos fazer uma conta simples:
100.000 registros x 100 vezes (FieldByname) = 10000000 instruções processadas. Tenho certeza que vocês concordam comigo que é muito. ('Imagina isso em uma grande aplicação')
Mas qual a solução? Fields[100]?
Vamos ver a implementação da classe TFields para ver como o mesmo processa a instrução
Implementação em TFields:
Fields[indice]:
TFields = class(TObject)
private
FList: TList;
...
protected
...
function GetField(Index: Integer): TField;
...
public
...
property Fields[Index: Integer]: TField read GetField write SetField; default;
end;
Podemos ver que Fields é uma property indexada, com certeza é mais rápido que o método "for" do FieldByName mas vamos mais a fundo. Vamos dar uma olhadinha no método de acesso GetField:
if FSparseFields > 0 then begin
if Index >= FSparseFields then
DatabaseError(SListIndexError, DataSet);
Result := FList[0];
Result.FOffset := Index;
end else
Result := FList[Index];
Reparem quem em nosso caso, que apenas a linha Result := FList[Index]; será acionada utilizando um TList onde são armazenados os campos de um DataSet. E como será a implementação da propriedade que define os itens de um TList?
"Implementação do TList"
TList = class(TObject)
private
FList: PPointerList;
...
protected
function Get(Index: Integer): Pointer;
...
public
...
property Items[Index: Integer]: Pointer read Get write Put; default;
...
end;
Por fim chegamos ao método de acesso Get da property items da classe TList:
"Método Get da propriedade itens de TList:"
function TList.Get(Index: Integer): Pointer;
begin
if (Index < 0) or (Index >= FCount) then
Error(@SListIndexError, Index);
Result := FList^[Index];
end;
Observem a diferença. Aqui se trabalha com Ponteiros para a localização do campo desejado. Sendo assim, o processamento desta instrução terá peso 1, mesmo que tenhamos 20 campos em nosso DataSet. Agora vamos pensar na conta que fizemos anteriormente.
100000 registros x 1 vez (Fields[indice]) = 100000 instruções processadas.
Olha que diferença entre executar 2000000 de instruções e 100000. Por isto digo, dentro de laços envolvendo um campo de um DataSet com vários campos, pensem bem se vale a pena utilizar
valor := 0;
while not DataSet.Eof do
begin
Valor := valor + DataSet.FieldByName('campo_calculado').asCurrency;
DataSet.Next;
end;
ou
valor := 0;
while not DataSet.Eof do
begin
Valor := valor + DataSet.Fields[20].asCurrency; //campo_calculado
DataSet.Next;
end;
Mas vamos deixar a coisa mais feia ainda, pensem nisso:
FieldByName('A').asInteger :=
((FieldByName('B').asInteger + FieldByName('C').asInteger)/ FieldByName('D').asInteger) * FieldByName('E')
Isto para 1000 registros, em um DataSet com 5 campos (sendo muito otimista) daria no pior caso:
1(A) x 2(B) x 3(C) x 4(D) x 5(E) x 100 = 120000 instruções processadas
Agora transportem esta situação para um DataSet com um pouco mais de campos e um pouco mais de registros. Na minha opinião inviável. Qual a maior dificuldade de usar Fields[indice]? A legibilidade do código?
Pois bem, nada que um comentário não resolva
Field[indice] // refere-se a campo tal..
Achei isso numa revista de delphi a algum tempo. Achei muito interessante e decidi compartilhar com vocês ^^
Se gostar comente ^^
0 comentários:
Postar um comentário