Search  
Monday, October 23, 2017 ..:: Articole ::.. Register  Login
 Article Details
Making Rushmore Rush More

Autor: Ken Murphy
Scopul acestui articol este acela de ati arata cum sa folosesti optimizarea Rushmore ca sa iti faciliteze aplicatii mai rapide.

Introduction

            Viteza este un factor important intr-o aplicatie. Abilitatea de a gasi inregistrarea sau setul de inregistrari de care ai nevoie afecteaza direct manevrabilitatea aplicatiei tale. Intr-o aplicatie unde tu lucrezi doar cu cateva zeci de mii de inregistrari, nu trebuie neaparat sa te gandesti la optimizarea aplicatiei, dar cand incepi a lucra cu cateva sute de mii de inregistrari sau chiar peste un milion, fara sa optimizezi aplicatia, utilizatorii se for astepta ca aplicatia ta sa gaseasca inregistrarile cerute de ei. In mod ciudat, utilizatorii au tendinta sa gandeasca pentru un oarecare motiv ca timpul lor este foarte imortant, si faptul ca aplicatia ta ii face sa astepte pana ce se gaseste inregistrarea sau setul de inregistrari, ii enerveaza. Scopul acestui articol este acela de ati arata cum sa folosesti optimizarea Rushmore ca sa iti faciliteze aplicatii mai rapide. Cheia utilizarii Rushmore este sa intelegeti cum functioneaza. Aceasta va faciliteaza incontinuare un design inteligent care va asigura o folosire corecta a tehnologiei Rushmore.

„Sa privim la date”

Inainte sa incepem a ne uita la Rushmore, este foarte important sa stim cate ceva despre cum se stocheaza inregistrarile in tabele de pe discul fizic. Daca ar fi sa ne uitam la o tabela de pe discul tau, nu am vedea coloane si randuri; in schimb am vedea un lung sir de date (un string foarte lung). Prima ‚gramada’ de octeti ar contine capul de tabel (table headder), daca ai avea rabdare sa descifrezi capul de tabel ai fi capabil sa iti dai seama lungimea inregistrarii. Hai sa presupunem ca lungimea inregistrarii tale are 500 de octeti. Daca ai vrea sa te uiti la urmatorea inregistrare din tabela, ai avea nevoie sa muti capul de citire pe disc exact 500 de octeti de la sfarsitul capului de tabel. Ca sa ne uitam la inregistrarea numarul 100 am avea deci nevoie sa citim exact 50 000 octeti de la sfarsitul capului de tabel, s.a.m.d. Din nou daca ne-am uita la tabelul nostru de pe disc, am constata ca inregistrarile din tabela nu sunt sortate dupa cheia primara. VFP adauga inregistrari adaugandule la sfarsitul tabelei. Prima inregistrare in tabela ar fi prima inregistrare adaugata iar a doua inregistrare ar fi inregistrarea urmatore; altfel spus este foarte posibil ca prima inregistrare din tabela ta sa fie inregistrarea cu numarul de ordine 1 (ReccNo = 1) si ultima inregistrare sa fie inreg cu nr. de ordine 2 (ReccNo = 2). Daca asa stau lucrurile mutarea capului de citire de la ReccNo=1 la ReccNo=2 inseamna ca trebuie sa citim intreaga lungime a tabelei. Daca aceasta tabela este una mare sau foarte mare, mutarea capului de citire va lua foarte mult timp. Sa subliniem faptul ca aici este vorba de un proces mecanic care este foarte incet (aduti aminte de scrierea mecanica pe discheta).

