Případ FieldByName

vložil Radek Červinka 16. ledna 2011 21:36

Často programátoři v Delphi používají pro přístup k jednotlivým položkám datasetu vyhledávání přes FieldByName. Takový kód je celkem čitelný, ale lehce může sklouznout k velkým časovým ztrátám.

Při používání FieldByName je dobré si uvědomit, že tato metoda vrací následníka TField, což je klasický objekt. Podle mne původní myšlenka autorů Delphi byla, že jednotlivé položky (fields) budou primárně definovány v IDE (přesně tak jak se to dá dodnes dělat). Můžeme to chápat jako ekvivalent instancí kontrolů (např. TButton), které také definujeme v IDE (ale můžeme je vytvářet dynamicky a hledat přes jméno - ale dělá se to jen výjimečně).

Ale časem se ukázala definice controls v design modu jako velmi výhodná, kdežto definice polí datasetu už ne všem vyhovující a místo toho programátoři generují dotazy a k polím přistupují dynamicky právě přes FieldByName.

Problémem je, že až do některé z nových verzí nebyla implementace této metody nijak optimalizovaná. Pravděpodobně v Delphi 2010 (nebo 2009) byla implementace předělána na implementaci za pomocí hash tabulky, ale přesto se dá ještě ušetřit.

Pokud nemáte tak vysokou verzi Delphi a nelíbí se Vám níže popsané řešení, můžete použít skvělé řešení které publikoval Zarko Gajic - hooknutí TDataset za pomocí háčku, který jsem zde již popisoval (nahrazení metody za běhu - viz. dole tag hacky) na rychlejší vyhledávání - Faster FieldByName.

Ale zpět. Klasickým takovým případem může být procházení otevřeného datasetu přes všechny položky, něco jako (je to příklad, ano znám SQL):

    1while not ds.Eof do
    2  begin
    3    dmPrice := dmPrice +  ds.FieldByName('Price').AsCurrency;
    4    ds.Next;
    5  end;

případně cokoliv, co mnohokrát přistupuje k jedné položce.

Pokud uvedený příklad napíšeme následujícím způsobem, dostaneme pravděpodobně nejrychlejší klientské řešení (i mnohem rychlejší než pomocí hash table - jen ne tak komfortní), a to díky použití nalezeného objektu. Pak totiž už jen přistupujeme pouze k jeho proměnným a metodám:

    1var
    2  oPriceField: TField;
    3
    4    5  oPriceField:= ds.FieldByName('Price');
    6  while not ds.Eof do
    7  begin
    8    dmPrice := dmPrice +  oPriceField.AsCurrency;
    9    ds.Next;
   10  end;  
   11
   12end;

A poslední, snad zajímavý, kód:

    1with ds.FieldByName('Price') do
    2  begin
    3    if AsCurrency > 0 then
    4      Price := Price + AsCurrency
    5    else
    6      Debit := Debit - AsCurrency;
    7  end;

což pro mne představuje krásné využití with pro ušetření jednoho volání FieldByName (pro každou větev). Opět se jedná pouze o ideový příklad.

Jen bych upozornil, že cílem článku mělo být jen upozornění na možné problémy. Je věcí každého jak bude svůj program psát. V každém případě pokud máte problém s rychlostí, zkuste pro zjištění úzkého hrdla použít profiler (i když se to dnes už moc nenosí - slušně řečeno).


Nabízíme Delphi školení a konzultace na různá témata, primárně ve Vaší firmě.

Tagy: , , ,

Praxe

Komentáře

17.1.2011 13:10:55 #

tomk

Ja jsem v dobach psani databazovych programu pouzival pro svoje pohodli a lepsi prehlednost kodu u pristupu k polim tabulek class helper (rychlost jsem neresil).

Napr.:

TDataSetHelper = class helper for TDataSet
private
  function GetCena: Currency;
  procedure SetCena(Value: Currency);  
public
  property Cena: Currency read GetCena write SetCena;
end;

function TDataSetHelper.GetCena: Currency;
begin
  Result := FieldByName('cena').AsCurrency;
end;

procedure TDataSetHelper.SetCena(Value: Currency);  
begin
  FieldByName('cena').AsCurrency := Value;
end;

Faktura: TDBTable;

Faktura.Cena := 999;
Faktura.Dph := Faktura.Cena * SysInfo.SazbaDph / 100;
Faktura.Celkem := Faktura.Cena + Faktura.Dph;

Class helper ovlivnuje vsechny objekty tabulek - potomku TDataSetu -, proto podminkou je, aby vsechny stejne se jmenujici pole v tabulkach mely stejny typ.

Kod zni velmi libozvucne, ze? :)

tomk

17.1.2011 19:02:22 #

pepak

Můžu potvrdit, že když jsem před časem hledal příčiny, proč mi jedna databázová operace trvá strašně dlouho, bylo použití FieldByName v každé iteraci smyčky druhým největším žroutem času (hned po špatné implementaci počítaných polí).

pepak

Komentování ukončeno

Naše nabídka

Partial English version.

MVP
Ing. Radek Červinka - Embarcadero MVP
profil na linkedin, Twitter:@delphicz

Nabízím placené poradenství a konzultace v oblasti programování a vývoje SW.
Dále nabízíme i vývoj speciálního software na zakázku.

Neváhejte nás kontaktovat (i ohledně reklamy nebo burzy práce).

Pokud chcete podpořit tento server libovolnou částkou, můžete použít PayPal. Moc děkuji.

Delphi Certified Developer

O Delphi.cz

Delphi je jediný moderní RAD nástroj podporující tvorbu nativních aplikací pro platformu Win32, Win64 , Mac OSX a na iPhone a Android (s výhledem na další platformy díky FireMonkey) na současném trhu (včetně Windows 8.1).

V současnosti je světová komunita přes dva miliónů vývojářů.

Delphi.cz je nezávislý portál pro uživatele Delphi. Portál není koncipován pro úplné začátečníky, i když i ti se zde nebudou nudit, ale spíše na programátory, kteří již něco znají a chtějí své znalosti dále rozvíjet a sledovat novinky.

Anketa

Poslední komentáře

Comment RSS