Freitag, April 27, 2012

SQL Server Memory Nutzung pro Datenbank

Ein recht nützliches Script zur Bestimmung der Memory-Nutzung durch einzelne Datenbanken oder einzelne Objekte im SQL Server hat Aaron Bertrand vor einiger Zeit veröffentlicht. Irgendwann sollte ich mal anfangen, nützliche SQL Server Scripts geordnet abzulegen.

NVL2

Jonathan Lewis stellt in seinem Blog die (zum Beispiel für die Definition von FBIs) nützliche NVL2-Funktion vor, deren Aufruf folgendermaßen aussieht:
NVL2(input_value, return_if_not_null, return_if_null)
In einem Kommentar weist Joel Garry allerdings auf einen Bug hin, der NVL2 und coalesce betrifft und der zu falschen Aggregationen in Subqueries führen kann. Das passt zumindest zum Eindruck, dass Oracle mit neuen Syntax-Elementen und Funktionen anfangs ein paar Schwierigkeiten hat (vgl. "ANSI" Join Syntax, CTEs etc.).

Mittwoch, April 25, 2012

Group By Alternativen

Iggy Fernandez hat eine Artikelserie mit dem Titel The Hitchhiker’s Guide to SQL gestartet. Im ersten Teil Lateral derived tables and other alternatives to GROUP BY zeigt er für eine gegebene Query drei Varianten zu GROUP BY:
  • analytische Funktionen
  • skalare Subquery
  • lateral derived table (die ist allerdings not supported)
Er erklärt dabei auch noch mal sehr prägnant, warum es wichtig ist, ein paar Syntaxvarianten zur Verfügung zu haben:
In a perfect world, we could use any of the above variations and it wouldn’t matter because all of them would have the same execution plan for any particular data distribution and hence would always have the same performance. In an imperfect world, we have to choose what works best in our case whether that be GROUP BY or something else. 

Aggregationen und Sortierungen

Tony Hasler weist in seinem Artikel Aggregate Functions and Sorts darauf hin, dass nicht jede aggregierende Funktion tatsächlich eine Sortierung durchführt - worauf auch Jonathan Lewis gelegentlich hingewiesen hat, wozu mir allerdings ein Link fehlt. Um die Sortierung zu vermeiden, merkt sich Oracle für entsprechende Funktionen jeweils den geeignetsten bisher gefundenen Wert und ersetzt ihn durch den aktuellen Wert, wenn dieser geeigneter ist. Eine solche Funktion wäre MAX, bei der im Rahmen des table scans für jeden Wert geprüft wird, ob er größer als das bisher gefundene Maximum ist. Im Ausführungsplan erscheint in einem solchen Fall ein Schritt SORT AGGREGATE, der somit eigentlich keine Sortierung darstellt (was man in v$mystat oder v$sesstat überprüfen kann). Ähnliches gilt für HASH GROUP BY: auch diese Operation erfordert keine Sortierung.

In einem weiteren Artikel FIRST/LAST versus FIRST_VALUE/LAST_VALUE erläutert Tony Hasler das Verhalten der angesprochenen Funktionen und erklärt, dass in der Regel FIRST und LAST die in Hinblick auf Ergebnis und Performance geeigneteren Varianten sind.

Freitag, April 20, 2012

Alert.log View

Neil Chandler zeigt, dass in 11g die View X$DBGALERTEXT zur Verfügung steht, über die man (wenn man es darf) die Inhalte der alert.log-Datei per SQL abfragen kann - ohne den Umweg über eine EXTERNAL TABLE machen zu müssen.

Coalesce Subquery Transformation

Und noch ein Link (der einmal mehr zeigt, wie weit ich meinem Blog Aggregator hinterher hinke ...). Randolf Geist beschreibt in seinem Blog eine ziemlich clevere Transformation, mit der es seit 11.2 möglich ist, mehrere korrelierte Subqueries zusammenzufassen (in seinem Beispiel sogar in der Kombination von EXISTS und NOT EXISTS). Das beschriebene Verfahren wirkt recht kompliziert, so dass Randolfs abschließende Annahme sehr plausibel klingt: "Of course you could also argue that possibly the optimization was particularly aimed at benchmarks like this [=> TPC-H], but then there are certainly similar real-life queries out there that can benefit from such potential workload reductions via query transformations."