Sortarea inregistrarilor pe masura ce sunt adaugate ia de departe foarte mult timp. Daca ai vrea ca inregistrarile tale sa fie sortate intr-o ordine, pe masura ce adaugi fiecare inregistrare, ai avea nevoie sa folosesti o tabela temporara in care sa sortezi inregistrarile adaugate sau modificate. Ai incepe prin a citi continutul tabelei existente si a compara cheia inregistrarii noi cu cheia inregistrarii existente, daca cheia existenta este mai mica decat cheia inregistrarii noi, ai salva acea inregistrare existenta in tabela temporara si ai face loop in continuare spre inregistrarea urmatoare din tabela originala. Ai continua acest loop pana cand ai gasi o inregistrare in tabela existenta cu o cheie mai mare decat cheia inregistrarii pe care o adaugi. Cand insfarsit ai gasi inregistrarea cu o cheie mai mare decat cheia noii inregistrari, ar trebui sa salvezi noua inregistrare in tabela temporara dupa cara sa salvezi inregistrarea curenta. Iarasi ar trebui sa faci loop prin toate inregistrarile ramase in tabela originala si sa le salvezi in tabela temporara. Acum stergi tabela existenta, redenumesti tabela temporara folosind numele tabelei originale si ai avea o tabela sortata. Evident, toata operatiunea va dura o gramada de timp si situatia in continuare se inrautateste – daca vei adauga sute de inregistrari va trebui sa apelezi la aceasta procedura de sortare pentru fiecare inregistrare nou adaugata. In versiunile mai vechi de VFP exista comanda SORT care facea exact ce sa prezentat mai sus. Sortarea inregistrarilor pe masura ce sunt adaugate pur si simplu ia foarte mult timp. Din acest motiv foarte simplu VFP adauga inregistrarile la sfarsitul tabelei.

Crearea unei cereri rapide in VFP

            Inainte sa ne uitam la Rushmore sa ne uitam mai intai la cum functioneaza o cerere (query) fara Rushmore. Sa luam aminte la urmatoarea cerere:

SELECT * ;

  FROM MyTable ;

  WHERE cSomeField = lcSomeValue ;

  INTO CURSOR csrMyResults

 

Din cauza ca datele din tabela nu sunt sortate in ordinea selectarii inregistrarilor, pentru a satisface clauza WHERE, VFP trebuie mai intai sa se uite la fiecare inregistrare in parte. Inregistrarile pot fi adaugate in orice ordine, astfel incat nu exista nici o logica care sa ii spuna lui VFP daca urmatoarea inregistrare ar putea contine o inregistrare care sa contina criteriul cautat in clauza WHERE. Singura posibilitate fiind astfel de a citi inregistrarea. Intradevar, VFP trebuie sa citeasca toate inregistrarile din tabela deoarece oricare din inregistrari ar putea intruni criteriul clauzei WHERE. Este important de subliniat ca atunci cand avem o interfata VFP, conditia clauzei WHERE este evaluata de catre client (WORKSTATION) - nu de server; „Ce inseamna asta?”, ca VFP sa evalueze o conditie WHERE, fiecare inregistrare trebuie sa treaca prin retea la client. Daca lucrezi cu o tabela cu multe campuri si inregistrari, expedierea acestora prin retea ar lua foarte mult timp.

Factori cheie:

1.     VFP trebuie sa se uite la fiecare inregistrare in parte;

2.     Fiecare inregistrare trebuie expediata prin retea.

Daca Rushmore trebuie sa otimizeze aceasta cerere, acestia sunt doi factori cu care trebuie sa se confrunte. Rushmore nu se uita efectiv la tabela; in schimb se uita la indecsi.

Indecsi

Daca noi ar trebui sa intelegem cum functioneaza Rushmore, este foarte important sa intelegem cum sunt construiti indecsi. Haide sa creem un index pe care Rushmore lar folosi in aceasta cerere:

INDEX ON cSomeField TAG MyTag

 

VFP creaza un index care contine o adresa de referinta la inregistrare si campul de referinta – cSomeField. Daca ar trebui sa ne uitam la index, ar trebui sa vedem cam asa ceva:


 

 


Address Reference

Field Reference

12345

Adams

32145

Brown

...

...

09814

Murphy

14356

Smith

 

