In Navision gebruikt men traditioneel 2 verschillende Find statements om records terug te vinden in een tabel, namelijk FIND('-') en FIND('+'). Deze functies worden gebruikt om
Het eerste of laatste record te vinden in een tabel of een set
- Checken of er records bestaan in een tabel
- Door records loopen in een tabel of een set
Deze functies werken zeer goed en performant op de native Navision Database omdat deze gebruik maakt van ISAM (Indexed Sequential Access Method) en dus records individueel gaat lezen. Deze statements kunnen ook gebruikt worden om een set van records op te vragen en vervolgens in deze set eventueel een key aan te passen van de index waarop de set gebaseerd is. Hiermee heeft SQL Server problemen, in tegenstelling tot de Native Database.
Sql server en de NDBCS database driver zijn ontworpen opdat SQL Server probeert te ontdekken of er in een loop wordt gelezen of als men single records wenst op te halen. Sql server misinterpreteert soms deze FIND('-') en FIND('+') statements en is geneigd set based queries te produceren om kleine recordsets terug te sturen in plaats van gewoon het single record terug te sturen wat gevraagd was. Dit gebeurt meestal als men gebruik maakt van de combinatie WHILE FIND('-') in plaats van de REPEAT UNTILL NEXT methode. Dit is een extreem inefficient gebruik van SQL Server en dus nefast voor de performantie van onze applicatie.
SQL Server heeft veel liever precieze statements die hem toelaten zijn cursors optimaler te herbruiken. Navision is nu uitgebreid met enkele nieuwe functies om dit te verbeteren, namelijk
- FINDFIRST
- FINDLAST
- FINDSET
Deze functies voeren exact hetzelfde uit maar veel efficienter en gaan de server niet belasten met onnodige server-calls en cursors. Deze functies resulteren in mindere server calls, een simpeler execution plan en een efficient gebruik van cursors.
Synthax: [OK] := FINDFIRST;
Gebruik deze functie om het eerste record te vinden in een tabel gebaseerd op de huidige key en filter.
- Minder round trips naar de server
- Simpeler Sql-Plan
- Efficient hergebruik van cursors
- Select TOP 1*, ...
Kan FIND(‘-’) vervangen op Microsoft Dynamics NAV Server
Synthax: [OK] := FINDLAST;
Gebruik deze functie om het laatste record te vinden in een tabel gebaseerd op de huidige key en filter.
- Minder round trips naar de server
- Simpeler Sql-Plan
- Efficient hergebruik van cursors
- Select TOP 1*, DESC ...
Kan FIND(‘+’) vervangen op Microsoft Dynamics NAV Server
Als je bijvoorbeeld een codeunit maakt waarin je 5 keren na elkaar een FIND('-') uitvoert, en je doet hetzelfde met een FINDFIRST dan zal je merken als je, bijvoorbeeld via de Client Monitor, de gegenereerde SQL-statements bekijkt dat in het geval van de FINDFIRST de Navision database driver sneller het juist SQL statement genereert en vervolgens SQL Server veel sneller zijn caching gaat aanspreken enzo het eenmaal uitgevoerde statement en bijhorend query plan zal hergebruiken.
Vervolgens is er ook nog het FINDSET statement:
Synthax: [OK]:=FINDSET([ForUpdate][,UpdateKey]);
Gebruik deze functie om een set van records te vinden in een tabel gebaseerd op de huidige key en filter. De records kunnen alleen opgehaald worden in dalende volgorde (ascending).
[ForUpdate]:
Zet deze parameter op FALSE als je geen records in de set wil aanpassen.
Zet deze parameter op TRUE als je wel records in de set wil aanpassen.
Als je deze parameter op TRUE zet dan zal een LOCKTABLE uitgevoerd worden op de tabel voor de records worden gelezen.
[UpdateKey]:
Deze parameter is alleen van toepassing als de ForUpdate parameter op TRUE staat.
Als je een veld dat deel uitmaakt van de huidige key wil aanpassen dan moet je deze parameter op TRUE zetten.
Met FINDFIRST en FINDLAST is het de bedoeling om 1 record op te halen en niet een hele set dus als je niet door een set van records wil lopen.
Als het de bedoeling is om een set van records af te lopen gebruik je beter FINDSET. Maar deze haalt de records op in ASCENDING volgorde.
Omdat je met FIND(+) en FIND(-) niet direct meegeeft aan SqlServer of dat hij 1 of meerdere records moet ophalen genereert hij soms teveel of slechte Sql statements (select * ipv select top 1) Met de FINDLAST en FINDFIRST statements wordt meteen aan SqlServer duidelijk gemaakt dat er slechts 1 record hoeft opgehaald te worden en wordt dan ook direct het juiste Sql statement gegenereerd (select top 1).
De oplossing die je voorstelt (FINDLAST en REPEAT UNTIL) of FIND(+) denk ik niet dat veel tijdsverschil zullen opleveren. Om zeker te zijn kan je de 2 mischien eens uitproberen en monitoren in de client monitor. Dan kan je direct zien of ze evenlang duren en dezelfde Sql genereren op SqlServer.
Posted by: Steven | 17/08/2006 at 14:46
Het is me aan de hand van het artikel niet duidelijk geworden welke FIND je nu precies het beste gebruikt als je een set records in descending order wilt doorlopen.
Doe je dan een FINDLAST gevolgd door een REPEAT met een UNTIL NEXT(-1) of is het dan beter om hier ipv FINDLAST de oude FIND('+') te gebruiken?
Posted by: Carla de Leeuw | 17/08/2006 at 13:57