Ez a dokumentum egy előző változata!
Tartalomjegyzék
Miért ír az adatbázis, hogyha csak olvasunk belőle?
Első olvasatra talán ellentmondásosnak tűnik a cím, de amint e rövid írásból remélhetőleg kiderül, lekérdezések során a PostgreSQL elkerülhetetlenül ír is az adatbázisba. A kiírt adatmennyiség általában elenyésző, de lehet igen jelentős is. Nézzünk meg néhány példát.
Klienseket kiszolgáló folyamatok
Az adatbázisba írásért alapvetően két háttérfolyamat felel. Az egyik a background writer
, amely a memóriában (shared_buffers) módosított adatblokkokat (dirty pages) írogatja vissza a lemezen lévő adatfájlokba. A másik pedig a checkpointer
, amely az összes módosított blokkot kiírja az adatfájlokba.
Kevésbé ismert viszont, hogy a klienseket kiszolgáló folyamatok (client backends) is szoktak írni az adatfájlokba. Ilyen akkor történik például, ha egy lekérdezés során az adatfájlokból felolvasandó adatblokkok már nem férnek el a memóriában (shared buffers), ezért helyet kell csinálni nekik. Ehhez ki kell írni a memóriából az adatfájlokba néhány módosított blokkot (diry pages), hogy azok helyére az újakat lehessen beolvasni.
Tehát csak olvasni szeretnénk az adatbázisból, mégis írásra kényszerítjük a szervert. Ha gyakran történik ilyen, akkor érdemes lehet a shared buffers méretét megnövelni.
Statisztikagyűjtés
A klienseket kiszolgáló folyamatok (client backends) az általuk végzett olvasások végeztével statisztikát küldenek a statistics collector
háttérfolyamatnak, amely összegyűjti, összegzi és tárolja azokat. A statisztikák a pg_stat_*
katalógusokból kérdezhetők le. Ilyen statisztika például egy tábla teljes végigolvasásainak száma (pg_stat_all_tables.seq_scan
), vagy index mentén történő olvasásainak száma (pg_stat_all_tables.idx_scan
).
Tehát a statisztikagyűjtés mindenképpen generál írási művelet, még akkor is, ha csak olvasunk az adatbázisból. Ezt ugyan ki lehet kapcsolni, de nem érdemes, mert a statisztikák hiánya nagyban korlátozná a PostgreSQL képességeit.
Hint bitek
Az adatbázistáblák minden sorához tárolja a rendszer, hogy melyik tranzakció hozta létre, és melyik módosította az adott sort. Minden egyes sorhoz tárolódnak továbbá ún. hint bitek, amelyek azt jelzik, hogy az adott sort létrehozó vagy módosító tranzakció lezárult-e már committal vagy aborttal. Ez az információ ahhoz szükséges, hogy gyorsan lehessen ellenőrizni, hogy a létrejött vagy módosult sorok láthatók-e más tranzakciók számára.
Ha egy táblát módosító tranzakció véget ér, ez a tény bekerül az ún. commit logba. A hint bitek által tárolt információk is a commit logból származnak. A commit logból olvasás viszont extra művelet, ezért az adatbázis az adatblokkokban is tárolja ezeket az információkat, hogy ezáltal a láthatósági ellenőrzést gyorsabban el tudja végezni.
A hint bitek frissítése úgy történik, hogy egy módosított adatblokkokból történő első olvasás során a commit logban lévő információ beíródik az olvasott sorok hint bitjeibe is.
Tehát ezúttal is azzal szembesülünk, hogy noha csak olvasunk az adatbázisból, mégis ír a szerver az adatfájlokba. Igaz, csak néhány bitet, de ezáltal módosulnak az érintett adatblokkok.
Ellenőrzőösszegek
Az esetleges adatkorrupció korai detektálása érdekében érdemes bekapcsolni azt a funkciót, hogy a PostgreSQL számítson ellenőrzőösszeget az egyes adatblokkokra (data checksums). A data checksums opció bekapcsolása viszont azzal is jár, hogy amikor egy checkpoint művelet után egy adatblokk először módosul, akkor beíródik a blokk teljes tartalma a WAL-ba (Write-Ahead Log, avagy tranzakciós napló, amely minden módosítást rögzít).
Ez a naplózás megtörténik akkor is, ha csak a hint bitek változtak meg a blokkban, hiszen a bitek megváltozása miatt is változik a blokk ellenőrző-összege. Ez tehát azt jelenti, hogy minden olyan blokk első olvasása, amely a legutolsó checkpoint óta változott, WAL-fájlba írást fog eredményezni.
Különösen adattárházakból történő lekérdezés esetén jelenthet komolyabb extra I/O-terhelést ez a működés, hiszen noha csak olvassuk az adatbázist, a legutolsó betöltés óta most olvassuk el először a módosult blokkokat, ami tekintélyes számú írási műveletet eredményezhet.
Konklúzió
Remélem, a fenti példákkal sikerült egy kicsit rámutatni arra, hogy a PostgreSQL egy komplex rendszer, és a címben feltett kérdés nem is mindig jelentéktelen. Szívesen látok a kommentben további példákat, amikor az adatbázis ír is, amikor csak olvasunk belőle.