Asa dupa cum se vede, indexul este sortat in ordinea campului de referinta. Adresa de referinta se indreapta catre inregistrarea din tabela curenta. Folosind indecsul, VFP stie ca pentru a gasi o inregistrare continand inregistrarea „Murphy”, are nevoie sa se duca la adresa 09814 din tabela. Ar fi de observat ca un index are 2 caracteristici care determina sa fie utilizat in optimizarea unei cereri. In primul rand un index este mic in comparatie cu tabela insasi. Hai sa presupunem ca TabelaMea.DBF contine 50 coloane pentru un total de inregistrari de 500 octeti. Indexul contine un camp de tip intreg (Integer) ca adresa de referinta cu marimea de 4 octeti si un camp de referinta de 20 octeti insumand in total 24 octeti. (Asta presupune ca acel cSomeField de mai sus are o lungime de 20 octeti. Un intrg in VFP are o lungime de 4 octeti) In acest exemplu, indexul are 4,8% din marimea tabelei. In general, mutand capul de citire de la o inregistrare la alta in acest index o sa ia 4,8% din timpul care ne-ar lua ca sa mutam capul de citire de la o inregistrare la alta in tabela noastra. Folosind acest index, VFP are nevoie sa mute capul de citire pe o distanta mult mai mica.

Intradevar indexul sar putea sa fie destul de mic astfel incat sa incapa in memorie. Daca VFP poate sa inglobeze indexul  in memorie, atunci va putea functiona mult mai rapid. Cand lucram cu date pe disk, VFP trebuie sa mute fizic capul de citire pa discul fizic.

Din punct de vedere mecanic evident este mai incet decat daca am citi ceva direct din memorie (cam asa functioneaza lucrurile si la noi ... mai repede scoatem ceva din propria memorie decat atunci cand trebuie sa il citim de undeva si apoi sa il reproducem).

In a doua parte indexul este sortat; asta inseamna ca exista o logica aplicata pe care Rushmore sa o foloseasca atunci cand se uita la inregistrarea urmatoare sa vada daca intruneste criteriul de cautare. Rushmore foloseste algoritmul „B-TREE” in index pentru a determina daca o inregistrare intruneste conditiile where. Rushmore incepe prin a se uita la mijlocul inregistrarii in index. Din cauza ca acel index este sortat, poate pune intrebarea „Este aceasta referinta pentru inregistrare egala, mai mare sau mai mica decat criteriul WHERE?” Daca campul de referinta este mai mic decat criteriul WHERE, atunci Rushmore stie ca urmatoarea inregistrare nu poate intruni criteriul WHERE. Daca referinta catre inregistrare este mai mare decat criteriul WHERE atunci Rushmore stie ca urmatoarea inregistrare ar putea intradevar intruni conditia lui WHERE. Cu alte cuvinte prin citirea in mijlocul inregistrarii a unui index, Rushmore este in stare sa elimine jumatate din inregistrari care nu corespund. Apoi Rushmore face recursiv acelasi lucru cu inregistrarile ramase pana ajunge la criteriul cautat. La a 2-a citire elimina 75% din inregistrari iar la a 3-a 87.5% din inregistrari sunt eliminate, continua sa elimine pana ramane fara inregistrari sau gaseste ce cauta. Daca Rushmore ramane fara inregistrari intoarce .F. insemnand ca nu exista inregistrari potrivite criteriului de cautare. Daca gaseste ce cauta la oricare citire, intoarce .T. insemnand bineinteles ca am gasit ce cautam si astfel se opreste din citire. Intradevar, daca la prima citire, Rushmore gaseste o referinta in index ca o potrivire exacta cu conditia WHERE, intoarce .T. si cautarea se incheie.

Iti vei aduce aminte ca Rushmore are nevoie sa adreseze 2 factori – citirea fiecarei inregistrari si expedierea acestora pe retea. Folosind un index, Rushmore are nevoie numai sa trimita indexul prin retea. Trimite intregu index bineinteles dar din cauza ca acesta este doar 4,8% din tabela avem mai putin de trimis, in concluzie vom avea un transfer mult mai rapid. Folosind algoritmul „B-TREE” Rushmore are nevoie sa citeasca un procent foarte mic din inregistrarile indexate. In improbabilitatea in care ai o tabela cu 130.000.000.000.000.000.000.000.000.000 de inregistrari, Rushmore trebuie sa faca un maxim de doar 100 de citiri pentru a determina daca intruneste sau nu criteriul cautat.

Unde este Rushmore folosit ?