Donnerstag, April 19, 2012

Connect By Filtering

Rob van Wijk liefert in seinem Blog eine umfassende Untersuchung der beiden internen Varianten zur Verarbeitung von hierarchischen Queries: CONNECT BY NO FILTERING WITH START-WITH und CONNECT BY WITH FILTERING. Unter anderem geht er dabei auf die Veränderungen im Costing zwischen Version 10 und Version 11 ein.

Who is active in neuer Version

Adam Machanic weist auf Version 11.11 seines nützlichen Who is Active Scripts für den SQL Server hin.

Mittwoch, April 18, 2012

table compression und Updates

Meiner Erinnerung nach habe ich gelegentlich (möglicherweise bei Randolf Geist) gelesen, dass auch die Option COMPRESS FOR ALL OPERATIONS nicht verhindert, dass ein UPDATE eines Satzes in einer komprimierten Tabelle zum Entpacken dieses Satzes führt, so dass dieser sich sogar dann vergrößert, wenn das Netto-Datenvolumen des Satzes kleiner wird (also ein Attribut mit einem kleineren Wert gefüllt wird). Da ich den Link dazu gerade nicht finde, hier ein kleiner Test dazu (mit 11.1.0.7 und einer Blocksize von 16K):

Zunächst das Test-Script:

-- test_compression.sql
-- Test-Tabellen löschen und anlegen
drop table t_nocompress purge;
drop table t_compress_direct purge;
drop table t_compress_oltp purge;

create table t_nocompress
as
select rownum id
     , 'blaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' bla 
  from dual 
connect by level <= 100000;

create table t_compress_direct
as
select *
  from t_nocompress;
  
create table t_compress_oltp
as
select *
  from t_nocompress;

-- unkomprimierte Größe der Segmente
select segment_name, blocks
  from user_segments
 where segment_name like 'T%COMPRESS%';

-- Komprimierung für zwei Tabellen
alter table t_compress_direct move compress;

alter table t_compress_oltp move compress for all operations;

-- komprimierte Größe der Segmente
select segment_name, blocks
  from user_segments
 where segment_name like 'T%COMPRESS%';

-- Auslesen des Komprimierungstyps
select table_name
     , compression
     , compress_for
  from user_tables
 where table_name like 'T%COMPRESS%';

-- Updates für alle Tabellen
update t_nocompress set bla = 'bla';

update t_compress_direct set bla = 'bla';

update t_compress_oltp set bla = 'bla';

-- Prüfung der Größe nach Durchführung des Updates
select segment_name, blocks
  from user_segments
 where segment_name like 'T%COMPRESS%';


Hier die relevanten Ergebnisse der Ausführung:


-- Größe nach der Anlage
SEGMENT_NAME                       BLOCKS
------------------------------ ----------
T_COMPRESS_DIRECT                     768
T_COMPRESS_OLTP                       768
T_NOCOMPRESS                          768

-- Größe nach Komprimierung
SEGMENT_NAME                       BLOCKS
------------------------------ ----------
T_COMPRESS_DIRECT                     256
T_COMPRESS_OLTP                       256
T_NOCOMPRESS                          768

-- Komprimierungstypen
TABLE_NAME                     COMPRESS COMPRESS_FOR
------------------------------ -------- ------------------
T_COMPRESS_DIRECT              ENABLED  DIRECT LOAD ONLY
T_COMPRESS_OLTP                ENABLED  FOR ALL OPERATIONS
T_NOCOMPRESS                   DISABLED

-- Update mit Laufzeiten
100000 Zeilen wurden aktualisiert.

Abgelaufen: 00:00:01.06

100000 Zeilen wurden aktualisiert.

Abgelaufen: 00:00:10.65

100000 Zeilen wurden aktualisiert.

Abgelaufen: 00:01:49.21

-- Größe nach dem Update
SEGMENT_NAME                       BLOCKS
------------------------------ ----------
T_COMPRESS_DIRECT                    1280
T_COMPRESS_OLTP                      1280
T_NOCOMPRESS                          768

