Diplomitöö: ASP.NET veebirakenduse optimeermine meediaorganisatsiooni näitel

From ICO wiki
Revision as of 01:24, 8 April 2011 by Mposka (talk | contribs) (→‎Cache)
Jump to navigationJump to search

Siin lehel kirjutan oma diplomitööd. Alustan 19.märtsil probleemi kirjeldusega.

1. Probleemi kirjeldus

1.1 Olemasolev lahendus

Meediaorganisatsiooni näitena kasutatakse Eesti Rahvusringhäälingut, mis tegutseb internetimeedia turul ja haldab enam kui kahtekümment portaali. Need on erineva sisuga, kuid kõikide näol on tegemist põhimõtteliselt uudiste portaalidega. Ainus erand on otse, mis võimaldab kasutajatel vaadata veebist internetiülekandeid. Ettevõtte eesmärgiks on laiendada oma tegevust ja kasutada kõikide portaalide haldamiseks ühtset .NET platvormi. Hetkel kasutavad seda tehnoloogiat pooled portaalid, milledest enamus kasutab .NET4, kuid leidub ka .NET 2 raamistikku kasutavaid rakendusi. Ülejäänud kasutavad PHPd. Hetkel tegeletakse aktiivselt kõikide portaalide ületoomisega .NET 4 raamistikule, mis on ka uute veebirakenduste aluseks.

ASP.NET võimaldab kasutada mitut programmeeriskeelt ühes rakenduses. Antud organisatsioonis kasutatakse nii C# kui ka Visual Basicut. .NET 4 raamistikul asuvate rakenduste näol on tegemist teise põlvkonna portaalidega, mis kasutavad enamus sarnast lahendust. Viimasel puudub aga korralik andmekiht, mille rolli täidab lihtsalt LinqToSql'iga genereeritud andmebaasitabelitest klassid. Kuna hetkel pole veel uut lahendust loodud, peab kasutama olemasolevat.

Andmebaasi platvormiks on SQL Server 2008 R2 Standart väljaanne. Veel mõned kuud tagasi oli kasutusel piiratud võimalustega Express versioon. Veebirakendused töötavad IIS 7.5 peal ja neil on kasutada üks server.

1.2 Probleem

Teise põlvkonna portaalide jaoks loodud lahendus valmis kiirustades, kuna seda oli vaja kiiresti ja programmeerijaid vähe. See tõttu puudus oodatava süsteemi kohta analüüs. Rakenduse loomiseks kasutati võtteid, mis kiirendasid küll selle valmimise kiirust, kuid paratamatult kannatas selle all jõudlus. Enne ametlikku kasutuselevõttu ei olnud võimalik teha süsteemile korraliku jõudlustesti, mis näidanuks tema toimimist suure koormuse korral. Sellel hetkel kasutas seda lahendust üks portaal ja .NET lahendusi oli vähem.

Arendusmeeskonda on lisandunud ka noori programeerijaid, kes ei ole piisavalt teadlikud optimeerimisvõimalustest. ASP.NET lahendusi on küll võimalik pealtnäha kiiresti ja kergelt valmistada, kuid jättes optimaalse ressursikasutuse jälgimise tagataustale, mõjub see rakenduse jõudlusele hävitavalt.

Poole aasta jooksul on lisandunud uusi .NET portaale, milledest enamus kasub eelpool mainitud lahendust. Viimasel ajal on esinenud suurte koormuste korral märgatavaid jõudlusprobleeme. Üheks põhjuseks on kindlasti asjaolu, et kõiki .NET portaalide haldamiseks on kasutada ainult üks server. Ehk kui üks portaal hakkab kasutama väga palju ressursse, siis mõjutab see ka teiste portaalide tööd. See on kindlasti ka üheks turvanõrkuseks - leides ühel leheküljel ressursinõudliku protseduuri, saab seda kasutada kõikide .NET portaalide töö häirimiseks. Halvimal juhul lõpeb see serveri töö seiskumisega. Täiendavad investeeringud riistvarasse on aga välistatud, et kasvatada serveripargi jõudlust. Kuna organisatsioon tegutseb internetimeedia turul ja laieneb sellel pidevalt, siis häired veebirakenduste töös mõjuvad mainele negatiivselt ning on oht kaotada külastajaid.

