Database Tuning & Administration
←
→
Transkription von Seiteninhalten
Wenn Ihr Browser die Seite nicht korrekt rendert, bitte, lesen Sie den Inhalt der Seite unten
Universität Konstanz SS 2007 Fachbereich Informatik und Informationswissenschaft Hausarbeit Database Tuning & Administration Seminar: Seminar: Database Tuning & Administration Dozent: Prof. Dr. Marc H. Scholl Assistant Christian Gruen Vorgelegt von: Ketevan Karbelashvili & Irina Andrei 1
Inhaltsverzeichnis 1 Einführung............................................................................................................................... 3 1.1 Oracle Datenbank Enterprise Edition (EE) ...................................................................... 3 1.2 Oracle Datenbank Express Edition (XE) ......................................................................... 3 1.3 TPC-H .............................................................................................................................. 4 1.4 CYGWIN ......................................................................................................................... 4 1.5 Zeitmessung ..................................................................................................................... 5 2 DBMS Architektur .................................................................................................................. 5 2.1 Interne Ebene.................................................................................................................... 5 2.1.1 System Global Area (SGA)....................................................................................... 6 2.1.2 Program Global Area (PGA)..................................................................................... 8 2.1.3 Optimierung unter Oracle 10g EE............................................................................. 9 2.1.4 Optimierung unter Oracle 10g XE .......................................................................... 10 2.2 Konzeptuelle Ebene........................................................................................................ 12 2.2.1 Denormalisierung .................................................................................................... 13 2.2.2 Integration von Views in Anfragen......................................................................... 14 2.2.3 Partitionierung von Tabellen................................................................................... 17 2.2.4 Clustering ................................................................................................................ 22 2.2.5 Optimale Indexierung von Tabellen........................................................................ 35 3 Oracle Tuning Pack............................................................................................................... 46 3.1 Oracle Tuning Pack über PL/SQL ................................................................................. 47 3.2 Oracle Tuning Pack über Web Benutzeroberfläche ....................................................... 49 3.3 FAZIT............................................................................................................................. 51 4 FAZIT der Optimierung ........................................................................................................ 51 4.1 Oracle Tuning Tips......................................................................................................... 52 Literaturverzeichnis.................................................................................................................. 53 2
1 Einführung „Tuning ist die Summe aller Maßnahmen, welche die Optimierung der Antwortzeiten und die Verbesserung der Skalierbarkeit zum Ziele haben“. (Dr. Günter Unbescheid) Heutzutage spielen Datenbanken eine immer wichtigere Rolle in den verschiedensten Bereichen der Industrie. Um diese Datenbanken und somit die Datenbestände sinnvoll auswerten zu können, werden die verschiedensten Datenbank-Systeme und -Werkzeuge angeboten. Um die Leistung der unterschiedlichen Systeme in Bezug auf bestimmte Eigenschaften wie Anfragezeit und Performanz miteinander vergleichen zu können, müssen die zu vergleichenden DB- Systeme standardisierten Tests unterzogen werden, was auch Benchmarking genannt wird. Das Transaction Performance Processing Council (kurz. TPC) hat es sich zur Aufgabe gemacht verschiedene Benchmarks zur Verfügung zu stellen, um die Leistungen der unterschiedlichen DB- Systeme zu vergleichen. 1 Je nach Verwendungszweck werden die Benchmark-Datenbanken von TCP in 3 verschiedenen Typen unterteilt: • TPC-App - simuliert Daten die eines Web-Projektes im 24x7 Modus • TPC-C - simuliert eine OLTP Datenbank, vorzugsweise im ERP-Bereich • TPC-H - simuliert eine dispositive Datenbank im Bereich Data Warehouse. 2 Der Benchmark auf den sich diese Arbeit bezieht ist der TPC BenchmarkH (TPC-H). Der TPC-H Benchmark wurde in dieser Arbeit unter Oracle 10g Express Edition (XE) und Oracle 10g Enterprise Edition (EE) eingesetzt. Dabei als Betriebssystem wurde Windows XP benutzt. 1.1 Oracle Datenbank Enterprise Edition (EE) Oracle 10g EE bietet effizientes, zuverlässiges und sicheres Datenmanagement unternehmenskritischen Anwendungen wie beispielsweise umfangreiche On-Line Transaktions Prozessing (OLTP) Umgebungen. Die Oracle Datenbank Enterprise Edition beinhaltet Werkzeuge und Funktionen, um selbst höchste Ansprüche an Verfügbarkeit und Skalierbarkeit problemlos zu erfüllen. Die Enterprise Edition unterstützt alle Rechnergrößen und hat keine Limitierung der CPU Kapazität. 1.2 Oracle Datenbank Express Edition (XE) Oracle 10g XE ist die neueste Einstiegsvariante in die Oracle Welt. Die Oracle XE ist vollständig kostenfrei und kann nach belieben entwickelt, eingesetzt und verteilt werden. Oracle XE mit der weltweit führenden Datenbanktechnologie kann auf Rechnern aller Größen und ohne Beschränkung der CPUs eingesetzt werden, ist jedoch beschränkt auf maximal 4 GB Nutzerdaten und die Nutzung von maximal 1 GB Speicher sowie der Nutzung von lediglich 1 CPUs auf dem Hostserver. 3 1 [5] Realisierung des TPC-H-Schemas auf einem Oracle-Datenbanksystem 2 [6] TPC-H Schema erstellen 3 [7] Datenbank Lizenzen 3
1.3 TPC-H Nach dem Download der Dateien TPCH unter http://www.tpc.org/tpch/ mussten ”Database Generator“ und ”Query Generator“ erstellt werden. Dafür musste erst das Makefile.suite angepasst werden: • Makefile wurde erstellt. • vier Parameter zur Anpassung an die vorhandene Datenbank wurden in Makefile eingestellt: CC = gcc DATABASE= SQLSERVER MACHINE = LINUX WORKLOAD = TPCH Kompiliert wurde mit Hilfe des Programs CYGWIN 1.4 CYGWIN nach dem beide Dateien QGEN.exe und DBGEN.exe erstellt wurden, mussten die Daten erstellt werden und anschließend in das Datenbank importieren werden, dafür wurde auch mit SYGWIN gearbeitet. Cygwin ist eine Emulation der Linux-API. Mit Cygwin lassen sich Programme, die üblicherweise unter POSIX-Systemen wie GNU/Linux, BSD und Unix laufen, auf Microsoft Windows portieren. Folgende Befehle wurden unter SYGWIN ausgeführt, um 1 GB Zufallsdaten und 22 Zufallsqueries zu erstellen: • run dbgen -v -s 1 (generierte 1 GB an Zufallsdaten) • run qgen -N -d 1 > 1_gen.sql (generierte 22 Zufallsqueries) Als nächstes mussten die Erstellten Daten in die Datenbank importiert werden: • Erst mussten die Tabellen erstellt wurden: Type "sqlplus Benutzer/Password" und @ /dss.ddl • Als nächstes mussten die Tabellen mit den Daten gefüllt werden. Dafür musste für jede Tabelle ein *.ctl File erstellt werden. Z.B. für CUSTOMER Tabelle: load data INFILE 'customer.tbl' INTO TABLE CUSTOMER FIELDS TERMINATED BY '|' (C_CUSTKEY, C_NAME, C_ADDRESS, C_NATIONKEY, C_PHONE, C_ACCTBAL, C_MKTSEGMENT, C_COMMENT) • Anschließend wurden die Daten mit dem Oracle SQL*Loader in die Datenbank eingespielt. sqlldr Benutzer/Password control = customer.ctl 4
1.5 Zeitmessung Für die Zeitmessung der Aufgaben wurden sie mehrmals ausgeführt, und die Ergebnisse in einer Excel Datei gespeichert. Die Mittelwerten wurden weiter betrachten um Vergleiche zu machen und Prozentsätze zu berechnen. 2 DBMS Architektur Ein DBMS ist in drei Ebenen unterteilt: • die interne Ebene (physische Sicht) • die konzeptuelle Ebene (logische Sicht) • die externe Ebene (benutzerspezifische Sicht) 4 2.1 Interne Ebene Die interne Ebene kümmert sich um die physische Abspeicherung der Daten. Weiter ist die Verwaltung des Pufferspeichers auf dieser Ebene angesiedelt. 4 [8] Datenbanksystem 5
Eine wichtige Aufgabe der internen Ebene ist die Sicherung der Datenkonsistenz zwischen Datenspeicher und Memory (Synchronisation). Sollten sich Datenobjekte ändern, so verwaltet die interne Ebene, wie die Speicherseiten verändert werden müssen. Ausserdem hat die interne Ebene die Aufgabe, die Indizes zu verwalten. 5 2.1.1 System Global Area (SGA) Zwei Faktoren bestimmen die Qualität eines Puffers. Zum einen die logischen Zugriffe (Logical Read), unter denen man alle Zugriffe auf einen Block versteht, und zum anderen die physikalischen Zugriffe, die alle Zugriffe auf einen Block auf der Festplatte ausdrücken (Physical Read). Aus diesen Faktoren ergibt sich die Qualität des Puffers über folgende Formel: Qualität (Hitratio) = Anzahl der Treffer/Anzahl der Abfragen × 100% Die Datenbankpuffer der Oracle-Datenbank befinden sich in der System Global Area (SGA). SGA fungiert als Hauptkommunikationsplattform für den schnellen Datenaustausch zwischen Oracle- Prozessen. 6 Der globale Systembereich (SGA) von Oracle ist der Speicherbereich, der beim Systemstart von Oracle zugeordnet wird und Speicherstrukturen zum Speichern von Daten und Steuerungsinformationen enthält. 7 Die wichtigsten Puffer in der SGA der Oracle-Datenbank sind zur Übersicht in der folgenden Tabelle dargestellt: 8 5 [8] Datenbanksystem 6 [9] Oracle-Datenbankadministration für SAP 7 [10] Oracle Konfigurationsoptionen 8 [9] Oracle-Datenbankadministration für SAP 6
Die für die folgenden Parameter definierten Werte wirken sich am stärksten auf die SGA-Größe aus: • LARGE_POOL_SIZE • SHARED_POOL_SIZE • DB_CACHE_SIZE 9 • LOG_BUFFER Man kann wegen Performance Engpässen oder bestimmten Oracle Fehlern (z.B. ORA-04135) die Größe dieser Speicherbereiche dynamisch anpassen. Allerdings die Maximale Grösse der SGA (SGA_MAX_SIZE) lässt sich nicht dynamisch ändern, sondern erfordert ein Reboot der Datenbank. 10 2.1.1.1 Database Buffer Cache „The buffer cache holds copies of data blocks so as they can be accessed quicker by oracle than by reading them off disk.“11 Der Speicher wird über einen LRU-Algorithmus (Least Recently Used) verwaltet. Dadurch werden die Blöcke, die am häufigsten gebraucht werden, immer im Speicher gehalten. Der Database Buffer Cache besteht aus den Sub-Caches wie z.B: • DB_KEEP_CACHE_SIZE ist die Größe des Keep Buffer Cache, welcher Blöcke zum Wiederverwenden speichert. • DB_BLOCK_SIZE bestimmt die Primary Block Size. 12 Default Cache Parameter Einstellungen unter ORACLE 10g EE nach Installierung. Die Parameter aus vorhergehender Tabelle können dynamisch geändert werden, das heißt, ein Neustart der Instanz ist nicht erforderlich. 9 [10] Oracle Konfigurationsoptionen 10 [11] Oracle-Server Bestandteile 11 [12] http://www.adp-gmbh.ch/ora/concepts/cache.html 12 [11] Oracle-Server Bestandteile 7
Shared Pool Der Shared Pool speichert die zuletzt verwendeten SQL Statements und Datendefinitionen. SHARED_POOL_SIZE definiert die Größe des Buffers für shared SQL und PL/SQL (Default 16MB bei 32bit bzw. 64MB bei 64 bit). Java Pool Der Java Pool ist optional und wird für Java verwendet. JAVA_POOL_SIZE definiert die Größe des Java Pools (Default 24MB). Large Pool Der Large Pool ist ein optionaler Speicherbereich im SGA. Er wird für Session Memory verwendet bei Shared Server. Weitere Anwendungen sind I/O, Backup/Restore (RMAN), ... Der Large Pool verwendet kein LRU-Algorithmus. LARGE_POOL_SIZE definiert die Größe des Large Pools (Default 0). LARGE_POOL_SIZE ist nicht dynamisch. Streams Pool Der Streams Pool ist neu in Oracle 10g und wird von Buffered Queues benutzt. Buffered Queues wurden in Zusammenhang mit Oracle Streams eingeführt. Die Größe des Streams Pool wird mit dem Parameter STREAMS_POOL_SIZE festgelegt. Der Streams Pool ist Bestandteil der SGA, er muss also in den Wert für SGA_MAX_SIZE eingerechnet werden. Redo Log Buffer Der Redo Log Buffer ist ein Circular Buffer und speichert Änderungen von Datenblöcken. LOG_BUFFER definiert die Größe des Redo Log Buffer in Bytes. 2.1.2 Program Global Area (PGA) Der Listener-Prozess registriert Verbindungswünsche von User-Prozessen. Server Prozesse werden dann auf Verlangen von User-Prozessen gestartet und führen stellvertretend dessen SQL-Statements aus. Wenn ein Server-Prozess startet, wird ihm Arbeitsspeicher zugewiesen. Diesen nennt man Program Global Area (PGA). Nach dem Beenden des User-Prozesses wird der PGA wieder freigegeben. Die PGA eines Prozesses enthält nur die Daten und Informationen, die von dieser benötigt oder bearbeitet werden. Besonders bei speicherintensiven Sortier- und Hash-Operationen kommt der Größe der PGA eine entscheidende Bedeutung zu. Die Konfiguration der PGA hat sich allerdings seit dem Release Oracle 9i deutlich vereinfacht. Ähnlich wie beim ASMM für die SGA passt Oracle die PGA-Bereiche aller Serverprozesse automatisch an. Der PGA besteht aus diesen Komponenten: • Private SQL Area • Persistent Area 8
• Run-Time Area • Session Memory • SQL Work Areas 13 2.1.3 Optimierung unter Oracle 10g EE Getestet wurde Datenbank 10g EE mit Primär-, Fremdschlüsseln mit Standart SGA, PGA Einstellungen gegen Datenbank mit Primär-, Fremdschlüsseln und • SGA=700 • PGA=397 Gegen Standart eingestellten Werten nach der Installation • SGA=432 • PGA=143 Diese Abbildungen zeigen, dass den einzelnen Bestandteilen der SGA die Größen automatisch zugewiesen werden, so braucht der Datenbankadministrator nicht ihnen die Werte manuell zuzuweisen. 13 [11] Oracle-Server Bestandteile 9
Die Tests zeigten, dass obwohl die Laufzeit fast allen Queries nach der Optimierung mit SGA und PGA sich verbessert hat, war diese Verbesserung nicht sehr gut und daher könnte man auch weiter mit den alten Größen die durch das System vergeben wurden arbeiten. 2.1.4 Optimierung unter Oracle 10g XE 2.1.4.1 Buffer Cache Sub-Caches Im unterschied zu Oracle 10g EE wurde es bei Oracle 10g XE auch versucht die Größen den einzelnen Database Buffer Cache Sub-Caches manuell zu vergeben. Default Cache Parameter Einstellungen unter ORACLE 10g XE nach Installierung Getestet wurde • Datenbank mit Primär-, Fremdschlüsseln und standard KEEP_CACHE_SIZE Einstellungen gegen Datenbank mit Primär-, Fremdschlüsseln und KEEP_CACHE_SIZE =25M. alter system set DB_KEEP_CACHE_SIZE = 25M; Die folgende Abbildung zeigt, dass die Ergebnisse der DB_KEEP_CACHE_SIZE = 25M schlechter als die Ergebnisse der Standart DB_KEEP_CACHE_SIZE waren. 10
2.1.4.1.1 FAZIT Die Tests zeigten, dass bei dem manuellen Eingriff in die einzelnen Größen des Database Buffer Cache man die Größen vorsichtig vergeben sollte und sich lieber auf die Standart eingestellten Größen durch das System verlasen sollte. 2.1.4.2 Optimierung mit SGA und PGA unter Oracle 10g XE Die Ergebnissen der Optimierung mit SGA und PGA unter Oracle 10g EE, waren den Ergebnissen der Optimierung unter Oracle 10g XE ähnlich. Default Einstellungen von SGA unter ORACLE 10g XE Default Einstellung PGA von Oracle 10g XE Getestet wurde Datenbank mit Primär-, Fremdschlüsseln mit Standart SGA, PGA Einstellungen gegen Datenbank mit Primär-, Fremdschlüsseln und • SGA = 512 • PGA = 124 11
Die Graphische Darstellung zeigt, dass obwohl sich die Laufzeit der Query 5 nach der Optimierung sehr verbessert hat, ist das Gesamtbild der Optimierung nicht sehr gut. 2.1.4.2.1 Fazit der Optimierung mit SGA und PGA Stellt der Datenbankadministrator bei der Installation der gesamten Datenbank diese zwei Parameter für die Speichergröße nicht ein so wird von der System die optimale Größe automatisch eingestellt, die man auch beibehalten kann es sei man hat Schwierigkeiten mit Performance oder bekommt bestimmte Oracle Fehler, dann können die Größen geändert werden. Die Tests haben gezeigt, dass nachdem die SGA und PGA erhöht wurden, hat die Laufzeit der Queries sich verbessert, aber weil es keine sehr gute Verbesserung war, könnte man auch weiter mit den alten Größen arbeiten und versuchen die Queries mit den anderen Methoden zu Optimieren. Schaut man aber sich das Gesamtbild der Optimierung unter oracle 10g EE an: Primär- und Fremdschlüssel, PGA und SGA so sieht man, dass die Durchschnittlaufzeit der Queries im Vergleich zum Anfangszustand sich merklich verbessert hat. 2.2 Konzeptuelle Ebene Die konzeptuelle Ebene befasst sich mit der Abstraktion der Daten. D.h. die Darstellung der Daten, die im physischen Schema vorliegen, werden so angepasst, wie sie der Benutzer haben möchte. 14 14 [8] Datenbanksystem 12
2.2.1 Denormalisierung Die Denormalisierung ist die bewusste Rücknahme einer Normalisierung zum Zweck der Verbesserung des Laufzeitverhaltens der Anfragen. Die Denormalisierung reduziert die Tabellenzahl und verbessert die Antwortzeiten. Mindestens theoretisch. Das ist der wichtigste Vorteil. Die Nachteile sind: Datenredundanz und mehr Speicherplatz nötig, Aufwand um die redundanten Daten konsistent zu halten, Gefahr von Datenanomalien. Die Synchronisierung der Updates (Aktualisierungen) ist eine konstante Herausforderung für die Integrität der Daten in einer denormalisierten Datenbank. Für unsere Datenbank haben wir zuerst die Tabellen NATION und REGION unter Oracle 10g XE in einer einzigen Tabelle transformiert: CREATE TABLE nation_region AS SELECT n_nationkey, n_name, n_comment, r_name AS n_r_name FROM nation, region WHERE n_regionkey=r_regionkey Die Ergebnisse waren aber nicht überzeugend, wahrscheinlich weil die zwei Tabellen sehr klein sind. Deswegen wurde auch die Tabelle supplier dazu addiert: Die Denormalisierung der TPCH Datenbank CREATE TABLE supp_nat_reg AS SELECT s_suppkey, s_name, s_address, s_nationkey, s_phone, s_acctbal, s_comment, n_name AS s_n_name, n_r_name AS s_r_name FROM supplier, nation_region WHERE s_nationkey=n_nationkey ALTER TABLE supp_nat_reg ADD CONSTRAINT pk_snr PRIMARY KEY (s_suppkey) 13
Nach dem Ausführung der geänderten Queries, waren die Ergebnisse überraschend. Die Ausführungszeit bei Query 5 z.B. hat sich um 6% verschlechtert. Dasselbe ist auch bei Oracle EE passiert: Denormalisierung 04:19.2 03:36.0 02:52.8 Zeit 02:09.6 01:26.4 00:43.2 00:00.0 Q2 Q5 Q9 Q11 Q20 Querie s Normal Denormalisiert Die Verschlechterung der Ausführungszeiten bei Oracle XE und EE Insgesamt sind die Zeiten um 14%, beziehungsweise um 8,6% höher geworden. Um eine Erklärung zu finden, wurde der Ausführungsplan von Q5 angeschaut. Der Query Optimizer hat bei der Denormalisierten Datenbank keine Primärschlüssel benutzt und hat die ganze neue Tabelle supp_nat_reg zugegriffen. 2.2.1.1 FAZIT Es lohnt sich nicht die Datenbank zu denormalisieren. Obwohl das teoretisch bessere Zeiten bringen sollte, bei Oracle gilt es nicht. 2.2.2 Integration von Views in Anfragen Eine View (deutsch Sicht) ist eine logische Relation (auch virtuelle Relation oder virtuelle Tabelle) in einem Datenbanksystem. Diese logische Relation wird über eine im Datenbankmanagementsystem (DBMS) gespeicherte Abfrage definiert. Der Datenbankbenutzer kann eine View wie eine normale Tabelle abfragen. Neben den herkömmlichen Views gibt es noch so genannte Materialized Views (MS). Diese sind Views, die physikalisch gespeichert werden, um Zugriffe zu beschleunigen. 14
Im Unterschied zu Klassischen Views werden Materialized Views nicht explizit in der SQL-Query angesprochen. Eine materialisierte View ist eine Replik von Daten, die von einer Abfrage abgeholt werden. Benutzerabfragen können zu einer materialisierten View umgeleitet werden, um Große Tabellen während der Ausführung zu vermeiden. 15 Materialized Views ermöglichen die Ergebnismenge einer View als eigenständige Tabelle abzuspeichern. Dies bringt besonders bei verteilten Datenbanken einen erheblichen Performancegewinn, da Abfragen lokal durchgeführt werden können und hierdurch das Netzwerk bei der Abfrage dieser Views nicht belastet wird. Der Begriff Materialized View wurde mit der Version Oracle 8i eingeführt und ersetzt den bis dahin verwendeten Begriff SNAPSHOT. Der Aufruf der Refresh-Prozedur ermöglicht die manuelle Aktualisierung einer Materialized View (MV). • EXEC DBMS_MVIEW.REFRESH (list=>‘Angestellte‘); Syntax: CREATE MATERIALIZED VIEW [schema.]mview ON PREBUILT TABLE [{WITH | WITHOUT} REDUCED PRECISION] [USING INDEX storage_options] [{REFRESH [refresh_options] | NEVER REFRESH] [FOR UPDATE] [{ENABLE|DISABLE} QUERY REWRITE] AS subbquery; 16 Es wurde versucht die Laufzeit der Queries durch Materializes views zu beschleunigen, dafür wurden die Queries: 7, 8, 9, 11, 20 und 22 benutzt. Z.B.: Query 8: Select o_year, sum (case when nation = 'BRAZIL' then volume else 0 end) / sum(volume) as mkt_share from ( select extract(year from o_orderdate) as o_year, l_extendedprice * (1 - l_discount) as volume, n2.n_name as nation from part, supplier, lineitem, orders, customer, nation n1, nation n2, region where p_partkey = l_partkey and s_suppkey = l_suppkey and l_orderkey = o_orderkey and o_custkey = custkey and c_nationkey = n1.n_nationkey and n1.n_regionkey = r_regionkey and r_name = 'AMERICA‘ and s_nationkey = n2.n_nationkey and o_orderdate between date '1995-01-01' and date '1996-12-31‘ and p_type = 'ECONOMY ANODIZED STEEL') group by o_year Order by o_year; Create Materialized View create materialized view mv_q8 as select extract(year from o_orderdate) as o_year, l_extendedprice * (1 - l_discount) as volume, n2.n_name as nation from part, supplier, lineitem, orders, customer, nation n1, nation n2, region where p_partkey = l_partkey and s_suppkey = l_suppkey and l_orderkey = o_orderkey and o_custkey = c_custkey and c_nationkey = n1.n_nationkey and n1.n_regionkey = r_regionkey and r_name = 'AMERICA‘ and s_nationkey = n2.n_nationkey and o_orderdate between date '1995-01-01' and 15 [13] http://de.wikipedia.org/wiki/Sicht_%28Datenbank%29 16 [14] Materialized Views 15
date '1996-12-31' and p_type = 'ECONOMY ANODIZED STEEL' Umschreiben der Query 8 select o_year, sum(case when nation = 'BRAZIL' then volume else 0 end) / sum(volume) as mkt_share from mv_q8 group by o_year order by o_year; Tests unter Oracle 10g EE Tests unter Oracle 10g XE 2.2.2.1 FAZIT Die durchgeführten Tests haben gezeigt, dass durch das Benutzen der Materialized Views die Laufzeit der Queires sich erheblich verbessert hat, und sowohl unter Oracle 10g EE als auch unter Oracle 10g XE ist fast die Gleiche Verbesserung zu sehen. Die Durchschnittslaufzeit der Queries lag nach der Optimierung unter Oracle 10g EE bei 0,021 Sekunden (0,47 Sekunden vor der Optimierung) und unter Oracle 10g XE bei 0,6 Sekunden (17 Sekunden vor der Optimierung). Es ist sehr einfach und empfehlenswert mit Materialized Views zu arbeiten, falls man die Laufzeit der Queries beschleunigen möchte. 16
2.2.3 Partitionierung von Tabellen In den letzten Jahren wurden Datenbanken ebenso wie Tabellen immer größer. Heutzutage müssen häufig Tabellen mit einem Platzbedarf von bis zu mehreren Terrabyte implementiert und verwaltet werden. Die Verwaltung sehr großer Tabellen und Indizes kann sehr zeitaufwendig sein. Zudem ist oft eine mangelnde Performance bei Datenzugriffen zu bemerken. Um dem entgegen zu wirken, führte Oracle bereits in Version 8 die horizontale Partitionierung von Tabellen. Jede einzelne Partition kann eigene physische Attribute (Tablespace, Storage-Parameter) haben und einzeln angesprochen werden. Aus Sicht des Benutzers handelt es sich dabei weiterhin um eine einzige Tabelle. Aufgrund eines „Partition Keys“ werden die eingefügten Daten automatisch in der jeweiligen Partition gespeichert. Einige Vorteile von Partitionierung sind: • die einzelnen Partitionen können unabhängig voneinander verwaltet werden (z.B. Partitionen löschen, reorganisieren und sichern) • Performanceverbesserungen (befinden sich die in einer Abfrage benötigten Daten in einer Partition, so muss nur auf diese Partition zugegriffen werden.) • bei geeigneter Partitionierung können auf diese Art große Datenmengen schnell gelöscht werden Oracle stellt verschiedene Varianten der Partitionierung zur Verfügung. Die RANGE-Partitionierung Hierbei handelt es sich um eine Bereichspartitionierung. Ein typisches Beispiel ist die Partitionierung einer Tabelle nach Datum, um alle Datensätze aus dem gleichen Quartal in einer eigenen Partition zu speichern. Die HASH-Partitionierung Bei der Hash-Partitionierung haben die Datensätze innerhalb der Partitionen keine besondere Bedeutung. Hier entscheidet das System mit Hilfe einer Hash-Funktion, in welche Partition ein Datensatz abgelegt wird. Beispiel: (Part Table wäre Möglich (Q16, 2)) CREATE TABLE part(P_PARTKEY INTEGER NOT NULL, P_NAME VARCHAR(55) NOT NULL, P_MFGR CHAR(25) NOT NULL, P_BRAND CHAR(10) NOT NULL, P_TYPE VARCHAR(25) NOT NULL, P_SIZE INTEGER NOT NULL, P_CONTAINER CHAR(10) NOT NULL, P_RETAILPRICE DECIMAL(15,2) NOT NULL, P_COMMENT VARCHAR(23) NOT NULL) PARTITION BY HASH (p_size) PARTITIONS 3 STORE IN (data1, data2, data3); In diesem Beispiel werden die einzelnen Datensätze vom System auf die drei verschiedenen Partitionen verteilt. Dabei wird eine Hash-Funktion angewendet, die aufgrund der Werte in der Spalte „p_size“ die Partition für die Speicherung bestimmt. Die Namen der Partitionen legt das System fest. Diese Partitionierungsmethode kann angewendet werden, wenn in einer DSS Umgebung gearbeitet wird (in der Regel wird die gesamte Tabelle eingelesen) und die Verteilung der Daten nicht bekannt ist. Sie stellt eine einfache Möglichkeit zur Verfügung, Daten auf mehrere Tablespaces (Dateien) zu verteilen, die dann mit Hilfe paralleler Zugriffsmechanismen bearbeitet werden können. 17
Im zweiten Teil des Artikels wird dann intensiv auf die Themen List- und Composite Partionierung eingegangen. 17 Die LIST-Partitionierung Die LIST-Partitionierung wurde in Oracle 9i speziell für Datenverteilungen eingeführt, die einzelnen Werten folgen. Beispiel: CREATE TABLE region (R_REGIONKEY INTEGER NOT NULL, R_NAME CHAR(25) NOT NULL, R_COMMENT VARCHAR(152)) TABLESPACE data1 PARTITION BY LIST (r_name) (PARTITION region_Europe VALUES ('EUROPE') TABLESPACE data2, PARTITION region_ASIA VALUES ('AISA') TABLESPACE data3, PARTITION region_AMERICA VALUES ('AMERICA') TABLESPACE data4, PARTITION region_default VALUES (DEFAULT) TABLESPACE data5 ); Die Datensätze werden aufgrund des Wertes in der Spalte "r_name " den Partitionen zugeordnet. Datensätze mit dem "r_name " EUROPE werden zum Beispiel in die Partition "region_Europe" eingefügt. Entspricht das spezifizierte "r_name " keinem der explizit aufgeführten Werte, so wird der Datensatz der Partition "region_default" zugewiesen. COMPOSITE-Partitionierung Es gibt zudem die Möglichkeit die verschiedenen Partitionierungsmethoden miteinander zu kombinieren, um so eine Partitionierung auf zwei Ebenen zu erreichen. Dadurch ist es möglich, eine Partition wiederum in eine bestimmte Anzahl an Subpartitionen aufzuteilen. Das kann sinnvoll sein, wenn die einzelnen Partitionen einer Tabelle noch sehr groß sind. Man unterscheidet die RANGE- LIST- und die RANGE-HASH-Partitionierung. Beispiel für eine RANGE-LIST-Partitionierung: CREATE TABLE lineitem ( L_ORDERKEY INTEGER NOT NULL, L_PARTKEY INTEGER NOT NULL, L_SUPPKEY INTEGER NOT NULL, L_LINENUMBER INTEGER NOT NULL, L_QUANTITY DECIMAL(15,2) NOT NULL, L_EXTENDEDPRICE DECIMAL(15,2) NOT NULL, L_DISCOUNT DECIMAL(15,2) NOT NULL, L_TAX DECIMAL(15,2) NOT NULL, L_RETURNFLAG CHAR(1) NOT NULL, L_LINESTATUS CHAR(1) NOT NULL, L_SHIPDATE DATE NOT NULL, L_COMMITDATE DATE NOT NULL, L_RECEIPTDATE DATE NOT NULL, L_SHIPINSTRUCT CHAR(25) NOT NULL, L_SHIPMODE CHAR(10) NOT NULL, L_COMMENT VARCHAR(44) NOT NULL) PARTITION BY RANGE (L_RECEIPTDATE) SUBPARTITION BY LIST (L_SHIPMODE) SUBPARTITION TEMPLATE (SUBPARTITION mailship VALUES ('MAIL', 'SHIP') TABLESPACE data2, SUBPARTITION andere VALUES (DEFAULT) TABLESPACE data3) (PARTITION Jahr_1994 VALUES LESS THAN (TO_DATE('1995-01-01','YYYY/MM/DD')), PARTITION Andere_Jahre VALUES LESS THAN (TO_DATE('1994-01-01','YYYY/MM/DD'))); 17 [15] Oracle: Einsatz von Partitioning 18
Die Tabelle wird mit vier Partitionen erstellt, die wiederum in jeweils zwei Subpartitionen aufgesplittet sind. Jede Partition nimmt die Subpartitions-Beschreibungen aus dem angegebenen SUBPARTITION TEMPLATE. Die generierten Subpartitionsnamen sind jeweils Jahr_1995 und Andere_Jahre,... Datensätze aus dem Juni 1994 werden der Partition Jahr_1994 zugeordnet. In Abhängigkeit des Wertes in der Spalte "L_SHIPMODE " werden sie dann einer der beiden Subpartitionen zugeordnet. Lautet das "L_SHIPMODE " MAIL, so wird der Datensatz in die Subpartition mailship eingefügt. Indizes Bei der Zugriffsoptimierung spielen Indizes eine bedeutende Rolle. Dies gilt sowohl bei nicht- partitionierten Tabellen als auch bei partitionierten Tabellen. Beim Anlegen eines Indexes auf eine partitionierte Tabelle hat man verschiedene Möglichkeiten: Zum einen kann ein Index über die gesamte Tabelle erstellt werden und zum anderen kann ein partitionierter Index erstellt werden. Dabei kann der Index entweder gleichpartitioniert sein oder der Index kann mit einer eigenen Partitionierungsstrategie erstellt werden. Ist ein Index gleichpartitioniert, so spricht man von einem lokalen Index, anderenfalls von einem globalen Index. Die lokalen Indizes sind im Zusammenhang mit der Verbesserung von Performance und Fehlertoleranz von großer Bedeutung. Beispiel für die Erstellung eines lokalen Indizes: create tablespace idx1 datafile 'E:\oracle\product\10.2.0\oradata\orcl\idx1.dbf' size 1M autoextend on next 500k; create tablespace idx2 datafile 'E:\oracle\product\10.2.0\oradata\orcl\idx2.dbf' size 1M autoextend on next 500k; create tablespace idx3 datafile 'E:\oracle\product\10.2.0\oradata\orcl\idx3.dbf' size 1M autoextend on next 500k; create tablespace idx4 datafile 'E:\oracle\product\10.2.0\oradata\orcl\idx4.dbf' size 1M autoextend on next 500k; create tablespace idx5 datafile 'E:\oracle\product\10.2.0\oradata\orcl\idx5.dbf' size 1M autoextend on next 500k; CREATE INDEX l_lineitem_idx ON lineitem (L_SHIPDATE, L_ORDERKEY, L_LINENUMBER) LOCAL (PARTITION p1 TABLESPACE idx1, PARTITION p2 TABLESPACE idx2, PARTITION p3 TABLESPACE idx3, PARTITION p4 TABLESPACE idx4, PARTITION p5 TABLESPACE idx5 ); Der Index, der auf die Spalte "l_orderkey, L_LINENUMBER" gelegt wird, besitzt die gleichen Partitionen wie die Tabelle "lineitem" (s.o.). Das bedeutet, dass Einträge aus einer Indexpartition auf genau eine Tabellenpartition verweisen. Diese Art von Index ist für Anfragen, die einzelne Partitionen betreffen sinnvoll. Beispiel für einen nicht-partitionierten, globalen Index CREATE INDEX l_orderkey_idx ON lineitem (l_orderkey); Der so erstellte Index ist nicht partitioniert. Diese Art von Indizes ist für Anfragen, die die gesamte Tabelle betreffen (und nicht einzelne Partitionen) sinnvoll. Beispiel für einen partitionierten, globalen Index: CREATE INDEX l_orderkey_idx ON lineitem (l_shipdate, l_orderkey) GLOBAL PARTITION BY RANGE (l_shipdate) (PARTITION p1 VALUES LESS THAN (TO_DATE('1993-12-31','YYYY/MM/DD')) 19
TABLESPACE p1, PARTITION p2 VALUES LESS THAN (TO_DATE('1995-03-14','YYYY/MM/DD')) TABLESPACE p2, PARTITION p3 VALUES LESS THAN (TO_DATE('1995-10-02','YYYY/MM/DD')) TABLESPACE p3, PARTITION p4 VALUES LESS THAN (TO_DATE('1997-01-01','YYYY/MM/DD')) TABLESPACE p4, PARTITION p5 VALUES LESS THAN (MAXVALUE) TABLESPACE p5 ); Voraussetzung für die Partitionierung ist, dass das Partitionierungskriterium ein Prefix ist (die zuerst indizierte Spalte oder Spaltenkombination). 18 2.2.3.1 Tests unter Tabellen Partitionierung Getestet wurde die RANGE-Partitionierung mit der Tabelle Lineitem, und die LIST-Partitionierung mit der Tabelle Part. Die RANGE-Partitionierung wurde mit und ohne den partitionierten lokalen Index getestet. Ein partitionierter Index geht Hand in Hand mit partitionierten Tabellen. Tatsächlich wird eine partitionierte Tabelle normalerweise standardmäßig über partitionierte Index verfügen. Ein Präfix- Index ist als Index definiert, dessen am weitesten links stehende Spalten exakt mit denen des Partitionsschlüssels übereinstimmen. Im Zusammenhang mit partitionierten Indices ist das Konzept von Präfix-Indices aus folgenden Gründen wichtig: Eindeutige Präfix-Indices stellen sicher, dass man nur noch auf eine Indexpartition zugreifen muss, um an die Daten zu gelangen. Nicht eindeutige Präfix-Indices stellen immer noch sicher, dass man nur eine Indexpartition benötigt, wenn man den vollständigen Partitionsschlüssel als Bestandteil der WHERE-Klausel angibt. Die Ausnahme hierzu ist, dass alle Partitionen durchsucht werden, wenn man nur einen Teil des Partitionsschlüssels angibt. Die Partitionierung wurde bei den Tabellen Region und Nation nicht benutzt, weil sie viel zu klein sind. Die RANGE-Partitionierung auf der Tabelle „Lineitem“ hat bei fast allen Queires deutliche Verbesserungen gebracht. create tablespace p1 datafile 'E:\oracle\product\10.2.0\oradata\orcl\p1.dbf' size 1M autoextend on next 500k create tablespace p2 datafile 'E:\oracle\product\10.2.0\oradata\orcl\p2.dbf' size 1M autoextend on next 500k create tablespace p3 datafile 'E:\oracle\product\10.2.0\oradata\orcl\p3.dbf' size 1M autoextend on next 500k create tablespace p4 datafile 'E:\oracle\product\10.2.0\oradata\orcl\p4.dbf' size 1M autoextend on next 500k create tablespace p5 datafile 'E:\oracle\product\10.2.0\oradata\orcl\p5.dbf' size 1M autoextend on next 500k CREATE TABLE LINEITEM ( L_ORDERKEY INTEGER NOT NULL, L_PARTKEY INTEGER NOT NULL, L_SUPPKEY INTEGER NOT NULL, L_LINENUMBER INTEGER NOT NULL, L_QUANTITY DECIMAL(15,2) NOT NULL, L_EXTENDEDPRICE DECIMAL(15,2) NOT NULL, 18 [16] Oracle: Einsatz von Partitioning (Teil 2) 20
L_DISCOUNT DECIMAL(15,2) NOT NULL, L_TAX DECIMAL(15,2) NOT NULL, L_RETURNFLAG CHAR(1) NOT NULL, L_LINESTATUS CHAR(1) NOT NULL, L_SHIPDATE DATE NOT NULL, L_COMMITDATE DATE NOT NULL, L_RECEIPTDATE DATE NOT NULL, L_SHIPINSTRUCT CHAR(25) NOT NULL, L_SHIPMODE CHAR(10) NOT NULL, L_COMMENT VARCHAR(44) NOT NULL) PARTITION BY RANGE (L_SHIPDATE) (PARTITION p1 VALUES LESS THAN (TO_DATE('1993-12-31','YYYY/MM/DD')) TABLESPACE p1, PARTITION p2 VALUES LESS THAN (TO_DATE('1995-03-14','YYYY/MM/DD')) TABLESPACE p2, PARTITION p3 VALUES LESS THAN (TO_DATE('1995-10-02','YYYY/MM/DD')) TABLESPACE p3, PARTITION p4 VALUES LESS THAN (TO_DATE('1997-01-01','YYYY/MM/DD')) TABLESPACE p4, PARTITION p5 VALUES LESS THAN (MAXVALUE) TABLESPACE p5 ); In diesem Beispiel wird die Tabelle “ LINEITEM” erstellt, die in fünf Partitionen aufgeteilt ist. In der ersten Partition werden alle Bestellungen gespeichert, deren Bestelldatum vor dem '1993-12-31' liegt. In der zweiten Partition werden die Datensätze gespeichert, deren Bestelldatum vor dem '1995-03-14' liegt und die nicht in der ersten Partition gespeichert sind. Die letzte Partition nimmt alle Datensätze auf, die keiner der anderen Partitionen zugeordnet werden können, da durch die Verwendung des Schlüsselwortes MAXVALUE keine Obergrenze definiert ist. Die einzelnen Partitionen werden hier in unterschiedliche Tablespaces abgelegt. Diese Partitionierungsmethode ist gut geeignet für die Ablage historischer Daten, da das Löschen alter Daten sowie das Hinzufügen neuer Partitionen einfach und schnell durchführbar ist. Insbesondere die Query 10, die sonst ungefähr 6 Minuten gebraucht hat, lief mit partitionierten lokalen Index nur noch 1,4 Minuten. Die Graphische Darstellungen zeigten, dass die besten Ergebnisse kamen mit unter partitionierten lokalen Index heraus, die zweit Besten Ergebnisse waren unter der Benutzung des Primärschlüssels zu sehen. Nachdem der partitionierte lokale Index auf (L_SHIPDATE, L_ORDERKEY, L_LINENUMBER)erstellt wurde, haben die Queries im Durchschnitt nur noch 0,45 Sekunden gebraucht und ohne den partitionierten lokalen Index aber mit dem Primärschlüssel auf (L_ORDERKEY, L_LINENUMBER) liefen die Queries im Durchschnitt 0,48 Sekunden. 21
LIST-Partitionierung wurde auf Tabelle Part erstellt und hat auch gute Ergebnisse gezeigt. Z.B. die Laufzeit der Query 19 hatte sich von 0,42 auf 0,32 verbessert. create tablespace data1 datafile 'E:\oracle\product\10.2.0\oradata\orcl\data1.dbf' size 1M autoextend on next 500k; create tablespace data2 datafile 'E:\oracle\product\10.2.0\oradata\orcl\data2.dbf' size 1M autoextend on next 500k; create tablespace data3 datafile 'E:\oracle\product\10.2.0\oradata\orcl\data3.dbf' size 1M autoextend on next 500k; create tablespace data4 datafile 'E:\oracle\product\10.2.0\oradata\orcl\data4.dbf' size 1M autoextend on next 500k; create tablespace data5 datafile 'E:\oracle\product\10.2.0\oradata\orcl\data5.dbf' size 1M autoextend on next 500k; CREATE TABLE part (P_PARTKEY INTEGER NOT NULL, P_NAME VARCHAR(55) NOT NULL, P_MFGR CHAR(25) NOT NULL, P_BRAND CHAR(10) NOT NULL, P_TYPE VARCHAR(25) NOT NULL, P_SIZE INTEGER NOT NULL, P_CONTAINER CHAR(10) NOT NULL, P_RETAILPRICE DECIMAL(15,2) NOT NULL, P_COMMENT VARCHAR(23) NOT NULL) TABLESPACE data1 PARTITION BY LIST (p_container) (PARTITION SM VALUES ('SM CASE', 'SM BOX', 'SM PACK', 'SM PKG') TABLESPACE data2, PARTITION MED VALUES ('MED BAG', 'MED BOX', 'MED PKG', 'MED PACK') TABLESPACE data3, PARTITION LG VALUES ('LG CASE', 'LG BOX', 'LG PACK', 'LG PKG') TABLESPACE data4, PARTITION region_default VALUES (DEFAULT) TABLESPACE data5); create tablespace idx11 datafile 'E:\oracle\product\10.2.0\oradata\orcl\idx11.dbf' size 1M autoextend on next 500k; create tablespace idx44 datafile 'E:\oracle\product\10.2.0\oradata\orcl\idx44.dbf' size 1M autoextend on next 500k; create tablespace idx22 datafile 'E:\oracle\product\10.2.0\oradata\orcl\idx22.dbf' size 1M autoextend on next 500k; create tablespace idx33 datafile 'E:\oracle\product\10.2.0\oradata\orcl\idx33.dbf' size 1M autoextend on next 500k; CREATE INDEX p_part_idx ON part (p_container, p_size, p_brand, p_partkey) LOCAL (PARTITION SM TABLESPACE idx11, PARTITION MED TABLESPACE idx22, PARTITION LG TABLESPACE idx33, PARTITION region TABLESPACE idx44 ); 2.2.3.1.1 FAZIT Die Tests haben gezeigt, dass Tabellen Partitionierung eine sehr gute Methode ist, um die Laufzeit der Queries zu beschleunigen, dabei wichtig ist, dass die Tabellen die Partitioniert nicht sehr klein sind, damit die Laufzeit der Queries auch merklich verbessert werden kann. Leider ist unter Oracle 10g XE die Funktion für Partitionieren nicht aktiviert (ORA-00439: Funktion nicht aktiviert: Partitioning), daher Partitionierung konnte nur unter Oracle 10g EE getestet werden. 2.2.4 Clustering Clustering ist ein Mittel zur Strukturierung der Daten in ein oder mehreren Tabellen, so dass deren Zeilen physisch nebeneinander liegen. 19 Ein Cluster kann eingesetzt werden, wenn mehrere Tabellen eine Zeile desselben Datentyps und derselben Größe am selben Speicherort aufnehmen. Dadurch lässt sich der Speicherbedarf reduzieren und in einigen Fällen der Datenzugriff beschleunigen. Der wesentliche Nachteil in Form von 19 [17] Oracle SQL im Überblick 22
Performanzeinbußen tritt bei Aktionen zu Tage, an denen Aktualisierungs-, Einfüge- und Löschoperationen beteiligt sind. Der DBA sollte den zu erwartenden Mix von Transaktionsarten für die zu clusternden Tabellen ermitteln und nur diejenigen von ihnen clustern, die häufig miteinander verknüpft werden und nicht viele Aktualisierungs-, Einfüge- und Löschoperationen erfahren. Cluster speichern gemeinsam genutzte Datenwerte in denselben physischen Blöcken (die Schlüsselwerte des Clusters). Bei häufig miteinander verknüpften Tabellen kann dies den Zugriff beschleunigen; bei Tabellen auf die häufig getrennt voneinander zugegriffen wird, ist das Verknüpfen keine Antwort. Ein einzelner Tabellencluster zwingt die Schlüsselwerte für diese Tabelle in eine einzige Gruppe von Blöcken, wodurch der Zugriff auf diese Tabelle beschleunigt wird. Üblicherweise kommt bei dieser Art von Einzeltabellenclustern auch eine Hash – Struktur zum Einsatz, die die Zugriffszeiten noch verbessert. 20 Man unterscheidet: • Index Cluster: Der Cluster Key entspricht einem oder mehreren Tabellenattributten. • Hash Cluster: Der Cluster Key das Ergebnis der Anwendung einer Hashfunktion auf ein oder mehrere Tabelenattribute. Idealfall: Der Cluster Key verteilt die Datensätze so, dass pro Cluster Key ein Block benötigt wird. Erzeugen von Cluster Ein Cluster wird durch folgenden Befehl erzeugt: CREATE CLUSTER clustername (attr1 datentyp1 [,attr2 datentyp2] ... ) [PCTUSED integer] [PCTFREE integer] [SIZE integer [K|M] ] [INDEX | [HASH IS attr] HASHKEYS integer] Die Attribute attr1, attr2,... geben den Clusterschlüssel an. Die Parameter PCTUSED und PCTFREE steuern den Füllgrad von Datenblöcken. Der Parameter PCTUSED bezeichnet dabei den Anteil (Angabe in Prozent) eines Datenblocks, der mindestens belegt sein sollte. PCTFREE gibt an, wie viel Prozent des Datenblocks mindestens frei sein sollten. Die Summe aus PCTUSED und PCTFREE darf den Wert 100 nie überschreiten. Der Parameter SIZE bestimmt, wie viele Bytes innerhalb eines Datenblockes für denselben Clusterschlüssel-Wert bzw. Hash-Wert verwendet werden. Der Wert darf die Größe eines Datenblockes nicht überschreiten. Wird die Angabe von SIZE weggelassen, so reserviert Oracle einen Datenblock pro Schlüsselwert. Die Angabe von INDEX erzeugt einen Index- Cluster, während durch HASHKEYS n ein Hash-Cluster mit n verschiedenen Hash-Werten (Buckets) erzeugt wird. Der Wert n wird zuvor intern auf die nächst größere Primzahl aufgerundet. Erzeugen von Indizes Indizes werden durch folgende Anweisung erzeugt: CREATE INDEX indexname ON { tabellenname(attr1 [,attr2]...) | CLUSTER clustername } [PCTFREE integer] Durch die Angabe eines Tabellennamens und der zu indizierenden Attribute der Tabelle wird ein mittelbarer Index auf der entsprechenden Relation aufgebaut. Durch Angabe von ASC bzw. DESC wird das Attribut innerhalb des Index aufsteigend bzw. absteigend sortiert. 21 20 [18] Oracle – Datenbanken Administration und Management 21 [19] Datenbanksysteme 23
2.2.4.1 Index Cluster Prinzip: Tupel mit gleichem Cluster Key werden gemeinsam in Blocken gespeichert. • Cluster Gruppe: Falls nicht alle zu einem Cluster-Key gehörenden Datensätze in einem Datenblock Platz haben, werden die benötigten Blöcke zu einer Cluster Gruppe verkettet. • Je Länger die Cluster Gruppen sind desto geringer ist die Effizienz. • Cluster-Gruppen sollen auf nicht mehr als zwei DB-Blöcke verteilt sein. • Vorteile: Joins der am Cluster beteiligten Tabellen über Cluster key werden schneller (was bei uns nicht der Fall war). Geringer Speicherbedarf, da Cluster Key nur einmal gespeichert wird. • Nachteil: Bei Abfragen, die nur eine Tabelle betreffen, sind mehr Zugriffe als bei konventioneller Speicherung notwendig, da die Datensätze der Tabelle auf mehr Blöcke verteilt sind. • Unterstützung: point-Queries und range-Queries. 24
2.2.4.1.1 Tests unter Oracle 10g XE Getestet wurden zwei Tabellen: • Part • Partsupp Bei den am Anfang durchgeführten Tests wurde es versucht erst ohne die Ermittlung des Speicherbedarfs für Cluster zu arbeiten. So wurde eine Große von 512 Byte gewählt. CREATE CLUSTER Cluster_Part_partsupp (p_partkey INTEGER ) size 512; CREATE TABLE PARTSUPP ( P_PARTKEY INTEGER NOT NULL, PS_SUPPKEY INTEGER NOT NULL, PS_AVAILQTY INTEGER NOT NULL, PS_SUPPLYCOST DECIMAL(15,2) NOT NULL, PS_COMMENT VARCHAR(199) NOT NULL ) CLUSTER Cluster_Part_partsupp (P_PARTKEY); CREATE TABLE PART ( P_PARTKEY INTEGER NOT NULL, P_NAME VARCHAR(55) NOT NULL, P_MFGR CHAR(25) NOT NULL, P_BRAND CHAR(10) NOT NULL, P_TYPE VARCHAR(25) NOT NULL, P_SIZE INTEGER NOT NULL, P_CONTAINER CHAR(10) NOT NULL, P_RETAILPRICE DECIMAL(15,2) NOT NULL, P_COMMENT VARCHAR(23) NOT NULL ) CLUSTER Cluster_Part_partsupp (P_PARTKEY); CREATE INDEX Part_partsupp_INDEX on CLUSTER Cluster_Part_partsupp; Query 2 Zeit: Mit Index Cluster: 3,48 seconds Ohne Index Cluster: 0,89 seconds Diese Tests haben gezeigt, dass leider mit dem Einsatz des Index Clusters die Laufzeit der Queries sich verschlechtert hat. Was natürlich nicht der Fall sein sollte. 2.2.4.2 Hash Cluster • Einsatz: Wird verwendet, um einzelne Tabellen aber auch um mehrere Tabellen gemeinsam zu speichern. • Vorteile: Extrem effizienter Zugriff über die Attributkombinationen auf die die Hashfunktion angewendet wird (was leider bei uns nicht der Fall war). Es ist keine Suche im Index notwendig. • Unterstützung: nur point-Queries. Getestet wurden die gleichen Tabellen: 25
• Part • Partsupp CREATE CLUSTER Cluster_Part_partsupp (p_partkey INTEGER ) size 512, hash is p_partkey, HASHKEYS 200001 CREATE TABLE PARTSUPP ( P_PARTKEY INTEGER NOT NULL, PS_SUPPKEY INTEGER NOT NULL, ……………………………………. PS_COMMENT VARCHAR(199) NOT NULL ) CLUSTER Cluster_Part_partsupp (P_PARTKEY); CREATE TABLE PART ( P_PARTKEY INTEGER NOT NULL, P_NAME VARCHAR(55) NOT NULL, ………………………………………… P_COMMENT VARCHAR(23) NOT NULL ) CLUSTER Cluster_Part_partsupp (P_PARTKEY); Query 2 Zeit: Mit Index Cluster: 3,48 seconds Ohne Index Cluster: 0,89 seconds Mit Hash Cluster: 3,08 seconds Diese Tests haben im Vergleich zu Index Cluster etwas besser abgeschnitten aber leider war das Ergebnis trotzdem nicht gut. 2.2.4.3 Index Cluster mit SIZE = 800b Weil die Optimierungsergebnisse nicht gut waren, wurde hier mit dem einfachen Weg versucht die Größe des SIZE Parameters zu bestimmen. Besonders vorteilhaft ist Index Cluster, wenn bei der 1:n Beziehung die Zahl n eine Konstante ist, daher geclustert wurden noch einmal die gleichen Tabellen: • Part • Partsupp Mit: select * from partsupp order by ps_partkey wurde die Beziehung zu ps_partkey Schlüssel bestimmt. n war hier immer eine Konstante = 4. 26
Mit: Select table_name, avg_row_len from dba_tables wurde die durchschnittliche Länge der PART und PARTSUPP Tabellen bestimmt. Mit Hilfe der gelieferten Ergebnissen konnte man dann die Größe des SIZE Parameters errechnen: |part|+n*|partsupp| ≈ 800 Byte Die Ergebnisse waren besser aber trotzdem leider nicht gut. 2.2.4.4 Hash Cluster gegen Index Cluster Die durchgeführten Tests unter Oracle 10g XE haben gezeigt, dass durch das Einsetzen der CLUSTER die Laufzeit der Queries sich veschlechtert hat. Auch das Ermitteln der Größe für SIZE Parameter hat zu keinen besseren Ergebnissen geführt. 2.2.4.5 Tests unter Oracle 10g EE Wie die folgende Graphische Darstellung zeigt, dass nachdem die Optimierung mit Hilfe der Tabellen Partitionierung durchgeführt wurde, hat die Laufzeit der Queries sich merklich verbessert, trotzdem blieb die Laufzeit der Queries 18 und 21 außerhalb der Verbesserung. Daher wird im Folgenden die Optimierung mit Hilfe der Index und Hash Cluster durchgeführt und die Laufzeit während der Optimierung wird nur bei diesen beiden Queries betrachtet. 27
2.2.4.6 Ermittlung des Speicherbedarfs für Cluster Sowohl bei Indexclustern als auch bei Hash – Clustern ist es wichtig, den Platzbedarf für die Daten abzuschätzen. Das im folgenden dargestellter Verfahren zeigt, wie sich der anfängliche Speicherbedarf für eine geclusterte Menge von Tabellen abschätzen lässt. Dieses Verfahren schätzt ausschließlich den anfänglichen Speicherbedarf ab. Zum Abschätzen des Speicherbedarfs von Clustern sind folgende Schritte auszuführen: Schritt 1: Berechnung der Gesamtgröße des Block-Headers und des für Tabellendaten verfügbaren Speicherplatzes. Schritt 2: Berechnung des Platzbedarfs pro Zeile. Schritt 3: Berechnung der gesamten durchschnittlichen Zeilengröße. Schritt 4: Berechnung der durchschnittlichen Blockgröße für den Cluster. Schritt: 1 Berechnung der Gesamtgröße des Block-Headers und des für Tabellendaten verfügbaren Speicherplatzes. Die folgende Formel liefert als Ergebnis die Menge des in einem Block zur Verfügung stehenden Speicherplatzes: Platz im Block nach Abzug der Header (Platz ohne Header) = DB_BLOCK_SIZE - (KCBH - UB4 - KTBBH - ((INITRANS – 1) * KTBIT – KDBH) DB_BLOCK_SIZEWert erhält man aus der Data Dictionary Tabelle V$PARAMETER SELECT value FROM v$parameter WHERE name = 'db_block_size'; Value = 8192 Byte (8 KByte) KCBH, UB4, KTBBH, KTBIT, KDBH Werte erhält man aus der Data Dictionary Tabelle V$TYPE_SIZE select * from v$type_size; KCBH BLOCK COMMON HEADER 20 Byte UB4 UNSIGNED BYTE 4 Byte KTBBH TRANSACTION FIXED HEADER 48 Byte KTBIT TRANSACTION VARIABLE HEADER 24 Byte KDBH DATA HEADER 14 Byte INITRANS Wert gibt Auskunft darüber, wie viele Transaktionen simultan einen Datenblock updaten können. Dieser Wert ist natürlich abhängig von der Anzahl der User, die gleichzeitig auf einen Block (auf eine Tabelle) zugreifen könnten. Jeder Eintrag für eine Transaktion, die gerade auf einen Block zugreift belegt 24 Bytes freien Speicher des Blockes. Bei der Erstellung eines Indexes, bzw. einer Tabelle wird gleichzeitig auch der INITRANS Wert festgelegt. Default 1 für Tabellen, 2 für Indizes. Mit einer Blockgröße von 8 KByte und dem INITRANS – Wer 1 ergibt sich folgende Rechnung: 8192 – 20 – 4 – 48 – (24 * (1-1)) – 14 = 8106 Byte Schritt 2: Berechnung des Platzbedarfs pro Zeile Zur Berechnung dieses Wertes muss man auf folgendes achten: Platzbedarf muss anhand einer durchschnittlichen Zeile für jede Tabelle im Cluster berechnet werden. Angenommen uns liegen die beiden geclusterten Tabellen vor: 28
CREATE TABLE ORDERS (L_ORDERKEY NUMBER (10, 2) NOT NULL, O_CUSTKEY NUMBER (10, 2) NOT NULL, O_ORDERSTATUS CHAR(1) NOT NULL, O_TOTALPRICE NUMBER (15, 2) NOT NULL, O_ORDERDATE DATE NOT NULL, O_ORDERPRIORITY CHAR(15) NOT NULL, O_CLERK CHAR(15) NOT NULL, O_SHIPPRIORITY NUMBER (10, 2) NOT NULL, O_COMMENT VARCHAR (79) NOT NULL) CLUSTER Cluster_ORDERS_LINEITEM (L_ORDERKEY); CREATE TABLE LINEITEM (L_ORDERKEY NUMBER (10, 2) NOT NULL, L_PARTKEY NUMBER (10, 2) NOT NULL, L_SUPPKEY NUMBER (10, 2) NOT NULL, L_LINENUMBER NUMBER (10, 2) NOT NULL, L_QUANTITY NUMBER (15, 2) NOT NULL, L_EXTENDEDPRICE NUMBER (15, 2) NOT NULL, L_DISCOUNT NUMBER (15, 2) NOT NULL, L_TAX NUMBER (15, 2) NOT NULL, L_RETURNFLAG CHAR(1) NOT NULL, L_LINESTATUS CHAR(1) NOT NULL, L_SHIPDATE DATE NOT NULL, L_COMMITDATE DATE NOT NULL, L_RECEIPTDATE DATE NOT NULL, L_SHIPINSTRUCT CHAR (25) NOT NULL, L_SHIPMODE CHAR (10) NOT NULL, L_COMMENT VARCHAR (44) NOT NULL) CLUSTER Cluster_ORDERS_LINEITEM (L_ORDERKEY); Clusterschlüssel in jeder Tabelle ist L_ORDERKEY. Es ergeben sich zwei folgende Rechnungen: D1 (TABLE LINEITEM) = (a + b + c + d + e + f + g + j + h + I + k + l + m) Byte = 10 + 10 + 10 + 10 + 15 + 15 + 15 + 15 + 25 + 10 + 44 = 179 Byte D2 (TABLE ORDERS) = (n + p + o + q + r + s + t + v) Byte = 10 + 10 + 1 + 15 + 15 + 15 + 10 + 79 = 155 Byte Schritt 3: Berechnung der gesamten durchschnittlichen Zeilengröße. Man kann den in einer geclusterten Tabelle mindestens für eine Zeile benötigten Platz mit folgender Gleichung berechnen: Sn Byte / Zeile = Zeilen – Header + Fn + Vn + Dn Dabei gilt: Zeilen – Header: Vier Byte pro Zeile einer geclusterten Tabelle. Fn: Gesamtanzahl der Längenbytes für Spalten der Tabelle n mit einer Länge von 250 oder weniger Byte. Für jede derartige Spalte wird 1 Längenbyte veranschlagt. Vn: Gesamtanzahl der Längenbytes für Spalten der Tabelle n, in denen mehr als 250 Byte gespeichert werden. Für jede derartige Spalte werden 3 Längenbytes veranschlagt. Dn: Kombinierter Platz für Daten aller Spalten in Tabelle n (aus Schritt 2). Demnach ergibt sich beispielsweise die gesamte durchschnittliche Zeilengröße für die geclusterten Tabellen LINEITEM und ORDERS wie folgt: S1 = (4 + (1 * 13) + (3 * 0) + 179) = 196 Byte 29
S2 = (4 + (1 * 8) + (3 * 0) + 155) = 167 Byte Schritt 4: Berechnung der durchschnittlichen Blockgröße für den Cluster. Zum Berechnen der durchschnittlichen Blockgröße des Clusters muss man zunächst die durchschnittliche Anzahl von Zeilen (für alle Tabellen) pro Clusterschlüssel ermitteln. Sobald dieser Wert bekannt ist, kann folgenden Gleichung benutzt werden, um die durchschnittliche Blockgröße für den Cluster zu berechnen: Durchschn.Cluster – Blockgröße (Byte) = ((R1 * S1) + (R2 * S2) + … + ( Rn * Sn)) + Schlüssel – Header + Ck + Sk + 2Rt. Dabei gilt: Rn: Die durchschnittliche Anzahl von Zeilen in Tabelle n, die einem Clusterschlüssel zugeordnet sind. (select * from lineitem order by l_orderkey) Sn: Die durchschnittliche Zeilengröße in Tabelle n (aus Schritt 3). Schlüssel – Header: Hat den Wert 19. Ck: Die Spaltengröße für den Clusterschlüssel. Sk: Der zum Speichern eines durchschnittlichen Clusterschlüssels benötigte Platz. Rt: Die Gesamtanzahl der Zeilen, die einem durchschnittlichen Clusterschlüssel (R1 + R2 + … + Rn) zugeordnet sind. Daraus ergibt sich der für jede Zeile des Blocks im Header des Datenblocks benötigte Platz. Als Beispiel wurden wieder die Tabellen LINEITEM und ORDERS genommen. Ein durchschnittlicher Clusterschlüssel verfügt über 4 Zeilen pro Tabelle LINEITEM und über 1 pro Tabelle ORDERS. Des weiternen ist der Clusterschlüssel von Datentyp NUMBER (Spaltengröße = 1 Byte) und die Zahl besteht durchschnittlich aus 6 Ziffern (5 Byte). Mit diesen Werten und den vorangegangenen Ergebnissen ergibt sich die durchschnittliche Größe für den Clusterschlüssel wie folgt: Größe = ((3 * 196) + (1 * 167) + 19 + 1 + 5 + (2 * 4)) Byte = 788 Byte Diese ermittelte Größe kann in der SIZE – Klausel angegeben werden, wenn man die Cluster mit Hilfe des CREATE CLUSTER – Befehls erstellt. Dieser Wert gibt an, wie viel Platz benötigt wird, um einen durchschnittlichen Clusterschlüssel und die ihm zugeordneten Zeilen aufzunehmen; Oracle verwendet diesen Wert, um die Anzahl der Clusterschlüssel zu beschränken, die sich einem gegebenen Datenblock zuordnen lassen. 22 2.2.4.7 Tests unter Oracle 10g EE mit Index Cluster Hier wird es versucht Index Cluster unter Tabellen LINEIETEM, ORDERS und NATION, SUPPLIER zu benutzen: CREATE CLUSTER Cluster_ORDERS_LINEITEM (L_ORDERKEY NUMBER (10, 2)) size 788; Als nächstes werden die beiden geclusterten Tabellen LINEIETEM und ORDERS erstellt und zum Schluss wird auf dem CLUSTER Cluster_ORDERS_LINEITEM eine INDEX ORDERS_LINEITEM_INDEX erstellt. CREATE INDEX ORDERS_LINEITEM_INDEX on CLUSTER Cluster_ORDERS_LINEITEM; ________________________ 22 [18] Oracle – Datenbanken Administration und Management 30
Sie können auch lesen