Demnach gilt Folgendes:
  • Nach der Anllage sind die Tabellen alle gleich groß (wie zu erwarten ist).
  • Nach dem ALTER TABLE ... MOVE mit den unterschiedlichen COMPRESS-Varianten, reduziert sich die Größe der komprimierten Segmente von 768 auf 256 Blocks.
  • Die Laufzeit der Updates ist für die komprimierten Tabellen deutlich erhöht. Dabei ist die OLTP compression (FOR ALL OPERATIONS) noch einmal sehr viel langsamer als die direct path compression.
  • Im Ergebnis sind die komprimierten Segmente nach dem Update deutlich größer als das nicht komprimierte Segment (1280 zu 768 Blocks)
Anscheinend habe ich mich also korrekt erinnert, dass die OLTP compression noch nicht ganz das tut, was man (oder zumindest ich) von ihr erwarten würde. Sollte ich den Link auf Randolf Geists entsprechenden Hinweis wiederfinden (oder eine andere Quelle), dann liefere ich diese Information noch nach.

Aus Gründen der Vollständigkeit hier noch der Verweis auf Randolf Geists Artikel zu den Einschränkungen der verschiedenen compression Mechanismen, in dem ich den Hinweis auf die beschränkte Wirksamkeit der OLTP compression auf Anhieb allerdings nicht (wieder?)gefunden habe (aber ich habe ihn auch nicht noch einmal gründlich gelesen).

Noch ein paar Nachträge zum Thema:
  • Für die OLTP compression benötigt man die Advanced Compression Option, während die Standard compression Teil der EE ist.
  • Einen ausführlicheren Test inklusive einer Erklärung der technischen Hintergründe der Advanced Compression hat Mark Rittman vor einigen Jahren geliefert. Darin schreibt er: "According to the manuals, my understanding is that it’s not a new “decompression-safe” algorithm that used, what actually happens with advanced compression is this:
    • 1) A table created using the advanced compression feature is initially actually uncompressed
    • 2) New data is loaded using conventional path (and direct path) inserts, updated as neccessary
    • 3) When the table’s PCTFREE limit is reached, the compression algorithm kicks in and compresses the data
    • 4) Inserts and updates then carry on, with updates decompressing the table rows as before
    • 5) When the table’s PCTFREE limit is again reached, compression kicks in again to pack down the rows."
So ganz bringe ich das mit meinem Test aber noch nicht zusammen ...
Nachtrag 02.05.2012: Randolf Geist hat die Links, die mir noch gefehlt hatte, in seinem Kommentar aufgeführt, aber da sie dort nur als Text erscheinen, ergänze ich sie hier noch mal als Links:
Vor allem Teil 2 beschäftigt sich ausführlich mit dem Verhalten der OLTP Compression beim Auftreten von UPDATEs. Das Fazit dort lautet: "Mixing compression with a significant number of updates is a bad idea in general."

Nachtrag 01.02.2013: Erst jetzt (im Anschluss an eine Wiederholung des Tests nach Lektüre der schönen Artikelserie, die Jonathan Lewis dieser Tage bei AllThingsOracle veröffentlicht hat) ist mir klar geworden, dass die extremen Laufzeiten meines Tests mit UPDATE und OLTP-compression (1:49 min) dem von Randolf Geist beschriebenen Bug zu verdanken sind. Wenn man den Test in 11.1.0.7 mit einem MSSM-Tablespace wiederholt, sind die Laufzeiten für die Updates in den Fällen T_COMPRESS_DIRECT und T_COMPRESS_OLTP relativ ähnlich (jeweils ca. 6 sec.; in 11.2 sollte der Bug keine Rolle mehr spielen und dort sehe ich auch für ASSM keine deutlichen Laufzeitunterschiede). OLTP compression wird dadurch nicht sehr viel interessanter, sollte aber zumindest keinen extrem negativen Effekt auf die Laufzeit von Updates haben

Montag, April 16, 2012

Kalender mit SQL erzeugen

Zwei Artikel zum Thema Kalenderberechnung mit SQL:

Freitag, April 13, 2012

All Things Oracle Webinars

Randolf Geist hat dieser Tage auf AllThingsOracle.com ein Webinar mit dem Titel Oracle Cost-Based Optimizer Basics gehalten, das ich leider aus Kindertransportgründen verpasst habe, aber jetzt im Webinar Archiv anschauen konnte, und das eine sehr schöne Zusammenfassung diverser Grundkonzepte der Performanceoptimierung liefert.