Lähiajal on lisandumas antud serverile veel kaks täiesti uut portaali. Lisaks peavad hakkama mõned esimese põlvkonna portaalid kasutama hakkama ka "uut mootorit". Kuna juba praegu esineb jõudlusprobleeme, tuleb enne seda parandada olemasolevate portaalide jõudlust. Selle tõttu on vaja olemasolevaid rakendusi optimeerida. Lisaks ei pruugi riistvara soetamine alati olla ka lahendus nagu seda näitavad ka meie digiretsept või valimistulemustesüsteem.

Tegemist on tänapäeval väga aktuaalse probleemiga, mis ei puuduta ainult näitena toodud organisatsiooni. Kasutades optimeerimist ei tööta veebirakendused mitte ainult kiiremini, vaid võib ära hoida ka täiendavaid lisakulutusi riistvara soetamiseks, millega loodetakse nii probleeme lahendada.

Metoodika valik ja võimalikud lahendused

Metoodika

Lahenduse leidmiseks kasutatakse olemasolevate materjalide analüüsi. Lõputöö käigus tutvutakse parimate praktikatega ja valitakse välja neist sobivaimad. Valiku tegemisel hinnatakse sobivust olemasoleva lahendusega. Kui valik on teostatud mõõdetakse praeguse lahenduse töökiirust. Peale seda võetakse kasutusele leitud optimeerimisvõimalused, mida rakendatakse kõigepealt testserveris, millele järgnevad uuesti mõõtmiseid. Võrreldakse saadud tulemusi ja tehakse järeldus. Eelistatud on Microsofti enda poolt soovitatud lahendused.

ASP.NET rakenduse arhitektuur

Optimeerimises üldiselt

Andmebaasi optimeerimine

Öeldakse, et koodi saab alles siis optimeerida, kui midagi töötavat on juba valmis tehtud. Andmebaaside puhul selline väide aga ei kehti, kuna selle hea jõudluse tagamise üheks tähtsamaks nurgakiviks on korralik disain. Kui andmebaas on halvasti loodud, siis on ka selle optimeerimine keeruline ja sellest pole nii palju kasu. Öeldakse, et päev tööd andmebaasi loomise algusfaasus võrdub hiljem sama tulemuse saavutamiseks kolme kuuga. Andmebaasi jõudluse tagamine ei koosne ainult protseduuride korrigeerimisest ja mõnede seadete muutmitest. Enne selle kallale asumist peab analüüsima üldse seda, mis hetkel toimub - kuidas päringuid täidetakse, kui palju see võtab jõudlust, kas indekseeritud on õiged väljad. Ei saa loota, et suvaline indekseerimine parandab andmebaasijõudlust, vastupidi, selle hoolimatu kasutamine mõjub jõudlusele hoopis negatiivselt. Siiski on mõned põhitõed, mis parandavad andmebaasi jõudlust alates selle loomisest.

Andmebaasi loomine

Nagu eelpool mainitud, algab kõik andmebaasiloomisest. Selle protsessi käigus tehtud otsused mõjutavad väga palju andmebaasi edaspidist jõudlust ja ressursikasutust. Alguses valesti tehtud otsused võivad mõjuda halvasti andmebaasi, kui ka seda kasutava rakenduse jõudlusele. Muidugi on kõige tähtsam andmebaasi loogiline ülesehitus, kuid tähelepanu tuleb pöörata ka kindlasti veergude definitsioonidile, mis tuleb määrata korrektselt ja loogiliselt. Ehk kuupäevad peaksid olema kuupäeva tüüpi, mitte nVarchar või char. Teine punkt mida veerutüüpide loomisel tasub alati läbi mõelda on, kui täpseid andmeid meilt nõutakse? Lihtne näide selle kohta on kuupäevad, mida kasutatakse alati väga palju, näiteks registreerimaks uue sissekande loomise kuupäeva. Tihti kasutatakse andmebaasis kuupäeva tüübiks automaatselt DateTime, mis võtab ruumi 8 baiti ja täpsuseks kolm millisekundit. Kuid kui tihti on selline täpsus süsteemides vajalik? Jah, tõesti on kohti kus see on väga kriitiline, kuid kindlasti leidub rohkem situatsioone, kus piisab ka minutitäpsusest.

Näiteks uudisteportaalides on avaldamisajad tihti märgitud ainult kuupäeva ja minutitega. Selle jaoks on ideaalne SmallDateTime, mis on minuti täpsusega ja lisaks võtab poole vähem ruumi(4baiti). Lisaks on andmebaasis olemas nüüd täpselt vajalikus formaadis kuupäev ning me ei pea hakkama seda veebirakenduses andmete väljaküsimusel seda omakorda ümber hakkama vormindama, mis säästab veel rohkem ressurssi.