Rushmore este folosit in optimizarea unor serii de comenzi inclusiv Select, Average, Count, Sum, Browse, Copy To, Replace For etc. (Cauta in help pentru lista completa). In marea majoritate a acestor comenzi Rushmore este obusnuit sa aplice un filtru in clauza FOR. In clauza SELECT, el poate fi folosit sa aplice un filtru si deasemenea poate fi folosit intr-o clauza JOIN. Luati seama de urmatoarele 2 cereri:

SELECT Table1.SomeField, Table2.SomeOtherField ;
        FROM Table1 ;
        INNER JOIN Table2 ON Table1.FK = Table2.PK ;
        WHERE Table1.nSomeField = lnSomeField ;
        INTO CURSOR csrResults
 
SELECT Table1.SomeField, Table2.SomeOtherField ;
        FROM Table1, Table2 ;
        WHERE Table1.FK = Table2.PK AND ;
                               Table1.nSomeField = lnSomeField ;
        INTO CURSOR csrResults

 

Ambele cereri intorc acelasi rezultat; dupa cum se poate vedea o clauza JOIN este tratata ca o sortare. Intr-o clauza JOIN Rushmore se duce cu un pas inainte. Rushmore vrea doar sa faca loop prin tabela cea mare odata. Sa luam aminte ca odata ce inregistrarea/setul de inregistrari este gasit, Rushmore se opreste din cautat. Este probabil ca Rushmore sa gaseasca ce cauta intr-o tabela mica mai repede decat intr-o alta mai mare.

 

Optimizarea cererilor

            Devreme ce stim acum ca Rushmore foloseste indecsii ca sa optimizeze cererea, ai nevoie sa te asiguri ca indecsii corespunzatori sunt creati corect. Acest fapt ne duce in mod logic la intrebarea „Ce indecsi poate Rushmore sa foloseasca?”. Ei bine poate sa foloseasca un index atata timp cat indexul nu este filtrat. Putem crea indecsi CDX  structurali/nestructurali sau chiar indecsi simpli IDX atata vreme cat acesti indecsi sunt actualizati si activi, Rushmore ii va folosi. Spre exemplu:

INDEX ON MyTable.SomeField TO "Data\MyIndex.IDX"
INDEX ON SomeField TAG MyStructuralTag
INDEX ON SomeField TAG MyNonStructuralTag "Data\MyCompoundIndex.CDX"
SET INDEX TO "Data\MyIndex.IDX"
SET INDEX TO TAG MyStructuralTag ADDITIVE
SET INDEX TO TAG MyNonStructuralTag OF "Data\MyCompoundIndex.CDX" ADDITIVE

 

Nu numai ca Rushmore va folosi acest tip de index, ci va folosi si indecsi multipli. Nu este nevoie sa creezi un index complex peste mai multe campuri. In loc, poti sa creezi o serie de indecsi simpli peste campuri simple:

*** Instead of
INDEX ON cField1+TRANSFORM(nField2) TAG ComplexTag
*** These are better
INDEX ON cField1 TAG Field1Tag
INDEX ON nField2 TAG Field2Tag

 

O serie de indecsi simpli pot fi folositi de un numar de cereri diferite. Acel index complex poate fi folosit intr-un singur scop. Rushmore NU POATE folosi indecsi filtrati. Daca indexul tau are o clauza FOR, Rushmore o va ignora.

Cat costa adaugarea indecsilor

Foarte usor! Creaza un index peste fiecare camp in tabela ta, nu include o clauza FOR, si astfel cererile vor fi intotdeauna optimizate. Din pacate este si un cost asociat cu crearea indecsilor. Indecsii sunt SORTATI. Asta inseamna, atunci cand adaugi o inregistrare in tabela, sau cand modifici un camp peste care ai un index, trebuie sa actualizezi indexul. Sa ne aducem aminte ca procesul de sortare a inregistrarilor intr-o tabela, este similar cu procesul de actualizare al indecsilor. Cu cat mai multi indecsi ai cu atat va dura mai mult sa ii actualizezi. Adaugarea indecsilor la toate campurile tale este in definitiv o metoda proasta. Adauga asadar numai indecsii de care STII ca ai nevoie. Definirea corespunzatoare a aplicatiei inainte sa incepi sa codezi va asigura ca stii care indecsi sunt aceia de care ai nevoie.

