Windows - Alkalmazás teljesítmény optimalizálása hatékony adatlekérdezéssel

Adatbázis optimalizálás 8. rész

Az adatlekérdezések optimalizálásával a hálózati forgalom jelentősen csökkenthető. Át kell vizsgálni alkalmazásainkat, hogy vajon a lekérdezéseink nem igényelnek-e felesleges adatokat. Nagyméretű eredménytáblák kiváltására pedig ott vannak a szerver kurzorok. Ezekkel foglalkozunk mostani cikkünkben.
Az egyik adottsága az SQL nyelvnek, hogy képes az adatokat a szerveren szűrni, így csak a minimálisan szükséges adat tér vissza a klienshez. Ennek a képességnek a használata csökkenti a hálózati forgalmat szerver és kliens között. Ez azt jelenti, hogy a WHERE feltételnek kellőképpen megszorítónak kell lennie, hogy csak azt az adatot kérje le, amelyet az alkalmazás igényel.
Minden esetben sokkal eredményesebb az adatot a kiszolgálón szűrni, mint elküldeni a felhasználónak és alkalmazásból elvégezni ugyanezt. Ez vonatkozik a visszaadott oszlopok számára is. Egy alkalmazás, amely futtat egy SELECT * FROM... utasítást, lekérdez minden oszlopadatot a szerverről, olyanokat is, amelyek valószínűleg éppen nem szükségesek. Ha csak a szükséges oszlopokat kérdezzük le, akkor ezzel megóvjuk a hálózatot a felesleges forgalomtól. Ez egyben azt is jelenti, hogy az alkalmazás válik bonyolultabbá, és ügyelni kell arra, hogy az újonnan felvett mezőket a lekérdezésekbe is mindig fel kell venni a kliensalkalmazásban.
A teljesítmény még attól is függ, hogy hogyan kéri le az alkalmazás az eredményt a szerverről. ODBC-t használó alkalmazásban az utasítás beállításai megelőzik a lekérdezés végrehajtását, így felmérhető, hogyan kéri le az alkalmazás az eredményeket a szerverről. Amikor az utasítási opciókat alapértelmezetten hagyjuk, az SQL 2000 a legeredményesebb módon küldi válaszát.
Az SQL szerver azt feltételezi, hogy az alkalmazásunk azonnal lekéri az összes sort egy alapértelmezett eredményhalmazból. Éppen ezért az alkalmazásunknak a háttérben tárolnia kell minden sort, amit nem használ éppen, de még szüksége lehet rá. Ez a tárolási szükséglet még lényegesebbé teszi számunkra (Transact-SQL-ből) csak a szükséges adatok lekérdezését.
Gazdaságosnak tűnhet lekérdezni egy alapértelmezett eredményhalmazt, és akkor lekérni a szerverről, amikor az alkalmazás felhasználójának szüksége van rá, de ez hibás feltételezés. Azok a sorok, amelyeket még nem kérdeztünk le a szerverről, felemészthetik a kapcsolatot a szerverrel, blokkolják más munkánkat ugyanabban a tranzakcióban. Ezen felül, a le nem kérdezett sorok azt okozhatják, hogy az SQL szervernek zárolás alatt kell tartania a kiszolgálót, gátolva más felhasználókat a frissítéstől. Ez az egybeesés nem mutatkozik problémaként alacsony-fokú tesztelés során, de később láthatóvá válik az alkalmazás üzembe helyezésekor. Ezért kell azonnal átvinni minden sort a szerverről a kliensre.
Néhány alkalmazás nem tudja pufferelni mindazt az adatot, amit lekérdezett a szerverről. Például egy alkalmazás, ami nagy méretű táblát kérdezett le és egy felhasználóra bízza a szelektálás eldöntését, lehet hogy semmi eredményt sem, vagy akár milliós eredményt is visszaadhat. A felhasználók azonban nem szeretnek milliós mennyiségekkel találkozni. Ehelyett a felhasználó sokkal inkább újrafuttatja a lekérdezést, közelebbi szelektálással. Ebben az esetben a milliós sorok átvitele és pufferelése csak a felhasználó idejét és erőforrását pazarolja.
Ezekhez az alkalmazásokhoz az SQL szerver kurzorokat nyújt, amelyek lehetővé teszik egy alkalmazásnak, hogy kis méretű blokkokat vigyen át egy nagyméretű eredménytáblából. Ha a felhasználó látni akar más rekordokat ugyanabból az eredményhalmazból, egy szerver kurzor lehetővé teszi az alkalmazásnak, hogy átvigyen bármely más blokkot az eredményhalmazból. Ezt megadhatja a következő n sor, megelőző n sor, vagy n sor a megfelelő pozíciótól megadásával. Az SQL szerver úgy végzi a munkáját, hogy csak a szükséges módon tölti fel a kért blokkot az átvitelre szánt adatokkal, és eközben nem végez zárolást a kurzorokon.
A kiszolgálói kurzorok lehetővé teszik egy alkalmazásnak, hogy pozícionált frissítést vagy törlést végezzenek anélkül, hogy számolnák az elsődleges kulcsértékeket. Ha a sor adat megváltozik a lekérés ideje alatt, és egy frissítés válik aktuálissá a felhasználótól, akkor az SQL szerver érzékeli a problémát, és megóv egy olyan frissítéstől, ami más által azonnal felülíródna.
Habár nagyon jó szolgálatot tesznek a kurzorok, de használatuk kiadással jár. Ha egy lekérdezés minden eredményét kurzorral visszük át egy alkalmazás számára, akkor az sokkal költségesebb, mint az alapértelmezett eredménytábla. Egy eredménytábla mindig csak egy kérés-válasz párost jelent a szerver és a kliens között, míg a blokkonkénti átvitel minden példány esetében oda-vissza forgalommal jár. Emellett a szerver kurzor felemészti a kiszolgáló erőforrásait, és korlátozások vannak a SELECT utasításban, amelyek csak néhány fajta kurzor esetében használhatók. Például a KEYSET kurzorok csak egyedi indexszel rendelkező táblákra korlátozottak, mialatt a KEYSET és STATIC kurzorok erősen igénybe veszik a szerver átmeneti tárolóját. Így tehát csak akkor használjunk kiszolgálói kurzorokat, amikor az alkalmazásunknak szüksége van erre a tulajdonságra. Ha egy sajátos feladat kér egy egyedi sort elsődleges kulccsal, használjuk az alapértelmezett eredménykészletet. Ha egy másik feladatnak szüksége van egy előre nem látható nagy és módosítható eredménykészletre, használjuk a szerver kurzort, és vigyünk át sorokat ésszerű blokkméretek használatával (például egy oldalnyi sor egyszerre). Emellett ahol lehetséges használjunk gyors, csak előre haladó kurzorokat, automatikus átvitellel. Ezek a kurzorok arra használhatók, hogy kis méretű eredményhalmazokat vigyenek át a kiszolgáló és kliens között egyedüli kérés-válasz segítségével, hasonlóan az alapértelmezett eredményhalmazokhoz.

Adatbázis optimalizálás cikksorozat