Kindlasti tuleb säilitada aga ka paindlikus ehk tinyint võtab küll 4 korda vähem ruumi, kui Int, aga see eest saab tabelisse kokku tekitada 256 unikaalset kannet kui tegemist on primaarse võtme väljaga.

Selliseid näiteid leidub kõigi andmetüüpide kohta. Ehk enne tabelite loomist tuleks kindlasti tutvuda konkreetse andmebaasimootori dokumentatsiooniga ja teha selgeks, milliseid võimalusi pakutakse ja mida meil täpselt vaja on. Eelpool mainitiud SmallDateTime on saadaval alates SQL Server 2008 versioonist.

GUID

Huvitav on mainida ka GUIDi kasutamist. Jõudluse poolelt tundub olevate GUID'i kasutamine hullumeelne kui võrrelda seda näiteks INT tüübiga. (Ikkagi 16 baiti vs 4 baiti). Samas GUID'iga kaasneb ka kaks plussi. GUID on alati unikaalne, kui INT on unikaalne ainult ühes tabelis. See tõttu on GUID'i kasutamisega välistatud, et kokku viiakse omavahel tabelite veerud, mis tegelikult ei ole omavahel seotud. Teine pluss on see, et GUID ei saa kunagi otsa.

Üks enim levinud argument, miks mitte GUIDi kasutada primaarse võtmena ja eelistada sellele INTi on asjaolu, et see nullib ära klasteeritud indekseerimisega saavutatava jõudlusevõidu. INT kasvab automaatselt ja seega iga uus sissekanne automaatse primaarse võtme kasvamise puhul on viimane, GUID genereeritakse automaatselt ja see tõttu ei pruugi see viimane olla. Iga uus sissekanne nõuab indeksite uuendamist ja see tõttu põhjustab selle kasutamine lehtede poolitusprobleeme ja indeksite fragmenteerumist. Alates SQL Server 2005 versioonist saab selle vastu kasutada funktsiooni NewsequentialID(), mis tagab, et iga järgmine GUID on eelmisest suurem. Seega ei tule uus sissekanne mitte lehe keskele, vaid läheb alati viimaseks. Samas tuleb tõdeda, et kuna GUID kasutab rohkem mälu, siis tekib juurde indekseerimisel rohkem lehti ja indeksite uuendamine on kulukam kui INT tüübi puhul.

Päringute optimeerimine

Info saamiseks andmebaasist tehakse päringuid, kus vastavalt seatud tingimustele väljastatakse sobivad tulemused. Nende loomisel ja kirjutamisel tuleb jälgida mõningaid lihtsaid võtteid, et vältida üleliigset ressursi kulutamist.

Infot küsides peab alati kirjeldama, mida me tahame tagasi saada. Ehk näiteks SELECT * päring võib olla päris korralik jõudlusetapja, olukorras kus meil on tabelis 10 välja, kuid tahame saada kätte neist ainult kahte. Sellisel juhul on tegemist ebavajaliku ressursiraiskamisega. Lisaks on sellisel juhul ka tabelite indekseerimisest väga vähe kasu, kuna kõigi veergude kättesaaamiseks tuleb teha lisapäringuid.

Päringuid kirjutades peaks küsima alati seda, mida meil vaja on. Võimalusel tuleks vältida eitusi.

Andmebaasi töö sõltub väga palju selle ülesehitustest ja konkreetsetest päringutest. Selle optimeerimiseks peab analüüsima juba loodud ja loomisel olevaid päringuid, et näha kuidas nad käituvad. Selle jaoks on soovitatv kasutada SQL Serveri Query Editor'i kus on võimalik näha päringu täitmist kasutades Execution plan'i. Nii on võimalik kindlaks teha, näiteks kas loodud indekseid kasutatakse, kuidas täpselt toimub päringu täitmine ning kui palju see aega võtab. Selle alusels saab vajadusel muuta indekseerimist või päringuid.

Protseduurid