Sehenswert sind sicher auch die übrigen Filme der Seite (darunter zwei von Cary Millsap), aber das Problem mit dieser Präsentationsform ist, dass sie doch erschütternd viel Zeit kostet.

Mittwoch, April 11, 2012

Objektdefinitionen für data dictionary views und fixed tables

Charles Hooper untersucht die Herkunft der Angabe PLAN_HASH_VALUE in v$sqlarea und führt bei der Suche nach dem Ursprung dieser Information eine hübsche archäologische Grabung durch diverse Schichten der internen Informationen des RDBMS durch - über dba_synonyms, dba_views, v$fixed_view_definition bis zu den x$-Objekten in der Tiefe.

White Paper zur Statistik-Erzeugung

Maria Colgan verweist im Blog der CBO-Entwickler auf das neue Whitepaper Best Practices for Gathering Optimizer Statistics, aus dem ich hier ein paar Punkte aufliste, die mir wesentlich erscheinen:
  • in der Regel ist der automatische Statistik-Erfassungs-Job, der die DBMS_STATS-Prozedur GATHER_DATABASE_STATS_JOB_PROC verwendet, mit den Default-Einstellungen ausreichend.
  • in relevanten Fällen können die Defaults mit Hilfe von DBMS_STATS.SET_*_PREF überschrieben werden.
  • für den Parameter ESTIMATE_PERCENT wird der Default-Wert AUTO_SAMPLE_SIZE vorgeschlagen. In 10g wurde bei Werten mit extrem ungleicher Verteilung (skew) oft ein zu kleines Sample verwendet, aber in 11g ist dieses Problem behoben (hinsichtlich der Details des Verfahrens wird auf ein weitere White-Paper verwiesen).
  • METHOD_OPT ist der umstrittenste Parameter in den GATHER_*_STATS-Prozeduren und dient der Erzeugung von Histogrammen.
    • In 10g sorgte das einmalige Bind-Peeking dafür, dass der erste Bindewert den Plan bestimmte - und deshalb konnten Histogramme zu einem besonders ungünstigen   (weil hochgradig speziellen) Plan führen. Deshalb wird für 10g empfohlen entweder das Bind-Peeking oder die Histogramm-Erstellung zu deaktivieren (abhängig von der Häufigkeit der Verwendung von Bindevariablen). 
    • In 11g wurde das adaptive cursor sharing eingeführt, das potentiell mehrere Pläne für eine Query mit Bindewerten verfügbar macht. Dadurch sind Histogramme kein Problem mehr.
    • erläutert wird auch der Umgang mit Attribut-Werten die durch die Histogramme als popular  bestimmt werden, wiel sie mehrere Buckets umfassen. In diesem Fall wird die cardinality über die Formel ((anzahl_der buckets_die_den_wert_enthalten/anzahl_aller_buckets) * anzahl_saetze) bestimmt). Für Werte, die der Endpoint nur eines oder keines Buckets sind, wird stattdessen die Formel: (density) * (anzahl_saetze) verwendet (wobei die density on the fly bestimmt wird. Problematisch sind dabei nearly popular values, die nahezu zwei Buckets umfassen, denn für sie gilt ebenfalls die density-basierte Formel. Die einzige Möglichkeit, nearly popular values zu erfassen, ist dynamic sampling.
  • grundsätzlich wird für 11g der default-Wert für method_opt empfohlen. Explizit abgeraten wird von der Verwendung von "for all columns size 254" abgeraten, da dies zur (kostspieligen) Erzeugung überflüssiger Histogramme führt.
  • Pending Statistics sollten verwendet werden, um die Effekte von Änderungen an den Defaults der GATHER%STATS-Prozeduren vor der Produktivsetzung zu überprüfen.
  • die automatische Statistikerfassung kann bei Bedarf angepasst oder auch deaktiviert werden.
  • Für unveränderte Daten sollte keine Statistikerfassung erfolgen.
  • Für ETL-Operationen kann die Statistikerfassung als Teil der Operation definiert werden (wobei auf das implizite Commit der Statistikerfassung zu achten ist).
  • Ein Problem für Tabellen mit stark veränderlichen Daten sind "out-of_range" Werte (oberhalb des Maximal- oder unterhalb des Minimal-Wertes), da der cbo jenseits des bekannten Wertebereichs stark sinkende cardinalities annimmt. Für partitionierte Tabellen kann man die Statistiken einer existierenden Partition über die Prozedur DBMS_STATS.COPY_TABLE_STATS auf eine neue Partition übertragen, wobei die Werte des Partitioning Keys passend adaptiert werden. Für nicht partitionierte Tabellen kann man die Grenzwerte mit Hilfe von DBMS_STATS.SET_COLUMN_STATS manuell setzen.
  • Zur Beschleunigung der Statistikerfassung dient Parellelisierung, die als inter object oder intra object parallelism möglich ist: im ersten Fall werden gleichzeitig Statistiken für mehrere Objekte erzeugt (was allerdings erst seit 11.2.0.2 unterstützt wird), im zweiten Fall erfolgt der Zugriff auf ein Objekt parallel (gesteuert über den DEGREE-Parameter der GATHER%STATS-Prozeduren). Beide Verfahren können kombiniert werden.
  • Für partitionierte Tabellen kann eine inkrementelle Statistikerfassung erfolgen (Details dazu haben zuletzt Randolf Geist und Doug Burns in ihren Blogs geliefert). Interessant ist dabei vor allem die Bestimmung globaler Werte über eine Synopse.
  • Keine (automatische) Statistkerfassung wird in folgenden Fällen empfohlen, für die man man repräsentative Statistiken locken oder dynamic sampling verwenden sollte:
    • Tabellen mit stark veränderlichen Daten
    • Global Temporary Tables (GTT)
    • ETL-Zwischentabellen (die einmalig gefüllt, gelesen und wieder geleert werden)
  • erfasst werden sollten außerdem dictionary statistics (regelmäßig), fixed table statistics und system statistics (jeweils einmalig).

Alles nicht besonders überraschend aber sehr kompakt und plausibel zusammengefasst. Detailprobleme zu den einzelnen Punkten findet man bei den üblichen Verdächtigen (Lewis, Geist, Antognini etc.), auf die ich hier regelmäßig verweise (und verlinke).

Außerdem findet sich bei Frau Colgan noch mal der Hinweis auf das vor kurzem veröffentlichte Whitepaper Understanding Optimizer Statistics.

Extended Statistics und "out-of-range" cardinalities

Randolf Geist zeigt in seinem Artikel Column Groups - Edge Cases, dass die cardinality Schätzungen des cbo für column groups beim Einsatz von extended statistics (oder beim Vorliegen eines entsprechenden Index) völlig unbrauchbar werden, wenn nur ein einziger distinkter Wert für die Spaltenkombination vorliegt:
  • Für eine einzelne Spalte fällt die cardinality Schätzung in einem solchen Fall von "alle Sätze der Tabelle (für die das Attribut not null ist)" auf 1 (also eine aufgerundete 0) - es gibt also kein langsames Absinken der cardinality jenseits von high_value und low_value, wie es im Fall mehrerer distinkter Werte auftritt. Das Verhalten ist somit völlig plausibel.
  • Für eine Spaltenkombination, zu der extended statistics angelegt wurden (oder zu der Index-Statistiken vorliegen wie in Randolfs Test), bleibt die Cardinality-Schätzung in allen Fällen bei "alle Sätze der Tabelle" (wobei NULL values anscheinend noch mal besonders seltsame Effekte hervorrufen - vgl. dazu meinen Kommentar in Randolfs Blog). Und das ist natürlich völlig falsch, wenn nicht die tatsächlich existierende Werte-Kombination vorliegt.
Wahrscheinlich sind Spalten mit einer solchen Werteverteilung nicht unbedingt Kandidaten für extended statistics, aber ein Index für die Spaltenkombination könnte recht unerfreuliche Effekte hervorrufen.

Nachtrag 12.04.2012: auch Jonathan Lewis hat gerade einen Artikel zum Verhalten von extended statistics mit "out-of-range" Prädikaten veröffentlicht. Dort stellt er fest, dass ein Über- oder Unterschreiten der Grenzwerte dazu führt, dass wieder auf die Statistiken der Einzelspalten zugegriffen wird - zumindest dann, wenn mehrere unterschiedliche Werte für die Spalten vorliegen. Maria Colgan erklärt das Verhalten in einem Kommentar zum Artikel:
This behavior is expected and it was a deliberate design decision to prevent over-estimations when one of the values supplied is ‘out of range’. We can’t ignore the ‘out of range’ scenario just because we have a column group. Extended statistics do not contain the min, max values for the column group so we rely on the individual column statistics to check for ‘out of range’ scenarios like yours. When one of the columns is ‘out of range’, we revert back to the column statistics because we know it is going to generate a lower selectivity range and if one of the columns is ‘out of range’ then the number of rows returned will be lower or none at all, as in your example.
Für den von Randolf betrachteten Spezialfall scheint dieses Verhalten aber nicht zu gelten, denn das Verlassen des Werte-Ranges (mit einem Wert) führt ja keine Reduzierung der Cardinality auf den Wert 1 herbei, der ohne Index (oder extended statistics) erscheinen würde.. 

Montag, April 09, 2012

Database Monitoring

Kyle Hailey liefert in seinem Blog eine hübsche Auswahl von SQL Scripts, mit denen man Performance Informationen aus dem AWR auslesen kann - wobei die Analyse vom Allgemeinen zum Besonderen schreitet. Weitere Scripts liefert ein zweiter Artikel mit dem Titel Buffer Busy Waits and Disk file operations I/O.

Für Freunde der Kommandozeile (und Leute ohne Zugriff auf dem OEM) ist das gewiß von Interesse.

Freitag, April 06, 2012

Analyse mit LogMiner

In seinem Artikel Analysing Row Lock Contention with LogMiner zeigt Chris Antognini, wie man den LogMiner benutzen kann, um die Bindewerte älterer Statements (die nicht mehr in V$SQL_BIND_CAPTURE vorliegen) zu ermitteln. Das Vorgehen ist dabei wirklich ausgesprochen simpel: ich habe den LogMiner schon seit Jahren nicht mehr verwendet und hatte in Erinnerung, dass das Setup eher kompliziert ist, aber entweder ist das Verfahren einfacher geworden, oder meine Erinnerung täuscht, oder ich habe den Fall damals komplizierter gemacht, als er war.

commit Varianten

Chris Antognini erläutert die Funktion der Parameter COMMIT_WAIT und COMMIT_LOGGING und zeigt ein Praxisbeispiel, in dem ihr Einsatz sich günstig auswirkt. Grundsätzlich dienen sie dazu, das Verhalten des LGWR und seiner Interaktion mit Serverprozessen zu beeinflussen, und man kann durch ihren Einsatz die Anzahl von system calls reduzieren. Da der Preis dafür allerdings eine mögliche Einschränkung der Durability aus ACID ist, sollte man recht genau überlegen, ob man sich diese Einschränkung leisten kann.

Dienstag, April 03, 2012

auto_sample_size und Histogramme

Randolf Geist hatte vor ein paar Tagen in einem Kommentar hier darauf hingewiesen, dass Oracle bei Verwendung der auto_sample_size für die Erzeugung von Histogrammen nur ein recht kleines Sample von ca. 5500 Sätzen verwendet. Dazu passt der neuste Artikel von Maria Colgan im Blog der cbo Entwickler, in dem sie erklärt, dass die sample_size für Spalten mit Histogrammen irreführend ist:
The sample size shown for these columns is not the sample size used to gather the basic column statistics. AUTO_SAMPLE_SIZE still uses all the rows in the table - the NULL rows to gather the basic column statistics (55,500 rows in this case). The size shown is the sample size used to create the histogram on the column.
Außerdem bestätigt Frau Colgan, dass das sample für die Histogramme:
  • in der Regel ca. 5.500 NON-NULL Werte enthält
  • üblicherweise für den Aufbau aller Histogramme für die Tabelle verwendet wird
  • vergrößert wird, wenn ein Attribut sehr viele NULL values enthält (damit man immer noch auf die magischen 5.500 kommt); in diesem Fall kann es dann auch vorkommen, dass mehrere samples für Fälle mit extrem unterschiedlicher NULL-Häufigkeit erzeugt werden.
Besonders solide scheint das Verfahren tatsächlich nicht zu sein, denn 5.500 halte ich für arg wenig (und sehr willkürlich). Insofern finde ich Randolfs Vorschlag sehr plausibel, die Histogramm-Erzeugung in einen zweiten dbms_stats-Aufruf auszulagern (auch wenn das ein zusätzliches Lesen der Tabelle erforderlich macht).