MainframeSupports
tip uge 19/2013:

Lige siden DB2's fødsel har vi lært, at tablespacescan er noget, der skal undgås. Men der findes faktisk en række gode undtagelser fra denne regel. Jeg vil dog kun komme ind på et enkelt eksempel i dette tip. Først er det dog vigtig at forstå den grundlæggende forskel på en tablespacescan i forhold til index access.

Når DB2 foretager en tablespacescan, så bliver rækkerne i tabellen læst ind i bufferpool'en af en anden asynkron process end den, der returnerer rækkerne til applikationsprogrammet. Det betyder, at der stort set ikke forekommer ventetid for at få fat i data, hvilket er meget effektivt og brænder en masse CPU af. Denne måde at læse rækker på kaldes sequential prefetch og asynkron I/O. Hvis du er fan af at kigge i PLAN_TABLE, så hedder kolonnen PREFETCH og indholdet er et S.

Når DB2 laver index access, så er det som hovedregel den samme process, der indlæser data og returnerer rækker til applikationsprogrammet. Det betyder, at hvis data ikke allerede er i bufferpool'en, så kommer applikationen til at vente, når der skal indlæses data. Denne måde at læse rækker på kaldes synkron I/O, og jeg har engang hørt synkron I/O omtalt som skildpadde I/O. Hvis kolonnen PREFETCH i PLAN_TABLE er blank, så vil DB2 benytte synkron I/O for at få fat i data.

Eftersom synkron I/O er skidt for svartiden, så kan DB2 en masse tricks for at undgå synkron I/O. Bufferpool'en er selvfølgelig det bedste tiltag, men der findes også andre former for PREFETCH, altså asynkron I/O, som jeg ikke vil komme ind på her. Det er som bekendt DB2 optimizeren, der finder ud af, om det er mest effektivt at benytte den ene eller anden måde at få fat på data, så normalt skal vi ikke bekymre os så meget, om der benyttes tablespacescan eller index access.

Men det kan blive ret interessant, hvis DB2 vælger at scanne et index i stedet for at scanne tablespacet. Det sker for eksempel, hvis alle kolonner i SQL statementet findes i samme index. En SELECT COUNT(*) FROM tabel uden WHERE eller med WHERE på kolonner i samme index er et godt eksempel. Dette er normalt den absolut hurtigste måde at få scannet alle rækker, fordi et index typisk er mindre end tablespace't og DB2 kan benytte sequential prefetch til denne process.

Det kan dog forekomme, at index'et er rigtig dårligt organiseret, og så vil en sequential prefetch via et sådant index performe uhyggeligt ringe. Så er det jo bare om at bede DBA om at køre en REORG. Det sker dog, at nogle tablespaces i al ubemærkethed får vokset sig så store, at DBA vil undlade at køre en REORG, bare fordi optimizeren vil scanne index'et for dit specielle behov. I sådan et tilfælde kan du prøve at fremtvinge en tablespacescan i stedet. Et eksempel:

SELECT COUNT(*)
FROM veryBadlyOrganized
WHERE columnInIndex > 1000
  AND columnNotInIndex <> -1

Det oprindelige statement er uden "AND columnNotInIndex <> -1", men ved at tilføje en betingelse, der altid er sand for en kolonne, der ikke er i noget index, vil du i langt de fleste tilfælde tvinge DB2 til at foretage en tablespacescan, som ikke tager hensyn til om data er dårligt organiseret eller ej. DB2 skal selvfølgelig bruge krudt på at finde ud af, at betingelsen er sand, men det er en lille udgift i forhold til den gevinst, der kan være på svartiden. Når jeg skriver "i langt de fleste tilfælde" skyldes det, at jeg har oplevet tilfælde, hvor optimizeren på trods af ovenstående trick nægtede at slå over i en tablespacescan.

Forrige danske tip        Last tip in english        Tip oversigten