Andmebaasi jõudluse tagamisel on hea praktika protseduuride kasutamine. Hästi kirjutatud protseduurid on väga kiired. Lisaks on neid lihtne testida ja hallata võrreldes ad hoc päringutega. Samuti on need turvalisemad, kuna kasutavad parameetreid, mis antakse neile kaasa. Ka rakenduseloojatel on lihtsam kutsuda välja protseduur, mille sisendiks antakse parameetrid, kui kirjutada ad hoc päringut, mis avab võimaluse SQL "injenction" rünnakuteks ja seega on ka üheks turvariskiks. Viimaseid on ka raske hallata ja asuvad reaalsetest andmetest kaugel.

Kasutades protseduure on lihtsam jälgida päringute täitmist ja ajakulu, võrreldes tavalise SQL päringuga, mis tuleb väljaspoolt andmebaasi. Kuna kaasa antakse ainult parameetrid, siis on ka edastatav andmemaht väiksem. Samuti asub see ka andmetele lähem.

Kirjutades protseduure on hea praktika lülitada COUNT välja kasutades käsku SET NOCOUNT ON. Viimasega võib sõltuvalt päringu keerukusest võita kuni 17% selle täitmise kiirusest. Vaikimisi on NOCOUNT välja lülitatud ja see tõttu saadab saadab SQL Server kaasa ka alati ridade arvu, mis päringu tulemusena leiti.

Lisaks tuleks vältida kursoreid. Kuigi nad on väga paindlikud ja võimaluste rohked, tuleb nende kasutamisel maksta ränka hinda jõudluses. Kui protseduurides kasutatakse kursoreid, siis nende optimeerimiseks tuleks alustada kursorite eemaldamisest.

Indekseerimine

Indeksid mõjutavad väga palju SQL Serveri jõudlust. Neid tuleb kasutada, et tagada märgatavalt parem jõudlus. Indekseerimine on nagu raamatu sisukord. Kui me soovime leida vajalikku infot, vaatame me sisukorda ning leiame õige koha. Samamoodi käime pidevalt andmebaasist infot otsimas, kus mingi sissekanne asub. Tabel ilma indeksita on nagu raamat sisukorrata - millegi leidmiseks peame lappama läbi terve raamatu, et leida õige koht, mida otsime ja see on kulukas. Kui andmebaasis on tabelid õigesti indekseeritud toimub otsimine nagu raamatu sisukorrast. Rühmitatud indekseerimist tuleb kasutada tabeli primaatvõtmete väljadel, kuna tihti otsime infot just selle võtme järgi. Indekseerimiseks ei sobi väljad, mis on väga mahukad. Näiteks nVarchar(200), kuna see on väga mahukas ja indeksite uuendamine on kulukas protsess.

Indekseerides tabeli veerge kõhutunde järgi, võib see mõjuda jõudlusele hoopis negatiivselt, kuna õigete ridade leidmiseks peab ikkagi tegema lisapäringuid. Selle vätlimiseks tuleks jälgida päringu täitmise plaani, mis näitab, kuidas päringuid läbi viiakse ja kas indeksite tabelit üldse kasutatakse. Nii võib leida kohti, kus tabel on küll indekseeritud, kuid selleks on kasutatud valesid välju ja see tõttu ei saa kasutada kunagi otsimist indeksi järgi ja päringu täitmine võtab kaua aega ning palju ressurssi.

Indeksite loomisel peab arvestama, et indekseerimisega peab maksma natuke hinda ka jõudluses. See tõttu tuleks kaasta indeksitesse minimaalselt välju. Mida rohkem on välju, seda kulukam on indeksite uuesti arvutamine, mis leiab aset iga DDL käsu puhul. Indeksite tabel koosneb lehtedest ja lisades uue sissekande tuleb lehed uuesti luua. Eriti halvasti mõjub see siis, kui uus sissekanne tuleb indeksi lehtede keskele. See eeldab lehtede uuesti loomist ja nende poolitamist. See tõttu tuleb hoolikalt kaaluda, kus kasutada rühmitatud indekseid.

Alates SQL Server 2008 versioonist on võimalik kasutada filtreeritud indekseerimist, mis tähendab, et rühmitamata indeksite loomiseks kasutatakse andmetest ainult mingit osa, mis vastab seatud tingimustele.

Sõnaotsing

SQL Server pakub sõnade otsimiseks lahendust, mille nimeks on FullTextSearch. Seda saab kasutada alates Standard versioonist ning töötab indekseerimise põhimõttel. See lahendus pole küll mõeldud otseselt otsingumootoriks, kuid see on väga hea jõudlusega ning täidab igati oma põhiülesannet, hoides samal ajal ressursikasutuse madalana. Kindlasti tuleks seda eelistada algelisele otsingule, kus kasutatae LIKE operaatorit, mis on aeglane.