Rushmore si inregistrarile sterse

Cand executi comanda SET DELETED ON, VFP automat adauga echivalentul lui „WHERE NOT DELETED()” sau a lui „FOR NOT DELETED()” ca si clauze la comanda ta sau la cerere. Ca si cu alte conditii de filtrare, Rushmore poate folosi un index ca sa optimizeze acesta conditie „WHERE NOT DELETED()”. Dupa cum sa discutat in orice caz, este un cost asociat cu fiecare index. Daca ai numai cateva inregistrari sterse in tabela ta, optimizarea acestei conditii in mod foarte probabil nu va afecta in mod semnificativ viteza cererii tale. Pe de alta parte, un index peste DELETED() va trebui sa fie actualizat pentru fiecare inregistrare noua si de fiecare data cand vei sterge o inregistrare. Decizia de a adauga un index DELETED()  va trebui luata in functie de fiecare situatie in parte. Daca decizi sa adaugi un index DELETED(), asigurate ca este unul de tip binar:

INDEX ON DELETED() TAG DelTag BINARY

 

Asta cel putin va minimiza marimea indexului. In acest index vei avea probabil o adresa pe 4 octeti si un camp bit – referinta pentru un total de 33 octeti (8 bit = 1 octet[byte])

Optimizare totala sau partiala

Sa ne uitam la SYS(3054) in help. Acesta funcie minunata iti va da un raport de cum si cat de bine poate Rushmore sa iti optimizeze cererea. Dute in fereastra de comenzi si da urmatoarele comenzi folosind SYS(3054):

SYS(3054,12) && Turn on SYS(3054)
SELECT ... INTO CURSOR MyCursor && Run your query
SYS(3054,0) && Turn SYS(3054) back off.

 

Cand sa nu folosesti Rushmore

Pentru marea majoritate Rushmore va face intotdeauna ca cererile tale sa mearga mai repede. Sunt deasemenea si situatii cand Rushmore va incetini tot procesul de optimizare. Sa ne aducem aminte ca Rushmore se uita sa vada care tabela este mai mare ca sa faca un loop prin aceasta o singura data. Intr-o cerere complexa care foloseste sub-cereri si cursoare derivate, Rushmore uneori intelege gresit acest lucru; sfarsesti prin a cicla prin cursorul derivat odata si prin cursorul mare de mai multe ori. Cand te afli in aceasta situatie poti folosi clauza FORCE in declaratia SELECT pentru a te asigura ca sub-cererile sunt evaluate in ordinea in care apar, sau poti sparge cererea intr-un numar de cereri mai mici unde fiecare din aceste cereri este optimizat complet. O cerere finala peste cursoarele rezultante serveste in a aduna rezultatele cursoarelor mici si nu este optimizabila, dar prin aceasta, lucram doar cu un numar restrans de inregistrari deci optimizarea cererii finale nu prea conteaza.

Concluzie

Pentru aceia dintre voi care nu au incercat inca sa foloseasca Rushmore, veti descoperi o mica comoara; aplicatiile voastre vor rula mult mai usor. In "The Lord of the Rings" Gandalf il roaga pe Shadowfax “Aratane ce inseamna viteza adevarata.”, il poti ruga pe Rushmore sa faca la fel.

Spor la optimizat

Textul original apartine dn-lui KEN MURPHY si a fost publicat aici :

http://www.foxite.com/articles/read.aspx?id=79&document=making-Rushmore-rush-more

Tradus de
Badita Alexandru Stefan – RO
J4prog [a] gmail [d] com



Written By: admin
Date Posted: 3/31/2008
Number of Views: 3418


Comments
10/16/2008 10:57:46 AM

da, chiar daca unele lucruri sunt stiute, este indicat sa recitesti, mai ales ca a fost scris de KEN MURPHY

4/30/2008 10:03:06 PM

Este interesant,de "rumegat" si de bagat la cap.
Multumim pentru traducere.

You must be logged in to submit a comment.

Return

  

Copyright 2002-2013 Profox   Terms Of Use  Privacy Statement