Andmebaasi konfigureerimine

Parimate praktikate kohaselt soovitatakse jätta palju variante vaikimisi, kuna nii töötab server kõige optimaalselt ning nende muutmisel võib olla effekt jõudlusele hoopis negatiivne

Startup Manager Kui soovida SQL Serverist pigistada välja viimane, siis võib SQL Server Configuration Manager'i all saab lisada Startup Parameters alla parameetri -x, mis võimaldab maksimaalselt jõudlust. Selllel on aga üks väga suur miinus. Nimelt lülitatakse kõik monitoorimisvõimalused selleks välja ja jõudlusprobleemide jälgimine ja otsimine muutub peaaegu võimatuks.

Ühenduste automaatne sulgemine(Auto Close) Ühenduste automaatset sulgemist saab kontrollida graafilisel Management Studiost ja käsuga: ALTER DATABASE <ANDBEMAASINIMI> SET auto_close ON/OFF. Kui Auto Close on lubatud, siis peale kõigi aktiivste ühenduste sulgumist andmebaasiga vabastab SQL server kõik selle andmebaasi ressursid, mis teoreetiliselt peaks andma rohkem ressursse mõnele teisele andmebaasile. Pealtnäha võib see mõjuda jõudlusele hästi, kuid tegelikult on see kindel viis kuidas hävitada SQL Serveri jõudlus, kuna paljud rakendused sulgevad ja avavad ühendusi korduvalt. Uute ühenduste puhul tuleb aga andmebaas uuesti laadida, kompileerida protseduurid ja arvutada päringu läbiviimise plaanid. See tõttu peaks see ühenduste automaatne sulgemine olema keelatud, mis on ka kõigis SQL Serveri versioonides vaikimis, välja arvatud SQL Express.

Ühenduste automaatne sulgemine peaks olema lubatud ainult siis, kui tegemist on andmebaasiga, mis hoiab endas arhiivi ja kasutatakse väga vähe.

Automaatne kahanemine (Auto Shrink) Samuti peaks olema keelatud käsuga ALTER DATABASE <Andmebaasinimi> SET AUTOSHRINK OFF; Kui andmebaasil on üle 25% vaba ruumi, siis see põhjustab andmete ja logifailide kahandamise operatsiooni. Failide kahandamine on väga kulukas protsess.

ASP.NET tehnoloogiast tulenevad optimeerimisvõimalused

Web.config

web.config failis asub informatsioon veebirakenduse seadistuse kohta nagu näiteks andmebaasiga ühenduse loomiseks vajalikud parameetrid või kuidas toimub rakenduse kompileerimine. ASP.NET kasutab selles failis olevat infot, et luua rakenduse ülesehitus. Kui testkonnas testida rakendust, peaks olema kindlasti web.configis olema parameeter "compilation debug" väärtus true. Vigade esinemise korral on sel juhul neid lihtne leida. Veebirakenduse tõstmisel live serverisse tõstmisel peab jälgima, et antud parameeter oleks false. Vastasel juhul kompileeritakse pidevalt veebirakendust iga lehe laadimise ajal uuesti ja see omakorda kasvatab protsessori ja mälu kasutust. Kõige kindlam viis selle vältimiseks on muuta serveris asuvat machine.config faili ja lisada parameeter deployment retail="true". Nii on kindel, et ükski veebiaplikatsioon ei kasuta antud serveris debug mode'i. Ainukeseks miinuseks selle puhul on, et vea ilmnemisel ei kuvata vea täpset asukohta(Rea numbrit ja veakirjeldust).

Lisaks tasub web.config faili lisada ka outputcache'imise erinevad profiilid, millega saab määrata kui kaua lehte serveri mälus hoitakse. Kui lehele on tulemas suur koormus või midagi muud, saab ühest kohast muuta kõikide cahche'ide kehtivuse pikkust, mis kasutavad konkreetset profiili.

Viewstate

Viewstate'i kasutatakse, et hoida väärtusi, mis postitatakse tagasi lehele endale. Nii on võimalik antud väärtuseid kasutada ka peale kliendi-serveri vahelist suhtlust, kui selleks kasutatakse postbacki, mille kutsub välja näiteks nupulevajutus. Kõiki neid väärtusi hoitakse lehel peitud väljas, mis kannab nime _VIEWSTATE. Hoides selles aga suurel hulgal andmeid, kasvab see tõttu ka lehe suurus ning selle laadimise aeg. Arvestama peab ka sellega, et lehe renderdamisel tuleb viewstate'i serialiseerida ja deseriaaliseerida. Lisaks võib see vähendada Garbage Collection'i efektiivsust. Sellepärast tuleb selle kasutamisega olla ettevaatlik ja eemaldada kohtadest, kus seda vaja ei lähe, kuna see mõjub jõudlusele halvasti. Näiteks genereerivad kõige rohkem viewstate'i ASP.net enda tööriistad Listview ja Gridview. Lehel sisalduva viewstate'i hulga analüüsimiseks on hea tööriist ASP.NET ViewState Helper, mis töötab Firefoxi ja Internet Exploreriga. Selle abil on võimalik näha, kui suure osa moodustab kogu lehe suurusest viewstate. Vaikimisi on see ASP.NET'is igal pool sisselülitatud. Soovitatav on see välja lülitada kohtades, kus ei toimu serveri poolseid kontrolle ja ei kasutata postbacke. Seda saab välja lülitada erinevatel tasemetel: serveris(machinge.config), veebirakenduses(web.config), lehel <%@ Page EnableViewState="false" %> kui ka ASP.NET tööriistades endas(EnableViewstate=false).

Postback'i kontrollimine Kui lehel on lubatud viewstate ja toimub postback, tuleb seda kontrollida kasutades IsPostBack() meetodit, mis teeb kindlaks, kas tegemit on postbackiga. Kui on, siis pole mõtet enam uuesti andmeid pärida, vaid kasutada juba olemasolevaid.

ASP.NET enda tööriistad

Enimlevinud tööriistad, mida tihti kasutatakse on GridView, Listview ja Repeater. Neid kõiki on mugav kasutada, erinevate ????? loomiseks. Esimesed kaks neist genereerivad aga suurel hulgal viewstate'i. Kui eesmärgiks on tavalise listi loomine(näiteks uudiste), siis peab kindlasti selle keelama. Nende tööriistade kasutamisels tuleks pöörata tähelepanu ka sellele, kuidas saada väärtuseid allikast kätte. Väga levinud viis on selleks kasutada süntaksi: <%#Eval("fieldname")%>, mis defineerib välja nime, kuskohast väärtust päritakse. Seda on lihtne kasutada, olenemata sellest, kas on tegemist objektide listiga või DataTable'iga. Tegelikult tuleb sellise süntaksi puhul maksta hinda jõudluses, kuna küsitava välja tüüp ei ole tegelikult defineeritud ja selle kindlaks tegemiseks kasutatakse peegeldust.(reflection) Nii tuleb 10 rea väärtustamiseks teha Eval operatsiooni tegelikult 20 korda, kuna esialgu pole teada, millist tüüpi andmetega tegu on. Parem variant on viidata kohe klassile, kust otsitav väli pärit on nagu näiteks: <%#((MyClass)Container.DataItem).field1%> või DataTable kasutamise puhul <%#((DataRowView)Container.DataItem).field1%>. Ainuüksi 10 rea lisamisel võib kiirusevahe olla enam kui kümne kordne, viimase variandi kasuks. Selle kasutamisel peame arvestaam, et muutes näiteks klassinime, peame muutma seda ka kohas, kus pärime välja väärtuseid.

ASP.NET genereerib automaatselt html'i kõikidele väljadele ID'd, kui need on ka koodis määratud. Näiteks kui meil on ASP.NET'i pildikomponent parameetritega <asp:Image ID="imgMainItem" runat="server"/>, siis sõltuvalt selle sügavusest lehtede hierarhias võib peale kompileerimist htmli vaadates näha, et antud välja ID'ks on saanud hoopis id="ctl00_leftColumn_ctl00_Vaikekategooria3_imgMainItem". Nagu näha on tegemist üpriski mahuka nimetusega. Kui aga tegelikkuses seda id'd meil vaja ei lähe, siis peaks jätma selle määramata. Mahuka esilehe puhul on sellega võimalik hoida päris palju ruumi kokku. Kui siiski vajame ID'd, võime selle peale kasutamist ära nullida. Eht näiteks: imgMainItem.Src="pilt.jpg"; imgMainItem.ID=null;

Cache

Cache'imine on üks lihtsamaid viise, kuidas muuta veebirakenduse ja ka andmebaasi tööd kiiremaks, hoides enimkasutatavaid andmeid mälus. Mälust andmete kättesaamine on lihtsam ja odavam, kui selle pärimine pidevalt andmebaasist. ASP.NET on kasutusel Cache API hoidmaks enimkasutatavaid andmeid ja OutputCache, mis hoiab mälus terveid lehti. Selle kasutamisel peab arvestama, et vajalike andmete/lehtede hoiustamiseks kasutatake serveri mälu. See tõttu peab ka cache'imise puhul läbi mõtlema, mida on vaja cache'ida ja mida mitte, eriti siis kui serveri mälu on vähe. Head kandidaadid cahce'imiseks on lehed/andmed, mida kasutatakse kõige rohkem või mille kätte saamine on väga kulukas protsess. Enamasti on headeks kandidaatiteks näiteks esileht ja mõned suuremad listid ning otsingutulemused. Cache API'l ja OutPutCachil cachimine toimub põhimõtteliselt sarnaselt. Mõlemale on võimalik ette anda aeg, kui kaua aega neid serveri mälus hoitakse. Lisaks saab mõlema puhul kasutada SqlCacheDepencyt, mis võimaldab jälgida, kas andmebaasitabelites on muudatusi toimunud. Cache kustutakse sellel juhul, siis kui jälgitavas tabelis toimub muudatus. Selle toimimiseks peab andmebaasis lubaba tabelitel SqlCacheDependency ja ka web.config failis kajastama seda. On võimalus ka kasutada mitme tabeli jälgmist. Soovitatav on kasutada tabeleid, kus tihti muudatusi ei toimu, vastasel juhul on Cache pidevalt tühi ja andmete saamiseks tuleb siiski päringuid teha. Sellisel juhul tuleks anda ajaline intervall, mille tagant andmeid uuendatakse. http://msdn.microsoft.com/en-us/library/system.web.caching.sqlcachedependency.aspx

OutPutCache

OutPutCache'i puhul salvestatakse terve leht serveri mällu. Seda saab kasutada nii UserControl'ide puhul kui ka tervete .aspx lehtede puhul. Defineeritakse lehe ülaosas kujul: <%@ OutputCache Duration="#ofseconds" Location="Any | Client | Downstream | Server | None | ServerAndClient " Shared="True | False" VaryByControl="controlname" VaryByCustom="browser | customstring" VaryByHeader="headers" VaryByParam="parametername" VaryByContentEncoding="encodings" CacheProfile="cache profile name | " NoStore="true | false" SqlDependency="database/table name pair | CommandNotification" ProviderName="Provider Name"  %> http://msdn.microsoft.com/en-us/library/hdxfb6cy.aspx

Kõige enimkasutatavad ja olulisemad neist on : Duration -määrab kestvuse kui kaua serveri mälus lehte hoitakse, VarByParam - querystringid, mille puhul cache'itakse, SqlDependency - defineeritakse andmebaasi /tabeli paarid, mille muutumise korral leht serveri mälust kustutakse. Shared - saab kasutada ainult usercontrollide puhul. Paneb paika, kas cache'itakse see kõikidel lehtedel. Üks huvitav muutujua on veel VarByCustom. Selle kasutamiseks tuleb Global.asax'is override'ida GetVarByCstomString meetod: public override string GetVarByCustomString(HttpContext context, string custom){ if(custom=="weekday"){ return .... }else{ return bas.GetVarbyCustomString(context, custom) } } ASP.NET ei hooli stringi tegelikust sisust, vaid kontrollib seda, kas vastav stringi väärtusega leht on juba serveri mällu salvestatud. Kui on, siis serveeritakse leht serveri mälust, vastasel juhul lisatakse uus lehe koopia mällu. Seda saab kasutada näiteks feedi cache'imiseks, mille loomine oli väga kulukas ja mida tohivad näha ainult teatud IP aadressitega kliendid. Tavalise OutPutCache'i lisamine oli välistatud, kuna kui võõra IP'ga klient tuli, nägi ta ikkagi feedi, kuna tulemused olid Cache'iitud. Teine variant oli, et võõra IP'ga klient tuleb siis kui cache on tühjendatud. Sellel juhul aga läheb terve feed katki, kuna outputcache'is on leht, mis on tühi. Lahenduseks oli override'ida GetVarByCustomString meetod ja cache'ida ära IP põhiselt.