1914 lines
		
	
	
		
			98 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			1914 lines
		
	
	
		
			98 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| # Motivation und Grundlagen
 | ||
| ## Aufgaben und Komponenten eines DBMS
 | ||
| Prinzipien: Die neun Codd’schen Regeln
 | ||
| 1. Integration: einheitliche, nichtredundante Datenverwaltung
 | ||
| 2. Operationen: Speichern, Suchen, Ändern
 | ||
| 3. Katalog: Zugriffe auf Datenbankbeschreibungen im Data Dictionary
 | ||
| 4. Benutzersichten
 | ||
| 5. Integritätssicherung: Korrektheit des Datenbankinhalts
 | ||
| 6. Datenschutz: Ausschluss unauthorisierter Zugriffe
 | ||
| 7. Transaktionen: mehrere DB-Operationen als Funktionseinheit
 | ||
| 8. Synchronisation: parallele Transaktionen koordinieren
 | ||
| 9. Datensicherung: Wiederherstellung von Daten nach Systemfehlern
 | ||
| 
 | ||
| Betrachtete Fragestellung
 | ||
| 
 | ||
| 
 | ||
| **Zentrale Komponenten**
 | ||
| - **Anfrageverarbeitung** : Planung, Optimierung und Ausführung deklarativer Anfragen
 | ||
| - **Transaktionsverwaltung** : Koordination und Synchronisation von Transaktionen, Durchführung von Änderungen, Sicherung der ACID-Eigenschaften
 | ||
| - **Speichersystem** : Organisation der Daten im Hauptspeicher und auf dem Externspeicher für effizienten Zugriff und Persistenz
 | ||
| 
 | ||
| ## Relationale vs. nicht-relationale DBMS
 | ||
| **Relationale DBMS**
 | ||
| - Basis: **Relationenmodell** = Daten in Tabellen strukturiert
 | ||
| - Beziehungen über Werte (= Fremdschlüssel),
 | ||
|     Integritätsbedingungen
 | ||
| - **SQL** als standardisierte Anfragesprache
 | ||
| - kommerziell erfolgreichstes Datenmodell: Oracle, IBM DB2,
 | ||
|     MS SQL Server, SAP HANA, ...
 | ||
| 
 | ||
| | WEINE | WeinID            | Name | Farbe | Jahrgang    | Weingut |
 | ||
| | ----- | ----------------- | ---- | ----- | ----------- | ------- |
 | ||
| | 1042  | La Rose Grand Cru | Rot  | 1998  | Château ... |
 | ||
| | 2168  | Creek Shiraz      | Rot  | 2003  | Creek       |
 | ||
| | 3456  | Zinfandel         | Rot  | 2004  | Helena      |
 | ||
| | 2171  | Pinot Noir        | Rot  | 2001  | Creek       |
 | ||
| | 3478  | Pinot Noir        | Rot  | 1999  | Helena      |
 | ||
| | 4711  | Riesling Reserve  | Weiß | 1999  | Müller      |
 | ||
| | 4961  | Chardonnay        | Weiß | 2002  | Bighorn     |
 | ||
| 
 | ||
| **Kritik an RDBMS / SQL**
 | ||
| - nicht skalierbar
 | ||
|     - Normalisierung von Relationen, viele Integritätsbedingungen zu prüfen
 | ||
|     - kann man in RDBMS auch vermeiden!
 | ||
| - starre Tabellen nicht flexibel genug
 | ||
|     - schwach typisierte Tabellen (Tupel weichen in den tatsächlich genutzten Attributen ab)
 | ||
|           - viele Nullwerte wenn alle potentiellen Attribute definiert
 | ||
|           - alternativ Aufspaltung auf viele Tabellen
 | ||
|           - Schema-Evolution mit **alter table** unflexibel
 | ||
|     - tatsächlich in vielen Anwendungen ein Problem
 | ||
| - Integration von spezifischen Operationen (Graphtraversierung, Datenanalyse-Primitive) mit Stored Procedures zwar möglich führt aber oft zu schwer interpretierbarem Code
 | ||
| 
 | ||
| **NoSQL-Systeme**
 | ||
| - Datenmodelle
 | ||
|     - KV-Stores
 | ||
|     - Wide Column Stores
 | ||
|     - Dokumenten-orientierte Datenhaltung
 | ||
|     - Graph-Speicher
 | ||
|     - ...
 | ||
| - Anfragesprache -> unterschiedliche Ansätze:
 | ||
|     - einfache funktionale API
 | ||
|     - Programmiermodell für parallele Funktionen
 | ||
|     - angelehnt an SQL-Syntax
 | ||
|     - ...
 | ||
| - Beispiele
 | ||
|   - dokumentenorientierte Datenbanksysteme: MongoDB
 | ||
|       - semistrukturierte Dokumente in JSON- bzw. BSON-Format
 | ||
|       - Anfragen: CRUD erweitert um dokumentspezifische Suche
 | ||
|   - Graph-Datenbanksysteme: Neo4j
 | ||
|       - Property Graphen als Datenmodell: Knoten und Kanten mit Eigenschaften
 | ||
|       - Anfragesprache Cypher
 | ||
|       - Muster der Form "Knoten -> Kante -> Knoten ..."
 | ||
| 
 | ||
| ## OLTP, OLAP und HTAP
 | ||
| ### OLTP vs OLAP
 | ||
| |                            | Online Transactional Processing (OLTP)                                            | Online Analytical Processing (OLAP)                          |
 | ||
| | -------------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------ |
 | ||
| |                            | -> Klassische operative Informationssysteme                                       | -> Data Warehouse                                            |
 | ||
| |                            | Erfassung und Verwaltung von Daten                                                | Analyse im Mittelpunkt = entscheidungsunterstützende Systeme |
 | ||
| |                            | Verarbeitung unter Verantwortung der jeweiligen Abteilung                         | Langandauernde Lesetransaktionen auf vielen Datensätzen      |
 | ||
| |                            | Transaktionale Verarbeitung: kurze Lese-/ Schreibzugriffe auf wenigen Datensätzen | Integration, Konsolidierung und Aggregation der Daten        |
 | ||
| |                            | ACID-Eigenschaften                                                                |                                                              |
 | ||
| |                            |                                                                                   |
 | ||
| | **Anfragen**               |                                                                                   |
 | ||
| | Fokus                      | Lesen, Schreiben, Modifizieren, Löschen                                           | Lesen, periodisches Hinzufügen                               |
 | ||
| | Transaktionsdauer und -typ | kurze Lese- / Schreibtransaktionen                                                | langandauernde Lesetransaktionen                             |
 | ||
| | Anfragestruktur            | einfach strukturiert                                                              | komplex                                                      |
 | ||
| | Datenvolumen einer Anfrage | wenige Datensätze                                                                 | viele Datensätze                                             |
 | ||
| | Datenmodell                | anfrageflexibel                                                                   | analysebezogen                                               |
 | ||
| | Antwortzeit                | msecs ...secs                                                                     | secs ...min                                                  |
 | ||
| |                            |                                                                                   |
 | ||
| | **Daten**                  |                                                                                   |
 | ||
| | Datenquellen               | meist eine                                                                        | mehrere                                                      |
 | ||
| | Eigenschaften              | nicht abgeleitet, zeitaktuell, autonom, dynamisch                                 | abgeleitet / konsolidiert, historisiert, integriert, stabil  |
 | ||
| | Datenvolumen               | MByte ...GByte                                                                    | GByte ...TByte ...PByte                                      |
 | ||
| | Zugriffe                   | Einzeltupelzugriff                                                                | Tabellenzugriff (spaltenweise)                               |
 | ||
| 
 | ||
| **OLTP: Beispiel**
 | ||
| ```sql
 | ||
| BEGIN ;
 | ||
| SELECT KundenNr INTO KNr
 | ||
| FROM Kunden WHERE email = '...';
 | ||
| INSERT INTO BESTELLUNG VALUES (KNr, BestNr, 1);
 | ||
| UPDATE Artikel SET Bestand = Bestand-1
 | ||
| WHERE ArtNr = BestNr;
 | ||
| COMMIT TRANSACTION ;
 | ||
| ```
 | ||
| 
 | ||
| **OLAP: Beispiel**
 | ||
| ```sql
 | ||
| SELECT DISTINCT ROW Zeit.Dimension AS Jahr,
 | ||
|     Produkt.Dimension AS Artikel,
 | ||
|     AVG(Fact.Umsatz) AS Umsatzdurchschnitt,
 | ||
|     Ort.Dimension AS Verkaufsgebiet
 | ||
| FROM (Produktgruppe INNER JOIN Produkt ON Produktgruppe.
 | ||
|     [Gruppen-Nr] = Produkt.[Gruppen-ID]) INNER JOIN
 | ||
|     ((((Produkt INNER JOIN [Fact.Umsatz] ON Produkt.[Artikel-Nr]
 | ||
|     = [Fact.Umsatz].[Artikel-Nr]) INNER JOIN Order ON
 | ||
|     [Fact.Umsatz].[Bestell-Nr]= Order.[Order-ID]) INNER JOIN
 | ||
|     Zeit.Dimension ON Orders.[Order-ID] =
 | ||
|     Zeit.Dimension.[Order-ID]) INNER JOIN Ort.Dimension ON
 | ||
|     Order.[Order-ID] = Ort.Dimension.[Order-ID]) ON
 | ||
|     Produktgruppe.[Gruppen-Nr] = Produkt.[Gruppen-ID]
 | ||
| GROUP BY Produkt.Dimension.Gruppenname, Ort.Dimension.Bundesland,
 | ||
| Zeit.Dimension.Jahr;
 | ||
| ```
 | ||
| 
 | ||
| ### HTAP
 | ||
| - HTAP = Hybrid Transactional and Analytics Processing
 | ||
| - Ziel: schnellere Geschäftsentscheidungen durch "Echtzeit"-Verarbeitung
 | ||
| - OLAP und OLTP auf der gleichen Datenbank: naheliegend aber große technische Herausforderung
 | ||
|     - sehr unterschiedliche Workloads (Anfrage- und Lastprofile)
 | ||
|     - Transaktionsverwaltung: gegenseitige Beeinflussung von Änderungs- und Leseoperationen reduzieren
 | ||
|     - unterschiedliche Datenorganisation (physisch, logisch)
 | ||
| - Herausforderungen
 | ||
|   - Analytical (OLAP) und Transactional processing (OLTP)
 | ||
|     - verschiedene Zugriffscharakterisiken
 | ||
|     - verschiedene Performance-Ziele (Latenz vs. Durchsatz)
 | ||
|   - => Unterschiedliche Optimierungen notwendig
 | ||
| 
 | ||
| ## Disk- vs. Main-Memory-Systeme**
 | ||
| **Traditionelle Annahmen**
 | ||
| - Daten sollen dauerhauft aufbewahrt werden
 | ||
| - Datenbank >> Hauptspeicher
 | ||
| - Disk >> Hauptspeicher
 | ||
| - Hauptspeicher = flüchtiger (volatiler) Speicher
 | ||
| - Disk-IO dominiert Kosten
 | ||
| 
 | ||
| **Speicherhierarchie**
 | ||
| 
 | ||
| 
 | ||
| **Eigenschaften von Speichermedien**
 | ||
| |                 | Primär   | Sekundär  | Tertiär      |
 | ||
| | --------------- | -------- | --------- | ------------ |
 | ||
| | Geschwindigkeit | schnell  | langsam   | sehr langsam |
 | ||
| | Preis           | teuer    | preiswert | billig       |
 | ||
| | Stabilität      | flüchtig | stabil    | stabil       |
 | ||
| | Größe           | klein    | groß      | sehr groß    |
 | ||
| | Granulate       | fein     | grob      | grob         |
 | ||
| 
 | ||
| **Speichermedien**
 | ||
| - **Primärspeicher**
 | ||
|     - Primärspeicher: Cache und Hauptspeicher
 | ||
|     - sehr schnell, Zugriff auf Daten fein granular: theoretisch jedes Byte adressierbar (Cachelines)
 | ||
| - **Sekundärspeicher**
 | ||
|     - Sekundärspeicher oder Online-Speicher
 | ||
|     - meist Plattenspeicher, nicht-flüchtig
 | ||
|     - Granularität des Zugriffs gröber: Blöcke, oft 512 Bytes
 | ||
|     - Zugriffslücke: Faktor 10^5 langsamerer Zugriff
 | ||
| - **Tertiärspeicher**
 | ||
|     - Zur langfristigen Datensicherung (Archivierung) oder kurzfristigen Protokollierung (Journale)
 | ||
|     - üblich: optische Platten, Magnetbänder
 | ||
|     - "Offline-Speicher" meist Wechselmedium
 | ||
|     - Nachteil: Zugriffslücke extrem groß
 | ||
| 
 | ||
| 
 | ||
| **Transferraten HDD vs. SSD**
 | ||
| 
 | ||
| 
 | ||
| **Konsequenz für disk-basierte Systeme**
 | ||
| - blockbasierter Zugriff mit typischen Blockgrößen ≥ 4 KB
 | ||
| - speziell für Magnetplatten Optimierung auf sequentielle Zugriffe
 | ||
|        - Disklayout: Organisation der Daten auf der Disk = fortlaufende Folge von Blöcken
 | ||
|        - sequentielles Lesen und Schreiben
 | ||
| - Zugriffslücke zwischen Hauptspeicher und Disk durch Caching verbergen (Lokalität von Zugriffen ausnutzen)
 | ||
| 
 | ||
| **Main-Memory-Datenbanken**
 | ||
| - klassische Annahmen nicht mehr zutreffend:
 | ||
|     - Systeme mit Hauptspeicher im TB-Bereich verfügbar
 | ||
|     - Datenbank kann komplett im Hauptspeicher gehalten werden (muss aber dennoch persistent sein)
 | ||
| - **Main-Memory-** oder **Hauptspeicher-** Datenbanken: Ausnutzung der großen Hauptspeicher und Multicore-Architekturen
 | ||
|        - Beispiele: SAP HANA, Oracle TimesTen, SQL Server Hekaton, Hyper, MemSQL, ...
 | ||
|        - Besonderheiten: hauptspeicheroptimierte Datenstrukturen (Main-Memory-Scans), Persistenz trotz volatilem Speicher, Datenkompression, Nebenläufigkeitskontrolle
 | ||
| 
 | ||
| 
 | ||
| ## Klassische 5-Schichtenarchitektur
 | ||
| **Fünf-Schichtenarchitektur**
 | ||
| - Architektur für klassische DBMS
 | ||
| - basierend auf Idee von Senko 1973
 | ||
| - Weiterentwicklung von Härder 1987
 | ||
| - Umsetzung im Rahmen des IBM-Prototyps _System R_
 | ||
| - genauere Beschreibung der Transformationskomponenten
 | ||
|     - schrittweise Transformation von Anfragen/Änderungen bis hin zu Zugriffen auf Speichermedien
 | ||
|     - Definition der Schnittstellen zwischen Komponenten
 | ||
| 
 | ||
| **5-Schichtenarchitektur: Funktionen**
 | ||
| 
 | ||
| 
 | ||
| **5-Schichtenarchitektur: Objekte**
 | ||
| 
 | ||
| 
 | ||
| Erläuterungen
 | ||
| - mengenorientierte Schnittstelle **MOS** :
 | ||
|     - deklarative Datenmanipulationssprache auf Tabellen und Sichten (etwa SQL)
 | ||
| - durch Datensystem auf satzorientierte Schnittstelle **SOS** umgesetzt:
 | ||
|        - navigierender Zugriff auf interner Darstellung der Relationen
 | ||
|        - manipulierte Objekte: typisierte Datensätze und interne Relationen sowie logische Zugriffspfade (Indexe)
 | ||
|        - Aufgaben des Datensystems: Übersetzung und Optimierung von SQL-Anfragen
 | ||
| - durch Zugriffssystem auf interne Satzschnittstelle **ISS** umgesetzt:
 | ||
|        - interne Tupel einheitlich verwalten, ohne Typisierung
 | ||
|        - Speicherstrukturen der Zugriffspfade (konkrete Operationen auf B+-Bäumen und Hashtabellen), Mehrbenutzerbetrieb mit Transaktionen
 | ||
| - durch Speichersystem Datenstrukturen und Operationen der ISS auf interne Seiten eines virtuellen linearen Adressraums umsetzen
 | ||
|        - Manipulation des Adressraums durch Operationen der Systempufferschnittstelle **SPS**
 | ||
|        - Typische Objekte: interne Seiten, Seitenadressen
 | ||
|        - Typische Operationen: Freigeben und Bereitstellen von Seiten, Seitenwechselstrategien, Sperrverwaltung, Schreiben des Logs
 | ||
| - durch Pufferverwaltung interne Seiten auf Blöcke der Dateischnittstelle **DS** abbilden
 | ||
|        - Umsetzung der DS-Operationen auf Geräteschnittstelle erfolgt durch BS
 | ||
| 
 | ||
| ## Neue Entwicklungen
 | ||
| Anforderungen aus neuen Anwendungen
 | ||
| - Nicht-Standard-Datenmodelle (siehe NoSQL-Systeme)
 | ||
| - flexibler Umgang mit Datenstrukturen (JSON, Schema on Read, ...)
 | ||
| - beschränkte (Lookups) vs. erweiterte (z.B. Graphoperationen, Datenanalysen) Anfragefunktionalität
 | ||
| - Skalierbarkeit zu Big Data (massiv parallele/verteilte Systeme)
 | ||
| - dynamische Daten / Datenströme
 | ||
| - ...
 | ||
| 
 | ||
| **Entwicklungen im Hardware-Bereich**
 | ||
| - Multicore- und Manycore-Prozessoren: 64+ Cores
 | ||
|     - Nutzung erfordert Parallelisierungstechniken und Nebenläufigkeitskontrolle
 | ||
| - Memory Wall: Hauptspeicherzugriff als Flaschenhals
 | ||
|     - RAM-Zugriff 60 ns, L1-Cache: 4 CPU-Zyklen -> Cache-optimierte Strukturen
 | ||
| - Datenbank-Accelerators
 | ||
|     - Hardware-unterstütztes Datenmanagement: FPGA, GPU als Coprozessoren, Highspeed-Netzwerk, SSDs als zusätzliche Cache-Ebene, ...
 | ||
| - Persistenter Memory: nicht-volatiler Speicher
 | ||
|     - Instant Restart / Recovery von Main-Memory-Datenbanken
 | ||
| 
 | ||
| **Zusammenfassung**
 | ||
| - Datenmanagementfunktionalitäten in vielen Softwaresystemen erforderlich
 | ||
| - nicht auf Implementierung kompletter DBMS beschränkt, sondern für nahezu alle datenintensiven Systeme: auch in Suchmaschinen, Datenanalyseanwendungen, eingebetteten Systemen, Visualisierungssystemen, Steuerungssystemen, Entwicklungsumgebungen, ...
 | ||
| - gemeinsame Aufgaben / Komponenten: Datenorganisation und -verwaltung (Indexstrukturen), Transaktionsverwaltung / Nebenläufigkeitskontrolle / Recovery, Anfrageverarbeitung
 | ||
| - betrifft Datenstrukturen und Algorithmen
 | ||
| 
 | ||
| # Speicherstrukturen für Datenbanken
 | ||
| ## Speicher- und Sicherungsmedien
 | ||
| Speichermedien
 | ||
| - verschiedene Zwecke:
 | ||
|     - Daten zur Verarbeitung bereitstellen
 | ||
|     - Daten langfristig speichern (und trotzdem schnell verfügbar halten)
 | ||
|     - Daten sehr langfristig und preiswert archivieren unter Inkaufnahme etwas längerer Zugriffszeiten
 | ||
| - Speicherhierarchie:
 | ||
|     1. Extrem schneller Prozessor mit Registern
 | ||
|     2. Sehr schneller Cache-Speicher
 | ||
|     3. Schneller Hauptspeicher
 | ||
|     4. Langsamer Sekundärspeicher mit wahlfreiem Zugriff
 | ||
|     5. Sehr langsamer Nearline-Tertiärspeicher bei dem die Speichermedien automatisch bereitgestellt werden
 | ||
|     6. Extrem langsamer Offline-Tertiärspeicher, bei dem die Speichermedien per Hand bereitgestellt werden
 | ||
| 
 | ||
| Zugriffslücke in Zahlen
 | ||
| - Zugriffslücke: Unterschiede in den Zugriffsgeschwindigkeiten auf den verschiedenen Speicherebenen
 | ||
| 
 | ||
| | Speicherart              | Zugriffszeit | CPU cycles | typische Kapazität         |
 | ||
| | ------------------------ | ------------ | ---------- | -------------------------- |
 | ||
| | CacheSpeicher            | 6 ns         | 12         | 256 KB (L2) bis 32 MB (L3) |
 | ||
| | Hauptspeicher            | 60 ns        | 120        | 1 GB bis 1.5 TB            |
 | ||
| | Zugriffslücke $10^5$     |              |            |
 | ||
| | Magnetplattenspeicher    | 8-12 ms      | 16*10^6    | 160 GB bis 4 TB            |
 | ||
| | Platten-Farm oder -Array | 12 ms        | 24*10^6    | im TB- bis PB-Bereich      |
 | ||
| 
 | ||
| Typische Merkmale von Sekundärspeicher
 | ||
| | Merkmal         | Kapazität | Latenz  | Bandbreite           |
 | ||
| | --------------- | --------- | ------- | -------------------- |
 | ||
| | 1983            | 30 MB     | 48.3 ms | 0.6 MB/s             |
 | ||
| | 1994            | 4.3 GB    | 12.7 ms | 9 MB/s               |
 | ||
| | 2003            | 73.4 GB   | 5.7 ms  | 86 MB/s              |
 | ||
| | 2009            | 2 TB      | 5.1 ms  | 95 MB/s              |
 | ||
| | 2019 SSD (NVMe) | 2 TB      | ??      | seq.read 3.500 MB/s  |
 | ||
| |                 |           | ??      | seq.write 1.600 MB/s |
 | ||
| 
 | ||
| Solid State Disk (SSD)
 | ||
| - basierend auf EEPROMs in NAND- oder NOR-Technologie
 | ||
| - Arrays (=Flash-Block mit ca. 128 KB) von Speicherzellen, entweder ein Bit (SLC) oder 2-4 Bit (MLC)
 | ||
| - MLC sind langsamer und haben verkürzte Lebensdauer
 | ||
| - initial ist jedes Bit auf 1 gesetzt, durch Reprogrammieren auf 0
 | ||
| - Löschen zurück auf 1 nur für ganzen Block
 | ||
| - Konsequenz: langsames Löschen (Lesen = 25 μs, Löschen = 2 ms), begrenzte Lebensdauer (ca. 100.000    Lösch-Schreib-Zyklen)
 | ||
| - Schnittstelle: SATA oder PCIe (NVMe)
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| SSDs in DBMS
 | ||
| - klassische, auf sequenzielles Lesen ausgerichtete, Strategien von DBMS nutzen die Stärken von Flash-Speicher nicht aus
 | ||
| - kleinere Blockgrößen lassen sich effizient adressieren, sollten aber ein Vielfaches der Flash-Seiten sein
 | ||
| - wahlfreie Lesezugriffe sind effizienter als auf Magnetplatten, sollten aber auf Größen von ca. 4 bis 16 MB begrenzt werden
 | ||
| - konkurrierende IO-Zugriffe sind bis zu einem gewissen Maße ohne negativen Performanzeinfluss durchführbar
 | ||
| 
 | ||
| **Speicherarrays: RAID**
 | ||
| - Kopplung billiger Standardplatten unter einem speziellen Controller zu einem einzigen logischen Laufwerk
 | ||
| - Verteilung der Daten auf die verschiedenen physischen Festplatten übernimmt Controller
 | ||
| - zwei gegensätzliche Ziele:
 | ||
|     - Erhöhung der Fehlertoleranz (Ausfallsicherheit, Zuverlässigkeit) durch Redundanz
 | ||
|     - Effizienzsteigerung durch Parallelität des Zugriffs
 | ||
| 
 | ||
| Erhöhung der Fehlertoleranz
 | ||
| - Nutzung zusätzlicher Platten zur Speicherung von Duplikaten (Spiegeln) der eigentlichen Daten => bei Fehler: Umschalten auf Spiegelplatte
 | ||
| - bestimmte RAID-Levels (1, 0+1) erlauben eine solche Spiegelung
 | ||
| - Alternative: Kontrollinformationen wie Paritätsbits nicht im selben Sektor wie die Originaldaten, sondern auf einer anderen Platte speichern
 | ||
| - RAID-Levels 2 bis 6 stellen durch Paritätsbits oder Error Correcting Codes (ECC) fehlerhafte Daten wieder her
 | ||
| - ein Paritätsbit kann einen Plattenfehler entdecken und bei Kenntnis der fehlerhaften Platte korrigieren
 | ||
| 
 | ||
| Erhöhung der Effizienz
 | ||
| - Datenbank auf mehrere Platten verteilen, die parallel angesteuert werden können => Zugriffszeit auf große Datenmengen verringert sich fast linear mit der Anzahl der verfügbaren Platten
 | ||
| - Verteilung: bit-, byte- oder blockweise
 | ||
| - höhere RAID-Levels (ab Level 3) verbinden Fehlerkorrektur und block- oder bitweises Verteilen von Daten
 | ||
| - Unterschiede:
 | ||
|     - schnellerer Zugriff auf bestimmte Daten
 | ||
|     - höherer Durchsatz für viele parallel anstehende Transaktionen durch eine Lastbalancierung des Gesamtsystems
 | ||
| 
 | ||
| 
 | ||
| RAID-Levels
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| | Level | Striping blockweise | Striping bitweise | Kopie | Parität | Parität dedizierte Platte | Parität verteilt | Erkennen mehrerer Fehler |
 | ||
| | ----- | ------------------- | ----------------- | ----- | ------- | ------------------------- | ---------------- | ------------------------ |
 | ||
| | 0     | √                   |
 | ||
| | 1     |                     |                   | √     |
 | ||
| | 0+1   | √                   |                   | √     |
 | ||
| | 2     |                     | √                 |       | √       |
 | ||
| | 3     |                     | √                 |       | √       | √                         |
 | ||
| | 4     | √                   |                   |       | √       | √                         |
 | ||
| | 5     | √                   |                   |       | √       |                           | √                |
 | ||
| | 6     | √                   |                   |       | √       |                           |                  | √                        |
 | ||
| 
 | ||
| **Sicherungsmedien: Tertiärspeicher**
 | ||
| - weniger oft benutzte Teile der Datenbank, die eventuell sehr großen Umfang haben (Text, Multimedia) "billiger" speichern als auf Magnetplatten
 | ||
| - aktuell benutzte Datenbestände zusätzlich sichern (archivieren)
 | ||
| - Tertiärspeicher: Medium austauschbar
 | ||
|     - offline: Medien manuell wechseln (optische Platten, Bänder)
 | ||
|     - nearline: Medien automatisch wechseln (_Jukeboxes_, _Bandroboter_)
 | ||
| 
 | ||
| Langzeitarchivierung
 | ||
| - Lebensdauer, Teilaspekte:
 | ||
| - physische Haltbarkeit des Mediums garantiert die Unversehrtheit der Daten: 
 | ||
|   - 10 Jahre für Magnetbänder, 
 | ||
|   - 30 Jahre für optische Platten, 
 | ||
|   - Papier???
 | ||
| - Vorhandensein von Geräten und Treibern garantiert die Lesbarkeit von Daten: 
 | ||
|   - Geräte für Lochkarten oder 8-Zoll-Disketten?
 | ||
| - zur Verfügung stehende Metadaten garantieren die Interpretierbarkeit von Daten
 | ||
| - Vorhandensein von Programmen, die auf den Daten arbeiten können, garantieren die Wiederverwendbarkeit von Daten
 | ||
| 
 | ||
| 
 | ||
| ## Struktur des Hintergrundspeichers
 | ||
| Verwaltung des Hintergrundspeichers
 | ||
| - Abstraktion von Speicherungs- oder Sicherungsmediums
 | ||
| - Modell: Folge von Blöcken
 | ||
|     
 | ||
| - Alternativen:
 | ||
|     - jede Relation oder jeder Zugriffspfad in genau einer Betriebssystem-Datei
 | ||
|     - ein oder mehrere BS-Dateien, DBS verwaltet Relationen und Zugriffspfade selbst innerhalb dieser Dateien
 | ||
|     - DBS steuert selbst Magnetplatte an und arbeitet mit den Blöcken in ihrer Ursprungsform ( _raw device_ )
 | ||
| - Warum nicht immer BS-Dateiverwaltung?
 | ||
|     - Betriebssystemunabhängigkeit
 | ||
|     - In 32-Bit-Betriebssystemen: Dateigröße 4 GB maximal
 | ||
|     - BS-Dateien auf maximal einem Medium
 | ||
|     - betriebssystemseitige Pufferverwaltung von Blöcken des Sekundärspeichers im Hauptspeicher genügt nicht den Anforderungen des Datenbanksystems
 | ||
| 
 | ||
| Blöcke und Seiten
 | ||
| - Zuordnung der physischen Blöcke zu Seiten
 | ||
| - meist mit festen Faktoren: 1, 2, 4 oder 8 Blöcke einer Spur auf eine Seite
 | ||
| - hier: "ein Block — eine Seite"
 | ||
| - höhere Schichten des DBS adressieren über Seitennummer
 | ||
| 
 | ||
| Dienste des Dateisystems
 | ||
| - Allokation oder Deallokation von Speicherplatz
 | ||
| - Holen oder Speichern von Seiteninhalten
 | ||
| - Allokation möglichst so, dass logisch aufeinanderfolgende Datenbereiche (etwa einer Relation) auch möglichst in aufeinanderfolgenden Blöcken der Platte gespeichert werden
 | ||
| - Nach vielen Update-Operationen: Reorganisationsmethoden
 | ||
| - Freispeicherverwaltung: doppelt verkettete Liste von Seiten
 | ||
| 
 | ||
| Abbildung der Datenstrukturen
 | ||
| - Abbildung der konzeptuellen Ebene auf interne Datenstrukturen
 | ||
| - Unterstützung durch Metadaten (im Data Dictionary, etwa das interne Schema)
 | ||
| 
 | ||
| | Konz. Ebene      | Interne Ebene   | Dateisystem/Platte |
 | ||
| | ---------------- | --------------- | ------------------ |
 | ||
| | Relationen ->    | Log. Dateien -> | Phys. Dateien      |
 | ||
| | Tupel ->         | Datensätze ->   | Seiten/Blöcke      |
 | ||
| | Attributwerte -> | Felder ->       | Bytes              |
 | ||
| 
 | ||
| - Beispiel: jede Relation in je einer logischen Datei, diese insgesamt in einer einzigen physischen Datei
 | ||
| 
 | ||
| 
 | ||
| ## Seiten, Sätze und Adressierung
 | ||
| ### Seite
 | ||
| - Block:
 | ||
|     - kleinste adressierbare Einheit auf Externspeicher
 | ||
|     - Zuordnung zu Seiten im Hauptspeicher
 | ||
| - Aufbau von Seiten
 | ||
|     - Header
 | ||
|        - Informationen über Vorgänger- und Nachfolger-Seite
 | ||
|        - eventuell auch Nummer der Seite selbst
 | ||
|        - Informationen über Typ der Sätze
 | ||
|        - freier Platz
 | ||
|     - Datensätze
 | ||
|     - unbelegte Bytes
 | ||
| 
 | ||
| Seitenorganisation
 | ||
| - Organisation der Seiten: doppelt verkettete Liste
 | ||
| - freie Seiten in Freispeicherverwaltung
 | ||
| 
 | ||
| 
 | ||
| Seite: Adressierung der Datensätze
 | ||
| - adressierbare Einheiten
 | ||
|     - Zylinder
 | ||
|     - Spuren
 | ||
|     - Sektoren
 | ||
|     - Blöcke oder Seiten
 | ||
|     - Datensätze in Blöcken oder Seiten
 | ||
|     - Datenfelder in Datensätzen
 | ||
| - Beispiel: Adresse eines Satzes durch Seitennummer und Offset (relative Adresse in Bytes vom Seitenanfang)
 | ||
| 
 | ||
| Seitenzugriff als Flaschenhals
 | ||
| - Maß für die Geschwindigkeit von Datenbankoperationen: Anzahl der Seitenzugriffe auf dem Sekundärspeicher (wegen Zugriffslücke)
 | ||
| - Faustregel: Geschwindigkeit des Zugriffs ⇐ Qualität des Zugriffspfades ⇐ Anzahl der benötigten Seitenzugriffe
 | ||
| - Hauptspeicheroperationen nicht beliebig vernachlässigbar
 | ||
| 
 | ||
| 
 | ||
| Einpassen von Datensätzen auf Blöcke
 | ||
| - Datensätze (eventuell variabler Länge) in die aus einer fest vorgegebenen Anzahl von Bytes bestehenden Blöcke einpassen: Blocken
 | ||
| - Blocken abhängig von variabler oder fester Feldlänge der Datenfelder
 | ||
|        - Datensätze mit variabler Satzlänge: höherer Verwaltungsaufwand beim Lesen und Schreiben, Satzlänge immer wieder neu ermitteln
 | ||
|        - Datensätze mit fester Satzlänge: höherer Speicheraufwand
 | ||
| 
 | ||
| Verschiedene Satztypen
 | ||
| 
 | ||
| 
 | ||
| Sätze fester Länge
 | ||
| - SQL: Datentypen fester und variabler Länge
 | ||
|     - _char(n)_ Zeichenkette der festen Länge _n_
 | ||
|     - _varchar(n)_ Zeichenkette variabler Länge mit der Maximallänge _n_
 | ||
| - Aufbau der Datensätze, falls alle Datenfelder feste Länge:
 | ||
|     1. Verwaltungsblock mit Typ eines Satzes (wenn unterschiedliche Satztypen auf einer Seite möglich) und Löschbit
 | ||
|     2. Freiraum zur Justierung des Offset
 | ||
|     3. Nutzdaten des Datensatzes
 | ||
| 
 | ||
| Sätze variabler Länge
 | ||
| - im Verwaltungsblock nötig: Satzlänge _l_, um die Länge des Nutzdaten-Bereichs _d_ zu kennen
 | ||
|     
 | ||
| - Strategie a)
 | ||
|     
 | ||
| - Strategie b)
 | ||
|     
 | ||
| 
 | ||
| Speicherung von Sätzen variabler Länge
 | ||
| - Strategie a): Jedes Datenfeld variabler Länge $A_i$ beginnt mit einem _Längenzeiger $al_i$, der angibt, wie lang das folgende Datenfeld ist
 | ||
| - Strategie b): Am Beginn des Satzes wird nach dem Satz-Längenzeiger _l_ und der Anzahl der Attribute ein Zeigerfeld $ap_1 ,..., ap_n$ für alle variabel langen Datenfelder eingerichtet
 | ||
| - Vorteil Strategie b): leichtere Navigation innerhalb des Satzes (auch für Sätze in Seiten => TID)
 | ||
| 
 | ||
| Anwendung variabel langer Datenfelder
 | ||
| - "Wiederholgruppen": Liste von Werten des gleichen Datentyps
 | ||
|        - Zeichenketten variabler Länge wie _varchar(n)_ sind Wiederholgruppe mit _char_ als Basisdatentyp, mathematisch also die Kleene’sche Hülle $(char)∗$
 | ||
|        - Mengen- oder listenwertige Attributwerte, die im Datensatz selbst denormalisiert gespeichert werden sollen (Speicherung als geschachtelte Relation oder Cluster-Speicherung), bei einer Liste von _integer_ -Werten wäre dies $(integer)∗$
 | ||
|        - Adressfeld für eine Indexdatei, die zu einem Attributwert auf mehrere Datensätze zeigt (Sekundärindex), also $(pointer)∗$
 | ||
| 
 | ||
| Blockungstechniken: Nichtspannsätze
 | ||
| - jeder Datensatz in maximal einem Block
 | ||
|     
 | ||
| - Standardfall (außer bei BLOBs oder CLOBs)
 | ||
| 
 | ||
| Blockungstechniken: Spannsätze
 | ||
| - Spannsätze: Datensatz eventuell in mehreren Blöcken
 | ||
|     
 | ||
| 
 | ||
| Adressierungstechniken
 | ||
| 
 | ||
| 
 | ||
| Adressierung: TID-Konzept
 | ||
| - Tupel-Identifier (TID) ist Datensatz-Adresse bestehend aus Seitennummer und Offset
 | ||
| - Offset verweist innerhalb der Seite bei einem Offset-Wert von _i_ auf den _i_ -ten Eintrag in einer Liste von Tupelzeigern (Satzverzeichnis), die am Anfang der Seite stehen
 | ||
| - Jeder Tupel-Zeiger enthält Offsetwert
 | ||
| - Verschiebung auf der Seite: sämtliche Verweise von außen bleiben unverändert
 | ||
| - Verschiebungen auf eine andere Seite: statt altem Datensatz neuer TID-Zeiger
 | ||
| - diese zweistufige Referenz aus Effizienzgründen nicht wünschenswert: Reorganisation in regelmäßigen Abständen
 | ||
| 
 | ||
| 
 | ||
| TID-Konzept: einstufige Referenz
 | ||
| 
 | ||
| 
 | ||
| TID-Konzept: zweistufige Referenz
 | ||
| 
 | ||
| 
 | ||
| ## Alternative Speichermodelle
 | ||
| - bisher klassisches N-äres Speichermodell (NSM), auch "row store"
 | ||
| - Vorteile:
 | ||
|     - gesamter Datensatz kann mit einem Seitenzugriff gelesen werden
 | ||
|     - leichte Änderbarkeit einzelner Attributwerte
 | ||
| - Nachteil:
 | ||
|     - werden nur wenige Attributwerte benötigt, müssen trotzdem immer alle Attributwerte gelesen werden -> unnötiger IO-Aufwand
 | ||
| - Alternativen: spaltenorientierte Speichermodelle
 | ||
|     - Zerlegung einer _n_ -stelligen Relation in eine Menge von Projektionen (z.B. binäre Relation)
 | ||
|     - Identifikation (und Rekonstruktion) über eine Schlüsselspalte oder Position
 | ||
| 
 | ||
| Spaltenorientierte Datenorganisation
 | ||
| 
 | ||
| 
 | ||
| Alternative Speichermodelle: DSM
 | ||
| - Decomposition Storage Model (DSM) -> column stores
 | ||
|     - alle Werte einer Spalte (Attribut) werden hintereinander gespeichert
 | ||
|     - Adressierung über Position
 | ||
|         
 | ||
| - Kompression einfach möglich (z.B. Run length encoding)
 | ||
| - effizientere Scanoperationen (Feldoperationen -> bessere Cache-Nutzung)
 | ||
| - jedoch: Updateoperationen sind komplexer, Lesen aller Spalten aufwendiger
 | ||
| - Einsatz bei leseoptimierten Datenbanken
 | ||
| 
 | ||
| Ein Full-Table-Scan in NSM
 | ||
| - Im NSM-Modell stehen alle Tupel einer Tabelle sequenziell hintereinander auf einer Datenbankseite.
 | ||
|   
 | ||
| 
 | ||
| Ein "Full-Table-Scan" in DSM
 | ||
| - Im DSM-Modell stehen alle Werte eines Attributs sequenziell hintereinander auf einer Datenbankseite.
 | ||
|     
 | ||
| - Alle Daten, die für den "l_shipdate Scan" geladen werden sind
 | ||
| auch dafür relevant.
 | ||
| 
 | ||
| Alternative Speichermodelle: PAX
 | ||
| - Partition Attributes Across (PAX) als Kompromiss
 | ||
|     - NSM: alle Spalten eines Satzes auf der gleichen Seite
 | ||
|     - DSM: vertikale Partitionierung, Miniseiten für jeweils eine Spalte
 | ||
|     
 | ||
| 
 | ||
| ## Main-Memory-Strukturen
 | ||
| Speicherstrukturen für Main-Memory-Datenbanken
 | ||
| - Vermeidung der seiten-basierten Indirektion (über Seitenadresse, Puffer)
 | ||
| - Hauptspeicherzugriffe als neuer Bottleneck ("Memory Wall")
 | ||
| - Cache-freundliche Datenstruktur: Hauptspeicherzugriffe tatsächlich nicht byteweise, sondern in Cachelines (64 Bytes)
 | ||
| - Speicherlayout: Row Store vs. Column Store - abhängig vom Workload (Reduzierung der Cache Misses)
 | ||
| - ggf. Partitionierung für Multicore-Systeme
 | ||
| - Kompression der Daten zur Reduktion des Speicherbedarfs
 | ||
| - Persistenz weiterhin notwendig, z.B. über Logging
 | ||
| - Bsp.: In-Memory-Datenstruktur für relationale Column Stores
 | ||
|        - pro Spalte = Feld von Attributwerten
 | ||
|        - Kompression der Attributwerte (siehe Kapitel 8)
 | ||
|        - ggf. Strukturierung in Segmemten (Chunks) für bessere Speicherverwaltung, NUMA-Effekte
 | ||
| 
 | ||
| 
 | ||
| ## Speicherorganisation in konkreten DBMS
 | ||
| Oracle: Datenbankstruktur
 | ||
|     
 | ||
| 
 | ||
| Oracle: Blöcke
 | ||
|     
 | ||
| 
 | ||
| Oracle: Aufbau von Datensätzen
 | ||
|     
 | ||
| - Kettadresse für _Row Chaining_ : Verteilung und Verkettung zu großer Datensätze (> 255 Spalten) über mehrere Blöcke
 | ||
| - row id = (data object identifier, data file identifier, block identifier, row identifier)
 | ||
| 
 | ||
| Zusammenfassung
 | ||
| - Speicherhierarchie und Zugriffslücke
 | ||
| - Speicher- und Sicherungsmedien
 | ||
| - Hintergrundspeicher: Blockmodell
 | ||
| - Einpassen von Sätzen in Seiten
 | ||
| - Satzadressierung: TID-Konzept
 | ||
| 
 | ||
| # Caching und Pufferverwaltung
 | ||
| ## Aufgaben
 | ||
| Aufgaben der Pufferverwaltung
 | ||
| - Puffer: ausgezeichneter Bereich des Hauptspeichers
 | ||
| - in Pufferrahmen gegliedert, jeder Pufferrahmen kann Seite der Platte aufnehmen
 | ||
| - Aufgaben:
 | ||
|     - Pufferverwaltung muss angeforderte Seiten im Puffer suchen => effizienteSuchverfahren
 | ||
|     - parallele Datenbanktransaktionen: geschickte Speicherzuteilung im Puffer
 | ||
|     - Puffer gefüllt: adäquate Seitenersetzungsstrategien
 | ||
|     - Unterschiede zwischen einem Betriebssystem-Puffer und _einem Datenbank-Puffer_
 | ||
|     - spezielle Anwendung der Pufferverwaltung: Schattenspeicherkonzept
 | ||
| 
 | ||
| 
 | ||
| Mangelnde Eignung des BS-Puffers
 | ||
| - Natürlicher Verbund von Relationen $a$ und $b$ (zugehörige Folge von Seiten: _Ai_ bzw. _Bj_ )
 | ||
| - Implementierung: _Nested-Loop_
 | ||
|     
 | ||
| - Ablauf
 | ||
|     - FIFO: $A_1$ verdrängt, da älteste Seite im Puffer
 | ||
|     - LRU: $A_1$ verdrängt, da diese Seite nur im ersten Schritt beim Auslesen des ersten Vergleichstupels benötigt wurde
 | ||
| - Problem
 | ||
|     - im nächsten Schritt wird das zweite Tupel von $A_1$ benötigt
 | ||
|     - weiteres "Aufschaukeln": um $A_1$ laden zu können, muss $B_1$ entfernt werden (im nächsten Schritt benötigt) usw.
 | ||
| 
 | ||
| ## Suche von Seiten und Speicherzuteilung
 | ||
| Suchen einer Seite
 | ||
| - Direkte Suche:
 | ||
|     - ohne Hilfsmittel linear im Puffer suchen
 | ||
| - Indirekte Suche:
 | ||
|     - Suche nur noch auf einer kleineren Hilfsstruktur
 | ||
|     - _unsortierte und sortierte Tabelle_ : alle Seiten im Puffer vermerkt
 | ||
|     - _verkettete Liste_ : schnelleres sortiertes Einfügen möglich
 | ||
|     - _Hashtabelle_ : bei geschickt gewählter Hashfunktion günstigster Such- und Änderungsaufwand
 | ||
| 
 | ||
| 
 | ||
| Speicherzuteilung im Puffer
 | ||
| - bei mehreren parallel anstehenden Transaktionen
 | ||
|     - Lokale Strategien: Jeder Transaktion bestimmte disjunkte Pufferteile verfügbar machen (Größe statisch vor Ablauf der Transaktionen oder dynamisch zur Programmlaufzeit entscheiden)
 | ||
|     - Globale Strategien: Zugriffsverhalten aller Transaktionen insgesamt bestimmt Speicherzuteilung (gemeinsam von mehreren Transaktionen referenzierte Seiten können so besser berücksichtigt werden)
 | ||
|     - Seitentypbezogene Strategien: Partition des Puffers: Pufferrahmen für Datenseiten, Zugriffspfadseiten, Data-Dictionary-Seiten, usw. - eigene Ersetzungstrategien für die jeweiligen Teile möglich
 | ||
| 
 | ||
| ## Seitenersetzungsstrategien
 | ||
| - Speichersystem fordert Seite $E_2$ an, die nicht im Puffer vorhanden ist
 | ||
| - Sämtliche Pufferrahmen sind belegt
 | ||
| - vor dem Laden von _E_ 2 Pufferrahmen freimachen
 | ||
| - nach den unten beschriebenen Strategien Seite aussuchen
 | ||
| - Ist Seite in der Zwischenzeit im Puffer verändert worden, so wird sie nun auf Platte zurückgeschrieben
 | ||
| - Ist Seite seit Einlagerung in den Puffer nur gelesen worden, so kann sie überschrieben werden (verdrängt)
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| Seitenersetzung in DBMS
 | ||
| - Fixieren von Seiten (Pin oder Fix):
 | ||
|     - Fixieren von Seiten im Puffer verhindert das Verdrängen
 | ||
|     - speziell für Seiten, die in Kürze wieder benötigt werden
 | ||
| - Freigeben von Seiten (Unpin oder Unfix):
 | ||
|     - Freigeben zum Verdrängen
 | ||
|     - speziell für Seiten, die nicht mehr benötigt werden
 | ||
| - Zurückschreiben einer Seite:
 | ||
|     - Auslösen des Zurückschreibens für geänderte Seiten bei Transaktionsende
 | ||
| 
 | ||
| Seitenersetzung: Verfahren
 | ||
| - grundsätzliches Vorgehen beim Laden einer Seite:
 | ||
|     - Demand-paging-Verfahren: genau eine Seite im Puffer durch angeforderte Seite ersetzen
 | ||
|     - Prepaging-Verfahren: neben der angeforderten Seite auch weitere Seiten in den Puffer einlesen, die eventuell in der Zukunft benötigt werden (z.B. bei BLOBs sinnvoll)
 | ||
| - Ersetzen einer Seite im Puffer:
 | ||
|     - optimale Strategie: Welche Seite hat maximale Distanz zu ihrem nächsten Gebrauch? (nicht realisierbar, zukünftiges Referenzverhalten nicht vorhersehbar) -> Realisierbare Verfahren besitzen keine Kenntnisse über das zukünftige Referenzverhalten
 | ||
|     - Zufallsstrategie: jeder Seite gleiche Wiederbenutzungswahrscheinlichkeit zuordnen
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| Fehlseitenrate
 | ||
| $$F=1-p(\frac{1-F_{kalt}}{p_{DB}}) * 100%$$
 | ||
| - $p$: Puffergröße
 | ||
| - $p_{DB}$: Puffergröße, die gesamte Datenbank umfasst
 | ||
| - $F_{kalt}$: Fehlseitenrate beim Kaltstart (d.h. leerer Puffer) -> Verhältnis von Anzahl der in den Puffer geladenen Seiten zur Anzahl der Referenzierungen
 | ||
| 
 | ||
| - Gute, realisierbare Verfahren sollen vergangenes Referenzverhalten auf Seiten nutzen, um Erwartungswerte für Wiederbenutzung schätzen zu können
 | ||
|        - besser als Zufallsstrategie
 | ||
|        - Annäherung an optimale Strategie
 | ||
| 
 | ||
| 
 | ||
| Merkmale gängiger Strategien
 | ||
| - Alter der Seite im Puffer:
 | ||
|     - Alter einer Seite nach Einlagerung (die globale Strategie (G))
 | ||
|     - Alter einer Seite nach dem letztem Referenzzeitpunkt (die Strategie des jüngsten Verhaltens (J))
 | ||
|     - Alter einer Seite wird nicht berücksichtigt (-)
 | ||
| - Anzahl der Referenzen auf Seite im Puffer:
 | ||
|     - Anzahl aller Referenzen auf eine Seite (die globale Strategie (G))
 | ||
|     - Anzahl nur der letzten Referenzen auf eine Seite (die Strategie des jüngsten Verhaltens (J))
 | ||
|     - Anzahl der Referenzen wird nicht berücksichtigt (-)
 | ||
| 
 | ||
| 
 | ||
| Gängige Strategien
 | ||
| 
 | ||
| 
 | ||
| Klassifikation gängiger Strategien
 | ||
| | Verfahren                        | Prinzip                                                             | Alter | Anzahl |
 | ||
| | -------------------------------- | ------------------------------------------------------------------- | ----- |
 | ||
| | FIFO                             | älteste Seite ersetzt                                               | G     | -      |
 | ||
| | LFU (least fre-quently used)     | Seite mit geringster Häufigkeit ersetzen                            | -     | G      |
 | ||
| | LRU (least recently used)        | Seite ersetzen, die am längsten nicht referenziert wurde (System R) | J     | J      |
 | ||
| | DGCLOCK (dyn. generalized clock) | Protokollierung der Ersetzungshäufigkeiten wichtiger Seiten         | G     | JG     |
 | ||
| | LRD (least reference density)    | Ersetzung der Seite mit geringster Referenzdichte                   | JG    | G      |
 | ||
| 
 | ||
| Beispiel
 | ||
| - Folge von Seitenanforderungen #1, #2 ...
 | ||
| - Puffer der Größe 6
 | ||
|     
 | ||
| - Ablauf mit
 | ||
|     - FIFO ...
 | ||
|     - LFU ...
 | ||
| 
 | ||
| ### LRU: Least Recently Used
 | ||
| - Idee: Seite im Puffer ersetzen, die am längsten nicht mehr referenziert wurde
 | ||
| - Implementierung:
 | ||
|     - Liste oder Stack von Seiten
 | ||
|     - Puffer-Hit bewegt Seite zur MRU-Position (Most Recently Used)
 | ||
|     - Seite am Ende wird verdrängt
 | ||
|     
 | ||
| - Varianten:
 | ||
|     - durch Interpretation der Pin-Operation: Least Recently Referenced bzw. Least Recently Unfixed
 | ||
|     - durch Berücksichtigung der letzten $k$ Referenzierungen (d.h. auch Häufigkeit): LRU-K
 | ||
| 
 | ||
| LRU: Probleme
 | ||
| - Lock Contention in Multitasking-Umgebungen
 | ||
|     - Zugriff auf LRU-Liste/Stack und Bewegung der Seite erfordert exklusiven Zugriff auf Datenstruktur
 | ||
|     - aufwendige Operation
 | ||
| - berücksichtigt nur Alter jedoch nicht Häufigkeit
 | ||
|     - oft gelesene Seiten mit langen Pausen zwischen den Zugriffen werden nicht adäquat berücksichtigt
 | ||
| - "Zerstörung" des Puffers durch Scan-Operator
 | ||
|     - Seiten werden nur einmalig gelesen, verdrängen jedoch andere (ältere) Seiten
 | ||
| 
 | ||
| 
 | ||
| Lock Contention bei der Pufferverwaltung
 | ||
| 
 | ||
| - Sperren = Latches: leichtgewichtige (wenige CPU-Instruktionen) Objekte für kurzzeitige Sperren
 | ||
| 
 | ||
| Approximierende Verfahren
 | ||
| - Idee:
 | ||
|     - Vereinfachung der benötigten Datenstruktur durch Approximation
 | ||
|     - Effektivität (Trefferrate) vs. Skalierbarkeit (Anzahl der Threads)
 | ||
| - CLOCK: Approximation der Historie durch Bit-Schieberegister der Länge $k$
 | ||
|        - $k= 0$: FIFO
 | ||
|        - $k\rightarrow\infty$: LRU
 | ||
|        - typisch: $k = 1$
 | ||
| 
 | ||
| ### CLOCK
 | ||
| - Seite mit Benutzt-Bit; bei Referenzierung auf "1" setzen
 | ||
| - bei Seitenfehler:
 | ||
|     - zyklische Suche
 | ||
|     - Seite mit "0" verdrängen
 | ||
|     - sonst Setzen auf "0"
 | ||
|     
 | ||
| 
 | ||
| ### GCLOCK
 | ||
| - Verbesserung: Benutzt-Bit durch Referenzzähler _RC_ ersetzen; Dekrementierung bei Suche
 | ||
| - weitere Verbesserungen:
 | ||
|     - Initialisierung des Referenzzählers
 | ||
|     - Inkrementierung des Zählers
 | ||
|     - seitentypspezifische Maßnahmen (für Typ _i_ : Seitengewicht $E_i$ bei Erstreferenzierung, $W_i$ bei weiterer Referenzierung)
 | ||
|     - Altern
 | ||
| - Varianten: Seite _j_ von Typ _i_
 | ||
|     - $GCLOCK(V1): RC_j := E_i ; RC_j := RC_j + W_i$
 | ||
|     - $GCLOCK(V2): RC_j := E_i ; RC_j := W_i$ (speziell für $W_i\geq E_i$)
 | ||
| 
 | ||
| ### DGCLOCK
 | ||
| - weitere Verbesserung: globaler Zähler $GC$ und Normierung der aktuellen Referenzzähler $RC$
 | ||
|     1. Initialisierung: $RC_j := GC$
 | ||
|     2. Referenzierung von Seite $j : GC := GC + 1 ; RC_j := RC_j + GC$
 | ||
|     3. bei Überschreiten $GC > MIN : \forall j : RC_j := RC_j / C$
 | ||
| 
 | ||
| ### ARC
 | ||
| - Adaptive Replacement Cache: neues Verfahren, das Nachteile von LRU vermeidet
 | ||
| - Prinzip:
 | ||
|     - Puffergröße _c_
 | ||
|     - Pufferverzeichnis für 2 _c_ Seiten: _c_ Pufferseiten + _c_ History-Seiten
 | ||
|     - Liste _L_ 1 : "recency" = kurzfristiger Nutzen-> Seiten, die kürzlich einmal gelesen wurden
 | ||
|     - Liste _L_ 2 : "frequency" = langfristiger Nutzen -> Seiten, die kürzlich mehrmals gelesen wurden
 | ||
| - Ausgangspunkt: einfache Verdrängungsstrategie DBL(2 _c_ )
 | ||
|     - Ersetze die LRU-Seite in $L_1$, wenn $|L_1| = c$ , sonst ersetze LRU-Seite in $L_2$
 | ||
|     - Ziel: Größenausgleich zwischen $L_1$ und $L_2$
 | ||
|     - Zugriff Seite $p$: wenn Treffer -> $p$ wird MRU in $L_2$ , sonst in $L_1$
 | ||
| 
 | ||
| Von DBL(2c) zu ARC
 | ||
| 
 | ||
| - Parameter $p$ mit $0\leq p \leq c$
 | ||
|     - $T_1$ enthält $p$ Seiten, $T_2$ enthält $c-p$ Seiten
 | ||
| - Wahl von $p$?
 | ||
| 
 | ||
| ARC: Algorithmus
 | ||
| - Seitenanforderungen: $x_1,x_2 ,..., x_t ,...$
 | ||
| - $p = 0, T_1 , B_1 , T_2 ,B_2$ sind initial leer
 | ||
|     - Fall 1: $x_t \in T_1 \cup T_2$ /* Puffer-Hit */
 | ||
|         - Bewege $x_t$ zu MRU von $T_2$
 | ||
|     - Fall 2: $x_t \in B_1$
 | ||
|         - Anpassung: $p = min\{ p +\delta_1,c\}$ mit $\delta_1 = \begin{cases} 1\quad\text{ wenn } |B_1|\geq |B_2| \\ \frac{|B_2|}{|B_1|} \quad\text{ sonst}\end{cases}$
 | ||
|         - $REPLACE(x_t,p)$
 | ||
|         - Bewege $x_t$ von $B_1$ zu MRU von $T_2$
 | ||
|     - Fall 3: $x_t \in B_2$
 | ||
|       - Anpassung: $p = max\{ p - \delta_2, 0 \}$ mit $\delta_2 = \begin{cases} 1\quad\text{ wenn } |B_2|\geq |B_1| \\ \frac{|B_1|}{|B_2|} \quad\text{ sonst}\end{cases}$
 | ||
|       - $REPLACE(x_t,p)$
 | ||
|       - Bewege $x_t$ von $B_2$ zu MRU von $T_2$
 | ||
|     - Fall 4: $x_t \not\in T_1 \cup B_1 \cup T_2 \cup B_2$
 | ||
|       - 4.A: $|L_1| = c$
 | ||
|         - Wenn $|T_1|<c$, lösche LRU in $B_1$, $REPLACE(x_t,p)$
 | ||
|         - sonst /* $B_1 = \varnothing$ */ lösche LRU in $T_1$
 | ||
|       - 4.B: $|L_1|<c$
 | ||
|         - Wenn $|L_1|+|L_2|\geq c$ , lösche LRU in $B_2$, $REPLACE(x_t,p)$
 | ||
|       - Bewege $x_t$ zu MRU in $T_1$
 | ||
| 
 | ||
| ARC: $REPLACE(x_t, p)$
 | ||
| 
 | ||
|     if $|T_1|>p$ oder ($x_t\in B_2$ und $|T_1|=p$)
 | ||
|         Lösche LRU-Seite in $T_1$ und bewege sie zu MRU in $B_1$
 | ||
|     else
 | ||
|         Lösche LRU-Seite in $T_2$ und bewege sie zu MRU in $B_2$
 | ||
|     endif
 | ||
| 
 | ||
| ARC: Beispiel
 | ||
| 1. erstmalige Anforderung der Seiten $#1$ und $#2$: Aufnahme in
 | ||
|     
 | ||
| 2. nächsten Referenzierung von $#1$: Übernahme in $T_2$-Liste
 | ||
|     
 | ||
| 3. Seitenanforderungen $#3$, $#4$, $#1$; mit $#2$ wird diese in $T_2$ bewegt; Platz für Seite $#5$:
 | ||
|     
 | ||
| 4. Beantwortung der Seitenanforderungen $#1$ und $#2$ aus $T_2$
 | ||
| 5. neu angeforderten Seiten $#5$ und $#6$ in $T_1$
 | ||
|     
 | ||
| 6. Seitenanforderung $#7$: Verdrängen von $#4$ aus $T_1$ in $B_1$
 | ||
|     
 | ||
| 
 | ||
| ARC: Eigenschaften
 | ||
| - kontinuierliche Anpassung von Parameter $p$
 | ||
|     - Lernraten $\delta_1$ und $\delta_2$
 | ||
|     - "Investieren in Liste mit dem meisten Profit"
 | ||
| - Berücksichtigung von Alter und Häufigkeit
 | ||
|     - durch zwei Listen $L_1$ und $L_2$
 | ||
| - Scan-Resistenz
 | ||
|     - einmalig gelesene Seiten nur in $L_1$, niemals in $L_2$
 | ||
| - Vermeidung von Lock Contention durch approximierende Varianten (CAR, CART, ...)
 | ||
| 
 | ||
| ## Fazit
 | ||
| - Pufferverwaltungsstrategie mit großem Einfluss auf Performance
 | ||
| - in kommerziellen Systemen meist LRU mit Variationen
 | ||
| - besondere Behandlung von Full-Table-Scans
 | ||
| - weiterer Einflussfaktor: Puffergröße
 | ||
| - Indikator: Trefferrate (engl. _hit ratio_ )
 | ||
|     $$hit\_ratio = \frac{\text{Anz. log. Zugriffe} - \text{Anz. phys. Zugriffe}}{\text{Anz. log. Zugriffe}}$$
 | ||
| - 5-Minuten-Regel (Gray, Putzolu 1997):
 | ||
|     Daten, die in den nächsten 5 Min. wieder referenziert werden, sollten im Hauptspeicher gehalten werden
 | ||
| 
 | ||
| # Indexierung von Daten
 | ||
| ## Klassifikation der Speichertechniken
 | ||
| Einordnung in 5-Schichten-Architektur
 | ||
| - **Speichersystem** fordert über Systempufferschnittstelle Seiten an
 | ||
| - interpretiert diese als interne Datensätze
 | ||
| - interne Realisierung der logischen Datensätze mit Hilfe von Zeigern, speziellen Indexeinträgen und weiteren Hilfsstrukturen
 | ||
| - Zugriffssystem abstrahiert von der konkreten Realisierung
 | ||
| 
 | ||
| Klassifikation der Speichertechniken
 | ||
| - Kriterien für Zugriffsstrukturen oder Zugriffsverfahren:
 | ||
|     - organisiert interne Relation selbst (Dateiorganisationsform) oder zusätzliche Zugriffsmöglichkeit auf bestehende interne Relation (Zugriffspfad)
 | ||
|     - Art der Zuordnung von gegebenen Attributwerten zu Datensatz-Adressen: Schlüsselvergleich = Zuordnung von Schlüsselwert zu Adresse über Hilfsstruktur; Schlüsseltransformation = Berechnung der Adresse aus Schlüsselwert (z.B. über Hashfunktion)
 | ||
|     - Arten von Anfragen, die durch Dateiorganisationsformen und Zugriffspfade effizient unterstützt werden können
 | ||
| 
 | ||
| 
 | ||
| Dünn- vs. dichtbesetzter Index
 | ||
| - dünnbesetzter Index: nicht für jeden Zugriffsattributwert $k$ ein Eintrag in Indexdatei sondern z.B. nur für _Seitenanführer_ einer sortierten Relation
 | ||
| - dichtbesetzter Index: für jeden Datensatz der internen Relation ein Eintrag in Indexdatei
 | ||
| 
 | ||
| Geclusterter vs. nicht-geclusterter Index
 | ||
| - geclusterter Index: in der gleichen Form sortiert wie interne Relation
 | ||
| - nicht-geclusterter Index: anders organisiert als interne Relation
 | ||
| - Primärindex oft dünnbesetzt und geclustert
 | ||
| - jeder dünnbesetzte Index ist auch geclusterter Index, aber nicht umgekehrt
 | ||
| - Sekundärindex kann nur dichtbesetzter, nicht-geclusterter Index sein (auch: invertierte Datei)
 | ||
| 
 | ||
| 
 | ||
| Statische vs. dynamische Struktur
 | ||
| - statische Zugriffsstruktur: optimal nur bei bestimmter (fester) Anzahl von verwaltenden Datensätzen
 | ||
| - dynamische Zugriffsstruktur: unabhängig von der Anzahl der Datensätze optimal
 | ||
|        - dynamische Adresstransformationsverfahren verändern dynamisch Bildbereich der Transformation
 | ||
|        - dynamische Indexverfahren verändern dynamisch Anzahl der Indexstufen => in DBS üblich
 | ||
| 
 | ||
| Klassifikation
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| ## Statische Verfahren
 | ||
| - Heap, indexsequenziell, indiziert-nichtsequenziell
 | ||
| - oft grundlegende Speichertechnik in RDBS
 | ||
| - direkte Organisationsformen: keine Hilfsstruktur, keine Adressberechnung (Heap, sequenziell)
 | ||
| - statische Indexverfahren für Primärindex und Sekundärindex
 | ||
| 
 | ||
| 
 | ||
| Statische Verfahren: Überblick
 | ||
| 
 | ||
| 
 | ||
| ### Heap
 | ||
| Organisation
 | ||
| - völlig unsortiert speichern
 | ||
| - physische Reihenfolge der Datensätze ist zeitliche Reihenfolge der Aufnahme von Datensätzen
 | ||
|     |      |       |            |     |
 | ||
|     | ---- | ----- | ---------- | --- | -------- |
 | ||
|     | 8832 | Max   | Mustermann | ... | 9.1.2003 |
 | ||
|     | 5588 | Beta  | Alpha      | ... | 7.3.1978 |
 | ||
|     | 4711 | Gamma | Delta      | ... | 2.5.1945 |
 | ||
| 
 | ||
| Operationen
 | ||
| - insert: Zugriff auf letzte Seite der Datei. Genügend freier Platz => Satz anhängen. Sonst nächste freie Seite holen
 | ||
| - delete: lookup, dann Löschbit auf 0 gesetzt
 | ||
| - lookup: sequenzielles Durchsuchen der Gesamtdatei, maximaler Aufwand (Heap-Datei meist zusammen mit Sekundärindex eingesetzt; oder für sehr kleine Relationen)
 | ||
| - Komplexitäten:
 | ||
|     - Neuaufnahme von Daten $O(1)$
 | ||
|     - Suchen $O(n)$
 | ||
| 
 | ||
| ### Sequenzielle Speicherung
 | ||
| - sortiertes Speichern der Datensätze
 | ||
|     |      |       |            |     |
 | ||
|     | ---- | ----- | ---------- | --- | -------- |
 | ||
|     | 4711 | Gamma | Delta      | ... | 2.5.1945 |
 | ||
|     | 5588 | Beta  | Alpha      | ... | 7.3.1978 |
 | ||
|     | 8832 | Max   | Mustermann | ... | 9.1.2003 |
 | ||
| 
 | ||
| Sequenzielle Datei: Operationen
 | ||
| - insert: Seite suchen, Datensatz einsortieren => beim Anlegen oder sequenziellen Füllen einer Datei jede Seite nur bis zu gewissem Grad (etwa 66%) füllen
 | ||
| - delete: Aufwand bleibt
 | ||
| - Folgende Dateiorganisationsformen:
 | ||
|     - schnelleres lookup
 | ||
|     - mehr Platzbedarf (durch Hilfsstrukturen wie Indexdateien)
 | ||
|     - mehr Zeitbedarf bei insert und delete
 | ||
| - klassische Indexform: indexsequenzielle Dateiorganisation
 | ||
| 
 | ||
| ## Indexsequenzielle Dateiorganisation
 | ||
| - Kombination von sequenzieller Hauptdatei und Indexdatei: indexsequenzielle Dateiorganisationsform
 | ||
| - Indexdatei kann geclusterter, dünnbesetzter Index sein
 | ||
| - mindestens zweistufiger Baum
 | ||
|     - Blattebene ist Hauptdatei (Datensätze)
 | ||
|     - jede andere Stufe ist Indexdatei
 | ||
| 
 | ||
| 
 | ||
| Aufbau der Indexdatei
 | ||
| - Datensätze in Indexdatei: _(Primärschlüsselwert, Seitennummer)_ zu jeder Seite der Hauptdatei genau ein Index-Datensatz in Indexdatei
 | ||
| - Problem: "Wurzel" des Baumes bei einem einstufigen Index nicht nur eine Seite
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| Mehrstufiger Index
 | ||
| - Optional: Indexdatei wieder indexsequenziell verwalten
 | ||
| - Idealerweise: Index höchster Stufe nur noch eine Seite
 | ||
| 
 | ||
| 
 | ||
| lookup bei indexsequenziellen Dateien
 | ||
| - lookup-Operation sucht Datensatz zum Zugriffsattributwert _w_
 | ||
| - Indexdatei sequenziell durchlaufen, dabei $(v_1,s)$ im Index gesucht mit $v_1\leq w$:
 | ||
|     - $(v_1,s)$ ist letzter Satz der Indexdatei, dann kann Datensatz zu _w_ höchstens auf dieser Seite gespeichert sein (wenn er existiert)
 | ||
|     - nächster Satz $(v_2,s′)$ im Index hat $v_2 > w$ , also muss Datensatz zu _w_, wenn vorhanden, auf Seite _s_ gespeichert sein
 | ||
| - $(v_1,s)$ überdeckt Zugriffsattributwert _w_
 | ||
| 
 | ||
| insert bei indexsequenziellen Dateien
 | ||
| - insert: zunächst mit lookup Seite finden
 | ||
| - Falls Platz, Satz sortiert in gefundener Seite speichern; Index anpassen, falls neuer Satz der erste Satz in der Seite
 | ||
| - Falls kein Platz, neue Seite von Freispeicherverwaltung holen; Sätze der "zu vollen" Seite gleichmäßig auf alte und neue Seite verteilen; für neue Seite Indexeintrag anlegen
 | ||
| - Alternativ neuen Datensatz auf Überlaufseite zur gefundenen Seite
 | ||
| 
 | ||
| delete bei indexsequenziellen Dateien
 | ||
| - delete: zunächst mit lookup Seite finden
 | ||
| - Satz auf Seite löschen (Löschbit auf 0)
 | ||
| - erster Satz auf Seite: Index anpassen
 | ||
| - Falls Seite nach Löschen leer: Index anpassen, Seite an Freispeicherverwaltung zurück
 | ||
| 
 | ||
| Probleme indexsequenzieller Dateien
 | ||
| - stark wachsende Dateien: Zahl der linear verketteten Indexseiten wächst; automatische Anpassung der Stufenanzahl nicht vorgesehen
 | ||
| - stark schrumpfende Dateien: nur zögernde Verringerung der Index- und Hauptdatei-Seiten
 | ||
| - unausgeglichene Seiten in der Hauptdatei (unnötig hoher Speicherplatzbedarf, zu lange Zugriffszeit)
 | ||
| 
 | ||
| 
 | ||
| Indiziert-nichtsequenzieller Zugriffspfad
 | ||
| - zur Unterstützung von Sekundärschlüsseln
 | ||
| - mehrere Zugriffpfade dieser Form pro Datei möglich
 | ||
| - einstufig oder mehrstufig: höhere Indexstufen wieder indexsequenziell organisiert
 | ||
| 
 | ||
| Aufbau der Indexdatei
 | ||
| - Sekundärindex, dichtbesetzter und nicht-geclusteter Index
 | ||
| - zu jedem Satz der Hauptdatei Satz $(w,s)$ in der Indexdatei
 | ||
| - _w_ Sekundärschlüsselwert, _s_ zugeordnete Seite
 | ||
|     - entweder für ein _w_ mehrere Sätze in die Indexdatei aufnehmen
 | ||
|     - oder für ein _w_ Liste von Adresse in der Hauptdatei angeben
 | ||
| 
 | ||
| 
 | ||
| Operationen
 | ||
| - lookup: _w_ kann mehrfach auftreten, Überdeckungstechnik nicht benötigt
 | ||
| - insert: Anpassen der Indexdateien
 | ||
| - delete: Indexeintrag entfernen
 | ||
| 
 | ||
| Probleme statischer Verfahren
 | ||
| - unzureichende Anpassung an wachsende/schrumpfende Datenmengen
 | ||
| - schlechte Ausnutzung von Speicher nach Seitensplits
 | ||
| - Bevorzugung bestimmter Attribute (Schlüssel)
 | ||
| - daher in den folgenden Kapiteln:
 | ||
|     - bessere Datenstrukturen zur Schlüsselsuche als zusätzlicher Zugriffspfad = Approximation einer Funktion Schlüssel -> Speicheradresse, z.B. über Baumverfahren
 | ||
|     - Erweiterung von Hashverfahren um Anpassung des Bildbereichs = dynamische Hashverfahren
 | ||
|     - Behandlung von zusammengesetzten Schlüsseln = multidimensionale Zugriffsverfahren, z.B. multidimensionale Bäume oder raumfüllende Kurven
 | ||
| 
 | ||
| # Baumbasierte Indexstrukturen
 | ||
| ## Baumverfahren
 | ||
| - Stufenanzahl dynamisch verändern
 | ||
| - wichtigste Baumverfahren: B-Bäume und ihre Varianten
 | ||
| - B-Baum-Varianten sind noch "allgegenwärtiger" in heutigen Datenbanksystemen als SQL
 | ||
| - SQL nur in der relationalen und objektrelationalen Datenbanktechnologie verbreitet; B-Bäume überall als Grundtechnik eingesetzt
 | ||
| 
 | ||
| Baumverfahren: Überblick
 | ||
| 
 | ||
| 
 | ||
| ## B-Bäume
 | ||
| - Ausgangspunkt: ausgeglichener, balancierter Suchbaum
 | ||
| - Ausgeglichen oder balanciert: alle Pfade von der Wurzel zu den Blättern des Baumes gleich lang
 | ||
| - Hauptspeicher-Implementierungsstruktur: binäre Suchbäume, beispielsweise AVL-Bäume von Adelson-Velskii und Landis
 | ||
| - Datenbankbereich: Knoten der Suchbäume zugeschnitten auf Seitenstruktur des Datenbanksystems
 | ||
| - mehrere Zugriffsattributwerte auf einer Seite
 | ||
| - Mehrwegebäume
 | ||
| 
 | ||
| Prinzip des B-Baumes
 | ||
| - B-Baum von Bayer (B für balanciert, breit, buschig, Bayer, NICHT: binär)
 | ||
| - dynamischer, balancierter Indexbaum, bei dem jeder Indexeintrag auf eine Seite der Hauptdatei zeigt
 | ||
| - Mehrwegebaum völlig ausgeglichen, wenn
 | ||
|   1. alle Wege von Wurzel bis zu Blättern gleich lang
 | ||
|   2. jeder Knoten gleich viele Indexeinträge
 | ||
| - vollständiges Ausgleichen zu teuer, deshalb B-Baum-Kriterium:
 | ||
|     Jede Seite außer der Wurzelseite enthält zwischen $m$ und $2m$ Einträge.
 | ||
| 
 | ||
| Definition B-Baum
 | ||
| - Ordnung eines B-Baumes ist minimale Anzahl der Einträge auf den Indexseiten außer der Wurzelseite
 | ||
| - Bsp.: B-Baum der Ordnung 8 fasst auf jeder inneren Indexseite zwischen 8 und 16 Einträgen
 | ||
| - Def.: Ein Indexbaum ist ein B-Baum der Ordnung $m$ , wenn er die folgenden Eigenschaften erfüllt:
 | ||
|     1. Jede Seite enthält höchstens $2m$ Elemente.
 | ||
|     2. Jede Seite, außer der Wurzelseite, enthält mindestens $m$ Elemente. 
 | ||
|     3. Jede Seite ist entweder eine Blattseite ohne Nachfolger oder hat $i+1$ Nachfolger, falls $i$ die Anzahl ihrer Elemente ist.
 | ||
|     4. Alle Blattseiten liegen auf der gleichen Stufe.
 | ||
| 
 | ||
| Eigenschaften des B-Baumes
 | ||
| - $n$ Datensätze in der Hauptdatei => in $log_m(n)$ Seitenzugriffen von der Wurzel zum Blatt
 | ||
| - Durch Balancierungskriterium wird Eigenschaft nahe an der vollständigen Ausgeglichenheit erreicht (1. Kriterium vollständig erfüllt, 2. Kriterium näherungsweise)
 | ||
| - Kriterium garantiert 50% Speicherplatzausnutzung
 | ||
| - einfache, schnelle Algorithmen zum Suchen, Einfügen und Löschen von Datensätzen (Komplexität von $O(log_m(n))$)
 | ||
| 
 | ||
| Suchen in B-Bäumen
 | ||
| - lookup wie in statischen Indexverfahren
 | ||
| - Startend auf Wurzelseite Eintrag im B-Baum ermitteln, der den gesuchten Zugriffsattributwert $w$ überdeckt => Zeiger verfolgen, Seite nächster Stufe laden
 | ||
| - Suchen: 38, 20, 6
 | ||
| - 
 | ||
| 
 | ||
| Einfügen in B-Bäumen
 | ||
| - Einfügen eines Wertes _w_
 | ||
|     - mit lookup entsprechende Blattseite suchen
 | ||
|     - passende Seite $n<2m$ Elemente, _w_ einsortieren
 | ||
|     - passende Seite $n=2m$ Elemente, neue Seite erzeugen,
 | ||
|        - ersten _m_ Werte auf Originalseite
 | ||
|        - letzten _m_ Werte auf neue Seite
 | ||
|        - mittleres Element auf entsprechende Indexseite nach oben
 | ||
|     - eventuell dieser Prozess rekursiv bis zur Wurzel
 | ||
| 
 | ||
| Einfügen in einen B-Baum: Beispiel
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| Löschen in B-Bäumen
 | ||
| - bei weniger als $m$ Elementen auf Seite: Unterlauf
 | ||
| - Löschen eines Wertes $w$ : Bsp.: 24; 28, 38, 35
 | ||
|     - mit lookup entsprechende Seite suchen
 | ||
|     - $w$ auf Blattseite gespeichert => Wert löschen, eventuell Unterlauf behandeln
 | ||
|     - $w$ nicht auf Blattseite gespeichert => Wert löschen, durch lexikographisch nächstkleineres Element von einer Blattseite ersetzen, eventuell auf Blattseite => Unterlauf
 | ||
| - Unterlaufbehandlung
 | ||
|     - Ausgleichen mit der benachbarten Seite (benachbarte Seite $n$ Elemente mit $n>m$)
 | ||
|     - oder Zusammenlegen zweier Seiten zu einer (Nachbarseite $n=m$ Elemente), das "mittlere" Element von Indexseite darüber dazu, auf Indexseite eventuell => Unterlauf
 | ||
| - Einfügen des Elementes 22; Löschen von 22
 | ||
|     
 | ||
| 
 | ||
| Komplexität der Operationen
 | ||
| - Aufwand beim Einfügen, Suchen und Löschen im B-Baum immer $O(log_m(n))$ Operationen
 | ||
| - entspricht genau der "Höhe" des Baumes
 | ||
| - Konkret: Seiten der Größe 4 KB, Zugriffsattributwert 32 Bytes, 8-Byte-Zeiger: zwischen 50 und 100 Indexeinträge pro Seite; Ordnung dieses B-Baumes 50
 | ||
| - 1.000.000 Datensätze: $log_{50}(1000000) = 4$ Seitenzugriffe im schlechtesten Fall
 | ||
| - Wurzelseite jedes B-Baumes normalerweise im Puffer: 3 Seitenzugriffe
 | ||
| 
 | ||
| ## B+-Baum
 | ||
| Varianten
 | ||
| - B+-Bäume: nur Blattebene enthält Daten -> Baum ist hohl
 | ||
| - B∗-Bäume: Aufteilen von Seiten vermeiden durch "Shuffle"
 | ||
| - Präfix-B-Bäume: Zeichenketten als Zugriffsattributwerte, nur Präfix indexieren
 | ||
| 
 | ||
| B+-Baum: Motivation
 | ||
| - B-Baum: Wie/wo werden Nicht-Schlüsseldaten (Tupel, TIDs) gespeichert?
 | ||
|        - Zusammen mit Schlüsseln in allen Knoten?
 | ||
|        - Problem beim Traversieren des Baumes, z.B. bei Bereichsanfragen
 | ||
|     
 | ||
| 
 | ||
| B+-Baum
 | ||
| - in der Praxis am häufigsten eingesetzte Variante des B-Baumes:
 | ||
|        - effizientere Änderungsoperationen, insb. Löschen
 | ||
|        - Verringerung der Baumhöhe
 | ||
| - Änderungen gegenüber B-Baum
 | ||
|     - in inneren Knoten nur noch Zugriffsattributwert und Zeiger auf nachfolgenden Seite der nächsten Stufe; nur Blattknoten enthalten neben Zugriffsattributwert die Daten (Datensätze bzw. Verweise auf Datensätze in der Hauptdatei)
 | ||
|     - Knoten der Blattebene sind untereinander verkettet für effiziente Unterstützung von Bereichsanfragen
 | ||
| 
 | ||
| B+-Baum: Aufbau
 | ||
| 
 | ||
| 
 | ||
| Ordnung; Operationen
 | ||
| - Ordnung für B+-Baum: $(x,y), x$ Mindestbelegung der Indexseiten, $y$ Mindestbelegung der Blattseiten
 | ||
| - delete gegenüber B-Baum effizienter ("Ausleihen" eines Elementes von der Blattseite entfällt)
 | ||
| - Zugriffsattributwerte in inneren Knoten können sogar stehenbleiben
 | ||
| - häufig als Primärindex eingesetzt
 | ||
| - B+-Baum ist dynamische, mehrstufige, indexsequenziellen Datei
 | ||
| 
 | ||
| B+-Baum: Blattebene mit Verweisen
 | ||
| 
 | ||
| 
 | ||
| B+-Baum: Datenstrukturen
 | ||
| ```cpp
 | ||
| BPlusBranchNode =record of
 | ||
|     nkeys: int;
 | ||
|     ptrs: array[0 .. nkeys ] of PageNum;
 | ||
|     keys: array[1 .. nkeys ]of KeyType;
 | ||
|     level: int;
 | ||
| /* Level= 1 zeigt an, dass die ptrs auf Blätter zeigen */
 | ||
| end;
 | ||
| ```
 | ||
| ```cpp
 | ||
| BPlusLeafNode = record of
 | ||
|     nkeys: int;
 | ||
|     keys: array[1 .. nkeys ]of KeyType;
 | ||
|     payload: array[1 .. nkeys ]of LoadType ; /* Daten bzw. TIDs */
 | ||
|     nextleaf: PageNum;
 | ||
| end;
 | ||
| ```
 | ||
| 
 | ||
| Operationen im B+-Baum
 | ||
| - lookup: wie im B-Baum jedoch immer bis zur Blattebene
 | ||
| - $search(u,o)$: Lookup für unteren Wert $u$ , Traversieren auf der Blattebene bis zum oberen Wert $o$
 | ||
| - $insert$: ähnlich zum B-Baum
 | ||
|     - im Fall des Split bei Überlaufbehandlung wird nur ein Separatorschlüssel im Elternknoten eingefügt
 | ||
|     - z.B. Kopie des kleinsten Schlüsselwertes des "rechten" Kindknotens oder geeigneter Wert zwischen beiden Knoten
 | ||
| - $delete$: ähnlich zum B-Baum, jedoch
 | ||
|     - Löschen der Daten zunächst nur auf Blattebene
 | ||
|     - bei Unterlauf: entweder Ausgleich mit Nachbarknoten oder Vereinigen mit Nachbarknoten; ggf. Anpassen (Ausgleich) oder Löschen (Vereinigen) des Separatorschlüssels
 | ||
|     - alternativ: Unterlauf akzeptieren und durch spätere inserts oder Reorganisation auflösen
 | ||
| 
 | ||
| Weitere Entwurfsentscheidungen für B+-Baum
 | ||
| - Schlüsselsuche im Knoten: sequenzielle Suche vs. binäre Suche vs. Interpolation Search
 | ||
| - Knotengröße: Maximieren der Anzahl der Vergleiche (Knotennutzen) pro I/O-Zeiteinheit
 | ||
| 
 | ||
| | Seitengröße (KB) | Sätze/Seite | Knotennutzen | I/O-Zeit (ms) | Nutzen/Zeit |
 | ||
| | ---------------- | ----------- | ------------ | ------------- | ----------- |
 | ||
| | 4                | 143         | ≈7           | 5,020         | 1,427       |
 | ||
| | 16               | 573         | ≈ 9          | 5,080         | 1,804       |
 | ||
| | 64               | 2.294       | ≈ 11         | 5,320         | 2,098       |
 | ||
| | 128              | 4.588       | ≈ 12         | 5,640         | 2,157       |
 | ||
| | 256              | 9.175       | ≈ 13         | 6,280         | 2,096       |
 | ||
| | 1024             | 36.700      | ≈ 15         | 10,120        | 1,498       |
 | ||
| | 4096             | 146.801     | ≈ 17         | 25,480        | 0,674       |
 | ||
| [Literatur](G. Graefe: Modern B-Tree Techniques, Foundations and Trends in Databases, 2010)
 | ||
| 
 | ||
| - Konsistenzprüfung während der Traversierung
 | ||
|     - mögliche Inkonsistenzen durch Speicherfehler, konkurrierende Änderungen + Implementierungsfehler, ...
 | ||
| - Cache-Optimierung: Knotenstruktur, Kompression (Präfix-/Suffix Truncation)
 | ||
| - Pointer Swizzling: zur Ersetzung der logischen Seitennummern durch physische Adressen
 | ||
| - Knotengröße: bei großen Puffern kann großer Teil der inneren Knoten im Puffer gehalten werden -> größere Knoten (im MB-Bereich) sinnvoll
 | ||
| - Verzögern des Splits bei Überlaufbehandlung: Ausgleichen mit Nachbarknoten soweit möglich; verbessert Auslastung der Knoten
 | ||
| - zusätzliche Verweise zwischen Knoten
 | ||
|     - z.B. zwischen inneren Knoten der gleichen Ebene, zu Elternknoten, etc.
 | ||
|     - ermöglichen Konsistenzchecks, aber erschweren Sperren für Nebenläufigkeitskontrolle
 | ||
| 
 | ||
| ## Weitere Varianten
 | ||
| Präfix-B-Baum
 | ||
| - B-Baum über Zeichenkettenattribut
 | ||
|     - lange Schlüssel in inneren Knoten -> hoher Speicherplatzbedarf
 | ||
|     - vollständige Schlüssel eigentlich nicht notwendig, da nur "Wegweiser"
 | ||
| - Idee: Verwaltung von Trennwerten -> Präfix-B-Baum
 | ||
|     - in inneren Knoten nur Trennwerte, die lexikographisch zwischen den Werten liegen
 | ||
|     - möglichst kurze Trennwerte, z.B. kürzester eindeutiger Präfix
 | ||
|     
 | ||
|     - aber: Beispiel "Vandenberg" und "Vandenbergh"
 | ||
| 
 | ||
| Mehr-Attribut-B-Baum
 | ||
| - B-Baum ist eindimensionale Struktur, jedoch können mehrere Attribute als kompositer Schlüssel indexiert werden
 | ||
|   `create index NameIdx on KUNDE(Name, Vorname)`
 | ||
| - allerdings: Attribute werden bei partial-match-Anfragen nicht gleich behandelt!
 | ||
| - Alternative: raumfüllende Kurven -> multidimensionale Indexstrukturen
 | ||
|     
 | ||
|     
 | ||
| ## Optimierungen für moderne Hardware
 | ||
| Optimierungspotential
 | ||
| - Verbesserung der Cache-Trefferrate
 | ||
|     - Organisation der Datenstruktur entsprechend Cacheline (Größe, Anordnung der Daten)
 | ||
|     - In-Place-Update im Hauptspeicher -> Cache-Invalidierung: verändertes Update Handling
 | ||
|     - Pointer Swizzling
 | ||
| - Berücksichtigung der Storage-Eigenschaften
 | ||
|     - SSD vs. HDD
 | ||
|     - Bevorzugung sequentieller Schreiboperationen
 | ||
|     - spezielle Berücksichtigung für Main-Memory-Indexe
 | ||
| - Synchronisation in Multicore-Umgebungen
 | ||
|     - Lock/Latch-freie Operationen
 | ||
| 
 | ||
| 
 | ||
| CSB+-Baum
 | ||
| - =Cache Sensitive B+ Tree (Rao, Ross: Making B+-Trees Cache Conscious in Main Memory, SIGMOD 2000)
 | ||
| - "Cache-Freundlichkeit" durch
 | ||
|     1. Platzsparen im Knoten -> mehr relevante Daten im Cache
 | ||
|     2. Eliminieren von Zeigern für 1. und Reduzierung von Zeigerarithmetik
 | ||
| - Ansatz: veränderte Struktur der inneren Knoten
 | ||
|     - Zeiger auf ersten Kindknoten
 | ||
|     - alle Kindknoten eines Knotens sind in einem zusammenhängenden Speicherbereich (Knotengruppe) allokiert und werden über einenOffsetadressiert
 | ||
|     
 | ||
| 
 | ||
| Bw-Baum
 | ||
| - = Buzzword Tree (Levandoski, Lomet, Sengupta: The Bw-Tree: A B-tree for New Hardware Platforms, ICDE 2013)
 | ||
| - Ziele: Cache-Freundlichkeit, Multicore-CPUs, Flash-Speichereigenschaften
 | ||
| - Techniken
 | ||
|     - überwiegend Latch-freie Operationen, stattdessen atomare CAS-Instruktionen
 | ||
|     - spezifische Struktur-Modifikationsoperationen: Folge von atomaren Modifikationen, Blink-ähnliche Struktur
 | ||
|     - Delta-Updates und Log Structured Storage (LSS)
 | ||
|         - Änderungen an Seiten/Knoten werden nicht direkt ausgeführt, sondern in Delta-Records pro Knoten erfasst
 | ||
|         - keine Synchronisation für Zugriff auf Seiten notwendig
 | ||
|         - Seite kann auch nach Änderung im Cache verbleiben
 | ||
|         - Seiten + Delta Records werden periodisch konsolidiert
 | ||
|         - Log Structured Storage -> später!
 | ||
|     - Mapping-Tabelle: logische Seitennummern in
 | ||
|       - (a) Offset im Flash-Speicher
 | ||
|       - (b) Zeiger im Hauptspeicher
 | ||
| 
 | ||
| ## LSM-Baum
 | ||
| - = Log Structured Merge Tree (O’Neil, Cheng, Gawlick, O’Neil: The log-structured merge-tree (LSM-tree). Acta Informatica. 33 (4): 351-385, 1996)
 | ||
| - Ziel: höherer Schreibdurchsatz durch Eliminierung verstreuter In-Place-Updates
 | ||
| - Einsatz in diversen NoSQL-Systemen: HBase, Cassandra, BigTable, LevelDB, RocksDB, ...
 | ||
| - Grundidee
 | ||
|     - Batches von Schreiboperationen werden sequentiell in Indexdateien gespeichert, d.h. Sortieren vor Schreiben auf Externspeicher (Log Structured)
 | ||
|     - Neue Updates werden in neuen Indexdateien gespeichert
 | ||
|     - Indexdateien werden periodisch zusammengefügt (Merge)
 | ||
|     - Leseoperationen müssen alle Indexdateien konsultieren
 | ||
| 
 | ||
| 
 | ||
| LSM-Baum: Realisierung
 | ||
| - Main-Memory-Baum $C_0$ als Puffer, sortiert nach Schlüsseln, z.B. als AVL- oder RB-Baum
 | ||
|   - bei Erreichen eines gegebenen Füllgrads -> Herausschreiben auf Disk (siehe unten)
 | ||
|   - ergänzt um Write Ahead Logging auf Disk für Wiederherstellung nach Systemfehler
 | ||
| - mehrere Append-only, disk-basierte Indexe $C_1, C_2,...,$ ebenfalls sortiert nach Schlüssel (z.B. als B-Baum)
 | ||
|   - effiziente Unterstützung von Scans (Schlüsselsuche)
 | ||
|   - Merge in einem Schritt
 | ||
| - Aktualität der Indexe: $C_0,C_1,...,C_n$
 | ||
| 
 | ||
| LSM-Baum: Verdichtung
 | ||
| - wenn bestimmte Anzahl von Dateien erzeugt wurden (z.B. 5 Dateien je 100 Datensätze), werden diese in eine Datei gemischt (1 Datei mit 500 Sätzen)
 | ||
| - sobald 5 Dateien mit 500 Sätzen vorliegen, dann Mischen in eine Datei
 | ||
| - usw.
 | ||
| - Nachteil: große Anzahl von Dateien, die alle durchsucht werden müssen
 | ||
| 
 | ||
| LSM-Baum: Ebenenweise Verdichtung
 | ||
| 1. pro Ebene wird eine bestimmte Zahl von Dateien verwaltet, partitioniert nach Schlüsseln (keine Überlappung der Schlüssel) -> Suche nur in einer Datei notwendig
 | ||
| 2. Ausnahme: erste Ebene (Überlappung erlaubt)
 | ||
| 3. Mischen der Dateien jeweils in die nächsthöhere Ebene: Auswahl einer Datei und Aufteilen der Sätze -> Platz für neue Daten schaffen
 | ||
| 
 | ||
| LSM-Baum: Lesezugriffe
 | ||
| - grundsätzlich: Verbesserung der Schreibperformance zulasten der Leseperformance
 | ||
|   - Suche in allen Indexen $C_0,C_1,...,C_n$ notwendig
 | ||
| - Vermeiden unnötiger Lesevorgänge durch Bloom-Filter pro Index oder pro Run
 | ||
|   - (probabilistische) Datenstruktur zum Feststellen, ob Objekt in einer Menge enthalten ist
 | ||
|   - Bit-Feld: Objekt wird über $k$ Hashfunktionen auf $k$ Bits abgebildet, die auf 1 gesetzt werden
 | ||
|   - Prüfen auf Enthaltensein: Hashfunktionen anwenden -> Wenn alle $k$ Bits $= 1$, dann ist Objekt enthalten
 | ||
|   - aber falsch-positive Werte möglich!
 | ||
|   - können ebenfalls durch Mischen kombiniert werden
 | ||
|   - [Quelle](Bloom: Space/Time Trade-offs in Hash Coding with Allowable Errors. CACM, 13(7):422-426, 1970)
 | ||
| 
 | ||
| ## Zusammenfassung
 | ||
| - B+-Baum als "Arbeitspferd" für Indexing
 | ||
| - Standardoperationen: Suche, Einfügen, Löschen
 | ||
| - noch nicht betrachtet: Nebenläufigkeitskontrolle und Wiederherstellung im Fehlerfall
 | ||
| - diverse Varianten und Optimierungen
 | ||
| - LSM-Baum für schreibintensive Workloads
 | ||
| 
 | ||
| # Hashing
 | ||
| ## Hashing
 | ||
| - Zugriff über Adressberechnung aus Schlüssel
 | ||
| - linearer Adressraum der Grösse $n$
 | ||
|     - Adressierung in einem Array
 | ||
| - Ziel: direkter Zugriff in $O(1)$ statt logarithmisch wie bei Bäumen
 | ||
| 
 | ||
| Hashverfahren
 | ||
| - Schlüsseltransformation und Überlaufbehandlung
 | ||
| - DB-Technik:
 | ||
|     - Disk-basiert: Bildbereich entspricht Seiten-Adressraum
 | ||
|     - Hauptspeicher: Adresse in einem Array (Hauptspeicheradresse plus Offset)
 | ||
| - Dynamik: dynamische Hashfunktionen oder Re-Hashen
 | ||
| 
 | ||
| Grundprinzipien
 | ||
| - Basis-Hashfunktion: $h(k)= k mod m$
 | ||
|     - $m$ oft Primzahl da besseres Verhalten bei Kollisionen
 | ||
|     - oder $m=2^k$ aufgrund einfacher Berechnungen
 | ||
| - Überlauf-Behandlung
 | ||
|     - Überlaufseiten als verkettete Liste
 | ||
|     - lineares Sondieren
 | ||
|     - quadratisches Sondieren
 | ||
|     - doppeltes Hashen
 | ||
|     - ...
 | ||
| 
 | ||
| Hashverfahren für blockorientierte Datenhaltung
 | ||
| 
 | ||
| 
 | ||
| Operationen und Zeitkomplexität
 | ||
| - lookup, modify, insert, delete
 | ||
| - lookup benötigt maximal $1+ #B(h(w))$ Seitenzugriffe
 | ||
| - $#B(h(w))$ Anzahl der Seiten (inklusive der Überlaufseiten) des Buckets für Hash-Wert $h(w)$
 | ||
| - Untere Schranke 2 (Zugriff auf Hashverzeichnis plus Zugriff auf erste Seite)
 | ||
| 
 | ||
| Statisches Hashen: Probleme
 | ||
| - mangelnde Dynamik
 | ||
| - Vergrößerung des Bildbereichs erfordert komplettes Neu-Hashen
 | ||
| - Wahl der Hashfunktion entscheidend; 
 | ||
|   - Bsp.: Hash-Index aus 100 Buckets, Studenten über 6-stellige MATRNR (wird fortlaufend vergeben) hashen
 | ||
|   - ersten beiden Stellen: Datensätze auf wenigen Seiten quasi sequenziell abgespeichert
 | ||
|   - letzten beiden Stellen: verteilen die Datensätze gleichmäßig auf alle Seiten
 | ||
| - Sortiertes Ausgeben einer Relation nicht unterstützt
 | ||
| 
 | ||
| ## Hash-Funktionen
 | ||
| - klassisch, etwa Divisions-Rest-Methode
 | ||
|     $h() = x mod m$
 | ||
| - zusammengesetzt, etwa $h(k)= h_2 (h_1 (k))$ (siehe später Spriralhashen)
 | ||
| - ordnungserhaltend
 | ||
|     $k_1 < k_2 => ( h(k_1) = h(k_2) \vee h(k_1) < h(k_2))$
 | ||
| - dynamisch (siehe später)
 | ||
| - mehrdimensional (siehe später)
 | ||
| - materialisiert (etwa Dictionary Encoding, siehe später)
 | ||
| 
 | ||
| Ordnungserhaltenes Hashen
 | ||
| - Schlüsselwerte werden als 8-Bit-Integer-Werte ohne Vorzeichen kodiert und sind gleichmässig im Bereich $0...2^8-1$ verteilt.
 | ||
| - Die Extraktion der ersten drei Bits ergibt eine ordnungserhaltende Hashfunktion für den Bereich $0...2^3-1$.
 | ||
| - Sind die Schlüsselwerte nicht gleichverteilt, etwa weil es sich um fortlaufend vergebene Nummern handelt, ist das Ergebnis zwar weiterhin ordnungserhaltend, aber die Hash-Tabelle ist sehr ungleichmäßig gefüllt.
 | ||
| 
 | ||
| ## Hardware-sensitives Hashen
 | ||
| Neue Hardware und Hash-Funktionen
 | ||
| - Beobachtung: Hashen mit klassischem Sondieren ungünstig für neue Hardware
 | ||
|   - schwer parallelisierbar
 | ||
|   - Clustern von Werten verletzt Nähe der Werte (bei Cache Lines)
 | ||
| - Varianten versuchen beide Punkte anzugehen
 | ||
|     - Cuckoo-Hashing
 | ||
|     - optimiertes lineares Sondieren
 | ||
|     - Hopscotch-Hashing
 | ||
|     - Robin-Hood-Hashing
 | ||
| 
 | ||
| Cuckoo-Hashen
 | ||
| - Kuckucks-Hashen
 | ||
| - soll Parallelität erhöhen im Vergleich zu linearem Sondieren
 | ||
| - Idee: Zwei Tabellen mit zwei Hash-Funktionen
 | ||
|     - im Fall einer Kollision in einer Tabelle wird in der zweiten Tabelle gesucht
 | ||
|     - ist dort der Platz belegt, wird der dortige Eintrag verdrängt in die jeweils andere Tabelle
 | ||
|           - _Kuckuck wirft Ei aus dem Nest_
 | ||
|     - dies wird solange gemacht bis ein freier Platz gefunden wird
 | ||
| - Beispiel
 | ||
|   - zwei einfache Hash-Funktionen, die jeweils die letzte beziehungsweise vorletzte Dezimalstelle einer Zahl extrahieren
 | ||
|       $h_1(k) = k mod 10$
 | ||
|       $h_2(k) = (k/10) mod 10$
 | ||
|   - Bei einer Suche muss immer in beiden Tabellen nachgeschaut werden, also $T_1[h_1(k)] = k\vee T_2[h_2(k)] = k$.
 | ||
|   - Wir fügen die Zahlen $433, 129$ und $555$ in die Tabelle $T_1$ ein. Beim Einfügen von $783$ ist der Platz in Tabelle $T_1$ belegt, so dass diese Zahl in $T_2$ gespeichert werden muss. Wird nun mit $103$ eine weitere Zahl eingefügt, die mit $433$ unter $h_1$ kollidiert, ist dies mit $h_2$ weiterhin möglich.
 | ||
| 
 | ||
| Cuckoo Beispiel
 | ||
| - Ergebnis des Einfügens von 433, 129 , 555 , 783 , 103
 | ||
| |       | 0   | 1   | 2   | 3   | 4   | 5   | 6   | 7   | 8   | 9   |
 | ||
| | ----- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
 | ||
| | $T_1$ |     |     |     | 433 |     | 555 |     |     |     | 129 |
 | ||
| | $T_2$ | 103 |     |     |     |     |     |     |     | 783 |
 | ||
| - Wird nun die Zahl $889$ eingefügt, so sind beide möglichen Positionen belegt. $889$ kann in $T_1$ die dort stehende Zahl $129$ verdrängen, die in $T_2$ an der Position $T_2[2]$ gespeichert werden kann.
 | ||
| |       | 0   | 1   | 2   | 3   | 4   | 5   | 6   | 7   | 8   | 9   |
 | ||
| | ----- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
 | ||
| | $T_1$ |     |     |     | 433 |     | 555 |     |     |     | 129 |
 | ||
| | $T_2$ | 103 |     | 129 |     |     |     |     |     | 783 |
 | ||
| - Wird nun $789$ eingefügt, sind wiederum beide Positionen belegt. Das Verdrängen von $889$ aus $T_1$ würde zu einem kaskadierenden Verdrängen führen: $889$ würde in $T_2$ dann $783$ verdrängen, das wiederum $433$ in $T_1$ verdrängen würde. Dies würde gehen da $433$ an der Stelle $T_2[3]$ Platz hätte
 | ||
| |       | 0   | 1   | 2   | 3   | 4   | 5   | 6   | 7   | 8   | 9   |
 | ||
| | ----- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
 | ||
| | $T_1$ |     |     |     | 783 |     | 555 |     |     |     | 129 |
 | ||
| | $T_2$ | 103 |     | 129 | 433 |     |     |     |     | 783 |
 | ||
| 
 | ||
| Weitere Prinzipien der Optimierung
 | ||
| - Lokalität von Datenzugriffen verringert die Wahrscheinlichkeit von Cache Misses
 | ||
| - Blockung von Daten kann an die Grösse von Cache-Lines (64 Bytes) angepasst werden, und erhöht den Durchsatz
 | ||
| - Parallelisierung für SIMD basierend auf einer Vektorisierung der Daten kann insbesondere SIMD-basierte Co-Prozessoren gut ausnutzen, aber greift auch bei MICs
 | ||
| 
 | ||
| Optimiertes lineares Sondieren
 | ||
| - Lineares Sondieren ist gut geeignet, um den Sondierungsvorgang auf Vektoren zu parallelisieren
 | ||
|   - Suchschlüssel kann in einen Vektor der Länge $n$ an alle Positionen kopiert werden
 | ||
|   - beginnend ab derem initialen Sondierungspunkt $h(k)$ können dann Vektoren jeweils mit Vektoren aus der Hash-Tabelle verglichen werden, also zuerst mit
 | ||
|     $H[h)k),...,h(k)+n - 1]$, dann mit $H[h(k) + n,...,h(k) + 2n-1 ]$, etc.
 | ||
|   - Vergleich kann parallel erfolgen; muss sowohl auf Vorhandensein von $k$ als auch auf Existenz einer leeren Position prüfen
 | ||
| 
 | ||
| Hopscotch-Hashen
 | ||
| - Hopscotch: _Himmel und Hölle_ beziehungsweise _wild herumhopsen_
 | ||
| - Begrenzung des Sondierungsraum auf eine (konstante) Länge
 | ||
| - Idee:
 | ||
|     - beim Einfügen erfolgt die Suche (parallel) in der festen Nachbarschaft
 | ||
|     - wird Schlüssel $k$ nicht gefunden und existiert kein freier Slot in der festen Nachbarschaft, dann wird versucht, $k$ mit einem anderen Schlüssel aus der festen Nachbarschaft zu tauschen
 | ||
|     - dafür wird die nächste freie Stelle gesucht; von dieser wird rückwärts in Richtung $h(k)$ gesucht und jeder Eintrag $k′$ untersucht
 | ||
|     - wenn die aktuelle freie Stelle noch in der festen Nachbarschaft von $k′$ liegt, wird getauscht: $k′$ springt auf die freie Stelle
 | ||
| 
 | ||
| Robin-Hood-Hashen
 | ||
| - Robin-Hood: _Nimm von den Reichen gib es den Armen_
 | ||
| - Basisidee: in der Situation, dass beim Sondieren für $k$ ein Platz bereits mit einem Element $k′$ besetzt ist, wird der nächste Sondierungsschritt mit demjenigen Element weitergeführt, das die kleinere Distanz zum eigentlichen Hash-Wert $h(k)$ bzw. $h(k′)$ hat
 | ||
| 
 | ||
| ## Dynamische Hash-Verfahren
 | ||
| Lineares Hashen
 | ||
| - Folge von Hash-Funktionen, die wie folgt charakterisiert sind:
 | ||
|   - $h_i$: dom(Primärschlüssel) ->$\{0,..., 2^i \times N\}$ ist eine Folge von Hash-Funktionen mit $i\in\{0,1,2,...\}$ und $N$ als Anfangsgröße des Hash-Verzeichnisses
 | ||
|   - Wert von $i$ wird auch als Level der Hash-Funktion bezeichnet 
 | ||
|   - $dom(Primärschlüssel)$ wird im folgenden als $dom(Prim)$ abgekürzt
 | ||
| - Für diese Hash-Funktionen gelten die folgenden Bedingungen:
 | ||
|     - $h_{i+1}(w) = h_i(w)$ für etwa die Hälfte aller $w\in dom(Prim)$
 | ||
|     - $h_{i+1}(w) = h_i(w) + 2^i\times N$ für die andere Hälfte
 | ||
|   - Bedingungen sind zum Beispiel erfüllt, wenn $h_i(w)$ als $w mod(2^i\times N)$ gewählt wird
 | ||
|   - Darstellung durch Bit-Strings, Hinzunahme eines Bits verdoppelt Bildbereich
 | ||
| 
 | ||
| Prinzip lineares Hashen
 | ||
| - für ein $w$ höchstens zwei Hash-Funktionen zuständig, deren Level nur um 1 differiert, Entscheidung zwischen diesen beiden durch Split-Zeiger
 | ||
|   - $sp$ Split-Zeiger (gibt an, welche Seite als nächstes geteilt wird)
 | ||
|   - $lv$ Level (gibt an, welche Hash-Funktionen benutzt werden)
 | ||
| - Aus Split-Zeiger und Level läßt sich die Gesamtanzahl $Anz$ der belegten Seiten wie folgt berechnen:
 | ||
|   - $Anz = 2^{lv} + sp$
 | ||
| - Beide Werte werden am Anfang mit 0 initialisiert.
 | ||
| 
 | ||
| 
 | ||
| Lookup
 | ||
| - $$s := h_{lv}(w)$;
 | ||
| - if $s < sp$
 | ||
| - then $s := h_{lv + 1}(w)$;
 | ||
| - zuerst Hash-Wert mit der "kleineren" Hash-Funktion bestimmen
 | ||
| - liegt dieser unter dem Wert des Split-Zeigers => größere Hash-Funktion verwenden
 | ||
| 
 | ||
| Splitten einer Seite
 | ||
| 1. Die Sätze der Seite (Bucket), auf die $sp$ zeigt, werden mittels $h_{lv+1}$ neu verteilt (ca. die Hälfte der Sätze wird auf Seite (Bucket) unter Hash-Nummer $2^{lv}*N +sp$ verschoben)
 | ||
| 2. Der Split-Zeiger wird weitergesetzt: $sp:=sp +1;$
 | ||
| 3. Nach Abarbeiten eines Levels wird wieder bei Seite 0 begonnen; der Level wird um 1 erhöht:
 | ||
| 
 | ||
| ```
 | ||
| if sp = 2^{lv} * N then
 | ||
|     begin
 | ||
|         lv := lv + 1 ;
 | ||
|         sp := 0
 | ||
|     end;
 | ||
| ```
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| Problem lineares Hashen
 | ||
| 
 | ||
| 
 | ||
| Erweiterbares Hashen
 | ||
| - Problem: Split erfolgt an fester Position, nicht dort wo Seiten überlaufen
 | ||
| - Idee: binärer Trie zum Zugriff auf Indexseiten
 | ||
| - Blätter unterschiedlicher Tiefe
 | ||
|     - Indexseiten haben Tiefenwert
 | ||
|     - Split erfolgt bei Überlauf
 | ||
| - aber: Speicherung nicht als Trie, sondern als Array
 | ||
|     - entspricht vollständigem Trie mit maximaler Tiefe
 | ||
|        - "shared" Seiten als Blätter
 | ||
|     - Array der Grösse 2 _d_ für maximale Tiefe _d_
 | ||
|        - erfordert nun nur einen Speicherzugriff!
 | ||
|     - bei Überlauf: Indexgrösse muss möglicherweise verdoppelt werden!
 | ||
| - Ausgangslage:
 | ||
|     - Einfügen von 00111111 würde Überlauf bei erreichter maximaler Tiefe erzeugen
 | ||
|         
 | ||
|     - Verdopplung der Indexgrösse
 | ||
|         
 | ||
|     - nun möglich: Split der Seite
 | ||
|         
 | ||
| 
 | ||
| Variante: Array als Trie gespeichert
 | ||
| 
 | ||
| 
 | ||
| Spiral-Hashen
 | ||
| - Problem: zyklisch erhöhte Wahrscheinlichkeit des Splittens
 | ||
| - Lösung: unterschiedliche Dichte der Hashwerte
 | ||
|     - Interpretation der Bit-Strings als binäre Nachkommadarstellung einer Zahl zwischen $0.0$ und $1.0$
 | ||
|     - Funktion von $[0.0,1.0] -> [0.0,1.0]$ so dass Dichte gleichmässig verteilter Werte nahe $1.0$ doppelt so gross ist wie nahe $0.0$
 | ||
| - Umverteilung mittels Exponentialfunktion
 | ||
| - Funktion $exp(n)$   $exp(n) = 2^n - 1$ erfüllt die Bedingungen
 | ||
| - insbesondere gilt $2^0 - 1 = 0$ und $2^1 - 1 = 1$
 | ||
| - Hashfunktion exhash
 | ||
|     $exhash(k) = exp(h(k)) = 2^{h(k)} - 1$
 | ||
| - Wirkung der verwendeten Hashfunktion im Intervall $0.0$ bis $1.0$
 | ||
|     | $n$   | $2^n-1$     |
 | ||
|     | ----- | ----------- |
 | ||
|     | $0.0$ | $0.0$       |
 | ||
|     | $0.1$ | $0.0717735$ |
 | ||
|     | $0.2$ | $0.1486984$ |
 | ||
|     | $0.3$ | $0.2311444$ |
 | ||
|     | $0.4$ | $0.3195079$ |
 | ||
|     | $0.5$ | $0.4142136$ |
 | ||
|     | $0.6$ | $0.5157166$ |
 | ||
|     | $0.7$ | $0.6245048$ |
 | ||
|     | $0.8$ | $0.7411011$ |
 | ||
|     | $0.9$ | $0.866066$  |
 | ||
|     | $1.0$ | $1.0$       |
 | ||
| - Spiralförmiges Ausbreiten
 | ||
|     - Ausgangslage: 4 Seiten der Tiefe 2
 | ||
|     
 | ||
| - Spiralförmiges Ausbreiten
 | ||
|     - Split der Seite mit der höchsten Dichte
 | ||
|     - Ergebnis: 5 Seiten, davon 3 der Tiefe 2 und 2 der Tiefe 3
 | ||
|     
 | ||
| 
 | ||
| ## Grid-File
 | ||
| Grid-Files
 | ||
| - bekannteste und von der Technik her attraktive mehrdimensionale Dateiorganisationsform
 | ||
| - eigene Kategorie: Elemente der Schlüsseltransformation wie bei Hashverfahren und Indexdateien wie bei Baumverfahren kombiniert
 | ||
|   - deshalb hier bei Hash-Verfahren betrachtet
 | ||
| 
 | ||
| Grid-File: Zielsetzungen
 | ||
| - Prinzip der 2 Plattenzugriffe: Jeder Datensatz soll bei einer _exact-match_ -Anfrage in 2 Zugriffen erreichbar sein
 | ||
| - Zerlegung des Datenraums in Quader: _n_ -dimensionale Quader bilden die Suchregionen im Grid-File
 | ||
| - Prinzip der Nachbarschaftserhaltung: Ähnliche Objekte sollten auf der gleichen Seite gespeichert werden
 | ||
| - Symmetrische Behandlung aller Raum-Dimensionen: _partial-match_ -Anfragen ermöglicht
 | ||
| - Dynamische Anpassung der Grid-Struktur beim Löschen und Einfügen
 | ||
| 
 | ||
| Prinzip der zwei Plattenzugriffe
 | ||
| - bei exact-match
 | ||
|     1. gesuchtes $k$ -Tupel auf Intervalle der Skalen abbilden; als Kombination der ermittelten Intervalle werden Indexwerte errechnet; Skalen im Hauptspeicher => noch kein Plattenzugriff
 | ||
|     2. über errechnete Indexwerte Zugriff auf das _Grid-Directory_ ; dort Adressen der Datensatz-Seiten gespeichert; erster _Plattenzugriff_.
 | ||
|     3. Der Datensatz-Zugriff: zweiter _Plattenzugriff_.
 | ||
| 
 | ||
| Aufbau eines Grid-Files
 | ||
| 
 | ||
| - Grid: $k$ eindimensionale Felder (Skalen), jede Skala repräsentiert Attribut
 | ||
| - _Skalen_ bestehen aus Partition der zugeordneten Wertebereiche in Intervalle
 | ||
| - Grid-Directory besteht aus Grid-Zellen, die den Datenraum in Quader zerlegen
 | ||
| - Grid-Zellen bilden eine Grid-Region, der genau eine Datensatz-Seite zugeordnet wird
 | ||
| - Grid-Region: $k$-dimensionales, konvexes (Regionen sind paarweise disjunkt)
 | ||
| 
 | ||
| Operationen
 | ||
| - Zu Anfang: Zelle = Region = eine Datensatz-Seite
 | ||
| - Seitenüberlauf:
 | ||
|     - Seite wird geteilt
 | ||
|     - falls zugehörige Gridregion aus nur einer Gridzelle besteht, muss ein Intervall auf einer Skala in zwei Intervalle unterteilt werden
 | ||
|     - besteht Region aus mehreren Zellen, so werden diese Zellen in einzelne Regionen zerlegt
 | ||
| - Seitenunterlauf:
 | ||
|     - Zwei Regionen zu einer zusammenfassen, falls das Ergebnis eine neue, konvexe Region ergibt
 | ||
| 
 | ||
| Beispiel
 | ||
| - Start-Grid-File
 | ||
|     
 | ||
|     - Datensätze einfügen: $(45,D),(2,B),(87,S),(75,M),(55,K),(3,Y),(15,D),(25,K),(48,F)$
 | ||
|     - jede Seite des Grid-Files fasst bis zu drei Datensätze
 | ||
| - Eingefügt: $(45, D), (2, B), (87, S)$
 | ||
|     
 | ||
| - Einfügen von $(75, M)$ erzwingt Split
 | ||
|     
 | ||
| - Eingefügt: $(55, K)$
 | ||
|     
 | ||
| - Einfügen von $(3, Y)$ erzwingt wiederum einen Split
 | ||
|     
 | ||
| - Eingefügt: (15, D), (25, K),
 | ||
|     
 | ||
| - Einfügen von (48, F) erzwingt wiederum einen Split
 | ||
|     
 | ||
| 
 | ||
| 
 | ||
| Buddy-System
 | ||
| - Beschriebenes Verfahren: Buddy-System (Zwillings-System)
 | ||
| - Die im gleichen Schritt entstandenen Zellen können zu Regionen zusammengefasst werden; Keine andere Zusammenfassung von Zellen ist im Buddy-System erlaubt
 | ||
| - Unflexibel beim Löschen: nur Zusammenfassungen von Regionen erlaubt, die vorher als Zwillinge entstanden waren
 | ||
| - Beispiel: $(15,D)$ löschen: Seiten 1 und 4 zusammenfassen; $(87,S)$ löschen, Seite 2 zwar unterbelegt, kann aber mit keiner anderen Seite zusammengefasst werden
 | ||
| 
 | ||
| # Weitere Indexstrukturen
 | ||
| ## Bitmap-Indexe
 | ||
| Bitmap-Indexe
 | ||
| - Idee: _Bit-Vektor_ zur Kodierung der Tupel-Attributwert-Zuordnung
 | ||
| - Vergleich mit baumbasierten Indexstrukturen:
 | ||
|     - vermeidet degenerierte B-Bäume
 | ||
|     - unempfindlicher gegenüber höherer Zahl von Attributen
 | ||
|     - einfachere Unterstützung von Anfragen, in denen nur einige (der indexierten) Attribute beschränkt werden
 | ||
|     - dafür aber i.allg. höhere Aktualisierungskosten
 | ||
|        - beispielsweise in Data Warehouses wegen des überwiegend lesenden Zugriffs unproblematisch
 | ||
| 
 | ||
| Bitmap-Index: Realisierung
 | ||
| - Prinzip: Ersetzung der TIDs (rowid) für einen Schlüsselwert im $b$ +-Baum durch Bitvektor
 | ||
| - Knotenaufbau: $|B: 0 1001 0...0 1 | F: 1 01 000... 10  | O: 000 101 ...00 |$
 | ||
| - Vorteil: geringerer Speicherbedarf
 | ||
|     - Beispiel: 150.000 Tupel, 3 verschiedene Schlüsselwerte, 4 Byte für TID
 | ||
|           - B+-Baum: 600 KB
 | ||
|           - Bitmap: $3*18750 Byte =56KB$
 | ||
| - Nachteil: Aktualisierungsaufwand
 | ||
| - Definition in Oracle
 | ||
|     ```sql
 | ||
|     CREATE BITMAP INDEX bestellstatus_idx ON bestellung(status);
 | ||
|     ```
 | ||
| - Speicherung in komprimierter Form
 | ||
| 
 | ||
| Standard-Bitmap-Index
 | ||
| - jedes Attribut wird getrennt abgespeichert
 | ||
| - für jede Ausprägung eines Attributs wird ein
 | ||
|     Bitmap-Vektor angelegt:
 | ||
|        - für jedes Tupel steht ein Bit, dieses wird auf 1 gesetzt, wenn das indexierte Attribut in dem Tupel den Referenzwert dieses Bitmap-Vektors enthält
 | ||
|        - die Anzahl der entstehenden Bitmap-Vektoren pro Dimension entspricht der Anzahl der unterschiedlichen Werte, die für das Attribut vorkommen
 | ||
| - Beispiel: Attribut Geschlecht
 | ||
|     - 2 Wertausprägungen (m/w)
 | ||
|     - 2 Bitmap-Vektoren
 | ||
|     | PersId | Name | Geschlecht | Bitmap-w | Bitmap-m |
 | ||
|     | --- | --- | --- | --- | --- |
 | ||
|     007 |James Bond |M |0 |1
 | ||
|     008 |Amelie Lux |W |1 |0
 | ||
|     010 |Harald Schmidt |M |0 |1
 | ||
|     011 |Heike Drechsler |W |1 |0
 | ||
| - Selektion von Tupeln kann nun durch entsprechende Verknüpfung von Bitmap-Vektoren erfolgen
 | ||
| - Beispiel: Bitmap-Index über Attribute Geschlecht und Geburtsmonat
 | ||
|   - (d.h. 2 Bitmap-Vektoren B-w und B-m für Geschlecht und 12 Bitmap-Vektoren B-1, ..., B-12 für die Monate, wenn alle Monate vorkommen)
 | ||
| - Anfrage: "alle im März geborenen Frauen"
 | ||
|     - Berechnung: $B-w \wedge B-3$ (bitweise konjunktiv verknüpft)
 | ||
|     - Ergebnis: alle Tupel, an deren Position im Bitmap-Vektor des Ergebnis eine 1 steht
 | ||
| 
 | ||
| Mehrkomponenten-Bitmap-Index
 | ||
| - bei Standard-Bitmap-Indexe entstehen für Attribute mit vielen Ausprägungen sehr viele Bitmap-Vektoren
 | ||
| - $<n,m>$-Mehrkomponenten-Bitmap-Indexe erlauben $n*m$ mögliche Werte durch $n+m$ Bitmap-Vektoren zu
 | ||
|     indexieren
 | ||
| - jeder Wert $x(0\leq x\leq n*m-1)$ kann durch zwei Werte $y$ und $z$ repräsentiert werden:
 | ||
|     $x=n*y+z$ mit $0\leq y\leq m-1$ und $0\leq z\leq n-1$
 | ||
|     - dann nur noch maximal $m$ Bitmap-Vektoren für $y$ und $n$ Bitmap-Vektoren für $z$
 | ||
|     - Speicheraufwand reduziert sich von $n*m$ auf $n+m$
 | ||
|     - dafür müssen für eine Punktanfrage aber 2 Bitmap-Vektoren gelesen werden
 | ||
| - Beispiel: Zweikomponenten-Bitmap-Index
 | ||
|     - Für $M= 0 ..11$ etwa $x= 4*y + z$
 | ||
|     - y-Werte: $B-2-1, B-1-1, B-0-1$
 | ||
|     - z-Werte: $B-3-0, B-2-0, B-1-0, B-0-0$
 | ||
|     | x|  y | || z |||||
 | ||
|     | --- | --- | --- | --- | --- | --- | --- | --- |
 | ||
|     | M | B-2-1 | B-1-1 | B-0-1| B-3-0| B-2-0| B-1-0| B-0-0
 | ||
|     |5| 0 |1 |0 |0 |0 |1 |0
 | ||
|     |3| 0 |0 |1 |1 |0 |0 |0
 | ||
|     |0| 0 |0 |1 |0 |0 |0 |1
 | ||
|     |11| 1| 0 |0| 1 |0| 0 |0
 | ||
| 
 | ||
| Beispiel: Postleitzahlen
 | ||
| - Kodierung von Postleitzahlen
 | ||
| - Werte 00000 bis 99999
 | ||
| - direkte Umsetzung: 100.000 Spalten
 | ||
| - Zweikomponenten-Bitmap-Index (erste 2 Ziffern + 3 letzte Ziffern): 1.100 Spalten
 | ||
| - Fünf Komponenten: 50 Spalten
 | ||
|     - geeignet für Bereichsanfragen "PLZ 39***"
 | ||
| - Binärkodiert (bis $2^17$): 34 Spalten
 | ||
|     - nur für Punktanfragen!
 | ||
| - Bemerkung: Kodierung zur Basis 3 ergibt sogar nur 33 Spalten...
 | ||
| 
 | ||
| ## Indexierung von Texten
 | ||
| Indexierung von Texten
 | ||
| - bisher vorgestellte Verfahren unterstützen prinzipiell auch die Indexierung von Zeichenketten
 | ||
| - Probleme bereitet folgendes:
 | ||
|     - unterschiedliche Längen der Zeichenketten als Suchschlüssel
 | ||
|     - bei Sätzen: Zugriff auf einzelne Wörter bevorzugt
 | ||
|     - Ähnlichkeiten u.a. über gemeinsame Präfixe und Editierabstand
 | ||
| 
 | ||
| Digital- und Präfixbäume
 | ||
| - B-Bäume: Problem bei zu indexierenden Zeichenketten
 | ||
| - Lösung: Digital- oder Präfixbäume
 | ||
| - Digitalbäume indexieren (fest) die Buchstaben des zugrundeliegenden Alphabets
 | ||
| - können dafür unausgeglichen werden
 | ||
| - Beispiele: Tries, Patricia-Bäume
 | ||
| - Präfixbäume indexieren Präfix der Zeichenketten
 | ||
| 
 | ||
| Tries
 | ||
| - von "Information Retrieval", aber wie try gesprochen
 | ||
|     - Abgrenzung vom _tree_ für allgemeine Suchbäume
 | ||
|     
 | ||
| - Knoten eines Tries
 | ||
|     
 | ||
|     - Probleme: lange gemeinsame Teilworte, nicht vorhandenen Buchstaben und Buchstabenkombinationen, möglicherweise leere Knoten, sehr unausgeglichene Bäume
 | ||
| 
 | ||
| Patricia-Bäume
 | ||
| - Tries: Probleme bei Teilekennzahlen, Pfadnamen, URLs (lange gemeinsame Teilworte)
 | ||
| - Lösung: Practical Algorithm To Retrieve Information Coded In Alphanumeric (Patricia)
 | ||
| - Prinzip: Überspringen von Teilworten
 | ||
| - Problem: Datenbanksprache bei Suchbegriff _Triebwerksperre_
 | ||
| 
 | ||
| Patricia-Baum und Trie im Vergleich
 | ||
| 
 | ||
| - übersprungene Teilworte zusätzlich speichern: Präfix-Bäume
 | ||
| 
 | ||
| 
 | ||
| Präfix-Bäume
 | ||
| - Patricia-Baum plus Abspeicherung der übersprungenen Präfixe
 | ||
|     
 | ||
| 
 | ||
| Invertierte Listen
 | ||
| - indizierte Worte (Zeichenketten) bilden eine lexikographisch sortierte Liste
 | ||
| - einzelner Eintrag besteht aus einem _Wort_ und einer Liste von Dokument-Identifikatoren derjenigen Dokumente, in denen das Wort vorkommt
 | ||
| - zusätzlich können weitere Informationen für die Wort-Dokument-Kombination abgespeichert werden:
 | ||
|     - Position des (ersten Auftretens des) Wortes im Text
 | ||
|     - Häufigkeit des Wortes im Text
 | ||
| 
 | ||
| Invertierte Listen
 | ||
|     
 | ||
| 
 | ||
| ## Mehrdimensionale Speichertechniken
 | ||
| Mehrdimensionale Speichertechniken
 | ||
| - bisher: eindimensional (keine partial-match-Anfragen, nur lineare Ordnung)
 | ||
| - jetzt: mehrdimensional (auch partial-match-Anfragen, Positionierung im mehrdimensionalen Datenraum)
 | ||
| - $k$ Dimensionen = $k$ Attribute können gleichberechtigt unterstützt werden
 | ||
| - dieser Abschnitt
 | ||
|     - mehrdimensionaler B-Baum
 | ||
|     - mehrdimensionales Hashverfahren
 | ||
| 
 | ||
| ## Mehrdimensionale Baumverfahren
 | ||
| Mehrdimensionale Baumverfahren
 | ||
| - KdB-Baum ist B+-Baum, bei dem Indexseiten als binäre Bäume mit Zugriffsattributen, Zugriffsattributwerten und Zeigern realisiert werden
 | ||
| - Varianten von $k$ -dimensionalen Indexbäumen:
 | ||
|     - _kd-Baum_ von Bentley und Friedman: für Hauptspeicheralgorithmen entwickelte, mehrdimensionale Grundstruktur (binärer Baum)
 | ||
|     - _KDB-Baum_ von Robinson: Kombination kd-Baum und B-Baum ( $k$ -dimensionaler Indexbaum bekommt höheren Verzweigungsgrad)
 | ||
|     - _KdB-Baum_ von Kuchen: Verbesserung des Robinson-Vorschlags, wird hier behandelt
 | ||
| - KdB-Baum kann Primär- und mehrere Sekundärschlüssel gleichzeitig unterstützen
 | ||
| - macht als Dateiorganisationsform zusätzliche Sekundärindexe überflüssig
 | ||
| 
 | ||
| Definition KdB-Baum
 | ||
| - Idee: auf jeder Indexseite einen Teilbaum darstellen, der nach mehreren Attributen hintereinander verzweigt
 | ||
|     - _KdB-Baum vom Typ_ ( $b$ , $t$ ) besteht aus
 | ||
|         - inneren Knoten (Bereichsseiten) die einen _kd-Baum_ mit maximal $b$ internen Knoten enthalten
 | ||
|         - Blättern (Satzseiten) die bis zu $t$ Tupel der gespeicherten Relation speichern können
 | ||
|     - Bereichsseiten: _kd-Baum_ enthalten mit Schnittelementen und zwei Zeigern
 | ||
|         - Schnittelement enthält Zugriffsattribut und Zugriffsattributwert; 
 | ||
|         - linker Zeiger: kleinere Zugriffsattributwerte; 
 | ||
|         - rechter Zeiger: größere Zugriffsattributwerte
 | ||
| 
 | ||
| Beispiel
 | ||
| 
 | ||
| 
 | ||
| KdB-Baum: Struktur
 | ||
| - Bereichsseiten
 | ||
|     - Anzahl der Schnitt- und Adressenelemente der Seite
 | ||
|     - Zeiger auf Wurzel des in der Seite enthaltenen kd-Baumes
 | ||
|     - Schnitt- und Adressenelemente.
 | ||
| - Schnittelement
 | ||
|     - Zugriffsattribut
 | ||
|     - Zugriffsattributwert
 | ||
|     - zwei Zeiger auf Nachfolgerknoten des kd-Baumes dieser Seite (können Schnitt- oder Adressenelemente sein)
 | ||
| - Adressenelemente: Adresse eines Nachfolgers der Bereichsseite im KdB-Baum (Bereichs- oder Satzseite)
 | ||
| 
 | ||
| KdB-Baum: Operationen
 | ||
| - Komplexität $lookup$, $insert$ und $delete$ bei exact-match $O(log n)$
 | ||
| - bei partial-match besser als $O(n)$
 | ||
| - bei $t$ von $k$ Attributen in der Anfrage spezifiziert: Zugriffskomplexität von $O(n^{1-t/k})$
 | ||
| 
 | ||
| KdB-Baum: Trennattribute
 | ||
| - Reihenfolge der Trennattribute
 | ||
|     - entweder zyklisch festgelegt
 | ||
|     - oder Selektivitäten einbeziehen: Zugriffsattribut mit hoher Selektivität sollte früher und häufiger als Schnittelement eingesetzt werden
 | ||
| - Trennattributwert: aufgrund von Informationen über Verteilung von Attributwerten eine geeignete "Mitte" eines aufzutrennenden Attributwertebereichs ermitteln
 | ||
| 
 | ||
| 
 | ||
| KdB-Baum: Brickwall
 | ||
| 
 | ||
| 
 | ||
| ## Mehrdimensionales Hashen
 | ||
| Mehrdimensionales Hashen
 | ||
| - Idee: Bit Interleaving
 | ||
| - abwechselnd von verschiedenen Zugriffsattributwerten die Bits der Adresse berechnen
 | ||
| - Beispiel: zwei Dimensionen
 | ||
|     | | *0*0 | *0*1 | *1*0| *1*1|
 | ||
|     | --- | --- | --- | --- | --- |
 | ||
|     0*0*| 0000 |0001 |0100 |0101
 | ||
|     0*1*| 0010 |0011 |0110 |0111
 | ||
|     1*0*| 1000 |1001 |1100 |1101
 | ||
|     1*1*| 1010 |1011 |1110 |1111
 | ||
| 
 | ||
| MDH von Kuchen
 | ||
| - MDH baut auf linearem Hashen auf
 | ||
| - Hash-Werte sind Bitfolgen, von denen jeweils ein Anfangsstück als aktueller Hashwert dient
 | ||
| - je ein Bitstring pro beteiligtem Attribut berechnen
 | ||
| - Anfangsstücke nun nach dem Prinzip des Bit-Interleaving zyklisch abarbeiten
 | ||
| - Hashwert reihum aus den Bits der Einzelwerte zusammensetzen
 | ||
| 
 | ||
| MDH formal
 | ||
| - mehrdimensionaler Wert $x := (x_1,..., x_k)\in D = D_1\times ...\times D_k$
 | ||
| - Folge von mit _i_ indizierten Hashfunktionen konstruieren
 | ||
| - _i_-te Hashfunktion $h_i(x)$ wird mittels Kompositionsfunktion $\bar{h}_i$ aus den jeweiligen $i$ -ten Anfangsstücken der lokalen Hash-Werte $h_{i_j}(x_j)$ zusammengesetzt: $h_i(x)=\bar{h}_i(h_{i_1}(x_1),...,h_{i_k}(x_k))$
 | ||
| - lokale Hashfunktionen $h_{i_j}$ ergeben jeweils Bitvektor der Länge $z_{i_j} +1$:$h_{i_j} : D_j\rightarrow \{0,..., z_{i_j}\}, j\in\{1 ,..., k\}$
 | ||
| - $z_{i_j}$ sollten möglichst gleich groß sein, um die Dimensionen gleichmäßig zu berücksichtigen
 | ||
| - Kompositionsfunktion $\bar{h}_i$ setzt lokale Bitvektoren zu einem Bitvektor der Länge $i$ zusammen: $\bar{h}_i:\{0,...,z_{i1}\times ...\times\{0,..., z_{i_k}\}\rightarrow\{0,...,2^{i+1}-1\}$
 | ||
| - ausgeglichene Länge der $z_{i_j}$ wird durch folgende Festlegung bestimmt, die Längen zyklisch bei jedem Erweiterungsschritt an einer Stelle erhöht:
 | ||
|     $$z_{i_j} = \begin{cases} 2^{\lfloor \frac{i}{k}\rfloor +1} -1 \quad\text{ für } j-1\leq (i mod k)\\ 2^{\lfloor \frac{i}{k}\rfloor} -1 \quad\text{ für } j-1 > (i mod k) \end{cases}$$
 | ||
| - Kompositionsfunktion:
 | ||
|     $$\bar{h}_i(x)=\sum_{r=0}^i (\frac{(x_{(r mod k)+1} mod 2^{\lfloor \frac{r}{k}\rfloor +1}) - (x_{(r mod k)+1} mod 2^{\lfloor \frac{r}{k}\rfloor})}{2^{\lfloor \frac{r}{k}\rfloor})}) 2^r$$
 | ||
| 
 | ||
| MDH Veranschaulichung
 | ||
| 
 | ||
| - verdeutlicht Komposition der Hashfunktion $h_i$ für drei Dimensionen und den Wert $i=7$
 | ||
| - graphisch unterlegte Teile der Bitstrings entsprechen den Werten $h_{7_1}(x_1),h_{7_2}(x_2)$ und $h_{7_3}(x_3)$
 | ||
| - beim Schritt auf $i=8$ würde ein weiteres Bit von $x_2$ (genauer: von $h_{8_2}(x_2)$) verwendet
 | ||
| 
 | ||
| MDH Komplexität
 | ||
| - Exact-Match-Anfragen: $O(1)$
 | ||
| - Partial-Match-Anfragen, bei $t$ von $k$ Attributen festgelegt, Aufwand $O(n^{1-\frac{t}{k}})$
 | ||
| - ergibt sich aus der Zahl der Seiten, wenn bestimmte Bits "unknown"
 | ||
| - Spezialfälle: $O(1)$ für $t=k$, $O(n)$ für $t=0$
 | ||
| 
 | ||
| ## Geometrische Zugriffsstrukturen
 | ||
| Geometrische Zugriffsstrukturen
 | ||
| - große Mengen geometrischer Objekte ($> 10^6$)
 | ||
| - Eigenschaften geometrischer Objekte
 | ||
|     - Geometrie (etwa Polygonzug)
 | ||
|     - zur Unterstützung bei Anfragen: zusätzlich $d$-dimensionales umschreibendes Rechteck (bounding
 | ||
|        box)
 | ||
|     - nichtgeometrische Attribute
 | ||
| - Anwendungsszenarien: Geoinformationssysteme (Katasterdaten, Karten), CAx-Anwendungen (etwa VLSI
 | ||
|     Entwurf), ...
 | ||
| - Zugriff primär über Geometriedaten: Suchfenster (Bildschirmausschnitt), Zugriff auf benachbarte Objekte
 | ||
| 
 | ||
| Typische Operationen
 | ||
| - exakte Suche
 | ||
|     - Vorgabe: exakte geometrische Suchdaten
 | ||
|     - Ergebnis: maximal ein Objekt
 | ||
| - Bereichsanfrage für vorgegebenes $n$-dimensionales Fenster
 | ||
|     - Suchfenster: $d$-dimensionales Rechteck (entspricht mehrdimensionalem Intervall)
 | ||
|     - Ergebnis sind alle geometrischen Objekte, die das Suchfenster schneiden
 | ||
|     - Ergebnisgröße parameterabhängig
 | ||
| - Einfügen von geometrischen Objekten
 | ||
|     - wünschenswert ohne globale Reorganisation!
 | ||
| - Löschen von geometrischen Objekten
 | ||
|     - wünschenswert ohne globale Reorganisation!
 | ||
| 
 | ||
| Nachbarschaftserhaltende Suchbäume
 | ||
| - Aufteilung des geometrischen Bereichs in Regionen
 | ||
| - benachbarte Objekte wenn möglich der selben Region zuordnen
 | ||
| - falls dieses nicht geht, diese auf benachbarte Regionen aufteilen
 | ||
| - Baumstruktur entsteht durch Verfeinerung von Regionen in benachbarte Teilregionen
 | ||
| - Speicherung von Objekten erfolgt in den Blattregionen
 | ||
| - Freiheitsgrade
 | ||
|     - Form der Regionen
 | ||
|     - vollständige Partitionierung oder Überlappung durch die Regionen
 | ||
|     - eindeutige Zuordnung von Objekten zu Regionen oder Mehrfachzuordnung
 | ||
|     - Speicherung und Zugriff über Originalgeometrie oder über abgeleitete Geometrie für Objekte
 | ||
|     - Grad des Baumes & Organisationsform
 | ||
| 
 | ||
| Mehrstufige Bearbeitung geom. Anfragen
 | ||
| 
 | ||
| 
 | ||
| Geom. Baumstruktur: BSP-Baum
 | ||
| - Binary Space Partitioning: schrittweises binäres Teilen des Datenraums
 | ||
| 
 | ||
| 
 | ||
| Realisierungsvarianten
 | ||
| | Alternative | Baumstrukturen | | |
 | ||
| | --- | --- | --- | --- |
 | ||
| | | BSP-Baum | R-Baum | R+-Baum |
 | ||
| Regionenform | konvexe Polygone |Rechtecke| Rechtecke|
 | ||
| Teilregionen |vollständig |unvollständig |unvollständig|
 | ||
| Überlappung |nein |ja |nein|
 | ||
| ausgeglichen |nein |ja |ja|
 | ||
| 
 | ||
| R-Bäume
 | ||
| - R-Baum: Verallgemeinerung des B-Baum-Prinzips auf mehrere Dimensionen
 | ||
|     - Baumwurzel entspricht einem Rechteck, das alle geometrischen Objekte umfasst
 | ||
|     - Geo-Objekte werden durch ihre umschließenden Rechtecke repräsentiert
 | ||
|     - Aufteilung in Regionen erfolgt in nichtdisjunkte Rechtecke
 | ||
|     - Jedes Geo-Objekt ist eindeutig einem Blatt zugeordnet
 | ||
| - Regionenaufteilung durch Rechtecke im R-Baum
 | ||
|     
 | ||
| - Baumstruktur für R-Baum
 | ||
|     
 | ||
| 
 | ||
| Probleme mit R-Bäumen
 | ||
| - gegebenes Rechteck kann von vielen Regionen überlappt werden, es ist aber genau in einer Region gespeichert
 | ||
| - auch Punktanfragen können eine Suche in sehr vielen Rechteckregionen bedeuten
 | ||
| - Ineffizient bei exakter Suche (exakte Suche auch bei Einfügen und Löschen notwendig!)
 | ||
| - Probleme beim Einfügen
 | ||
|     - Einfügen erfordert oft Vergrößern von Regionen (aufwärts propagiert)
 | ||
| 
 | ||
| Vergrößern beim Einfügen
 | ||
| 
 | ||
| 
 | ||
| R+-Bäume
 | ||
| - R+-Bäume: Aufteilung in Teilregionen disjunkt
 | ||
| - Jedem gespeicherten Punkt des geometrischen Bereichs ist eindeutig ein Blatt zugeordnet
 | ||
| - In jeder Baumebene ist einem Punkt ebenfalls maximal ein Rechteck zugeordnet -> eindeutiger Pfad von der Wurzel zum speichernden Blatt
 | ||
| - ‘Clipping’ von Geo-Objekten notwendig!
 | ||
|     
 | ||
|     
 | ||
| 
 | ||
| Probleme mit R+-Bäumen
 | ||
| - Objekte müssen in mehreren Rechteckregionen gespeichert werden (clipping) - erhöhter Speicher- & Modifikationsaufwand
 | ||
| - Einfügen von Objekten erfordert möglicherweise Modifikation mehrerer Rechteckregionen
 | ||
|     
 | ||
| - Einfügen kann in bestimmten Situationen unvermeidbar zu Regionenaufteilungen führen
 | ||
|     
 | ||
| - Regionenmodifikationen haben Konsequenzen sowohl in Richtung Blätter als auch in Richtung Wurzel
 | ||
| - obere Grenze für Einträge in Blattknoten kann nicht mehr garantiert werden
 | ||
| 
 | ||
| Rechteckspeicherung durch Punktdatenstrukturen
 | ||
| - Probleme bei ausgedehnten Geometrien -> Entartung
 | ||
| - Nutzung "robuster" mehrdimensionaler Indexstrukturen (z.B. Grid-File) durch Abbildung von Rechtecken auf Punkte möglich?
 | ||
| 
 | ||
| Punktdatenstrukturen
 | ||
| - Rechteckspeicherung durch Punktdatenstrukturen
 | ||
|     - Transformation von ausgedehnten Objekten (mehrdimensionale Rechtecke) in Punktdaten
 | ||
|     - Transformation bildet $d$-dimensionale Rechtecke auf Punkte im $2d$-dimensionalen Raum $R^{2d}$ ab
 | ||
|     - $d$-dimensionale Rechteck: $r=[l_1, r_1]\times ...\times [l_d, r_d]$
 | ||
| - Eckentransformation
 | ||
|     $p_r = (l_1, r_1,..., l_d, r_d) \in R^{2d}$
 | ||
|     pro Intervall als Koordinaten: obere Schranke, untere Schranke
 | ||
| - Mittentransformation $p_r =(\frac{l_1+r_1}{2}, \frac{r_1-l_1}{2},...,\frac{l_d+l_r}{2},\frac{r_d-l_d}{2})\in\mathbb{R}^{2d}$
 | ||
|     pro Intervall als Koordinaten: Mittelpunkt, halbe Breite
 | ||
| 
 | ||
| Eckentransformation
 | ||
| 
 | ||
| 
 | ||
| Mittentransformation
 | ||
| 
 | ||
| 
 | ||
| Suchfenster
 | ||
| 
 | ||
| 
 | ||
| Grid-File-Degeneration
 | ||
| 
 | ||
| 
 | ||
| ## Approximierende Verfahren
 | ||
| Approximierende Verfahren
 | ||
| - insbesondere für hochdimensionale Daten
 | ||
| - pro Tupel einen approximierenden Bit-Code mit nur wenigen Bits pro Dimensionen
 | ||
|        - beispielsweise ein Grid mit jeweils $2^k$ Bit pro Dimension
 | ||
|        - ordnungserhaltend wenn die Bits geeignet gewählt werden
 | ||
|        - adressiert werden die Zellen in denen ein Punkt liegt
 | ||
|        - Nutzung zur Nachbarschaftssuche in hochdimensionalen Räumen
 | ||
| - VA-File von Weber et al.
 | ||
|     - ersetzt Durchlauf über alle Punkte durch Durchlauf über alle Approximationswerte zur Vorauswahl von Kandidaten
 | ||
| 
 | ||
| VA-File
 | ||
| 
 | ||
| 
 | ||
| Zusammenfassung
 | ||
| - Bitmap-Indexe
 | ||
| - Digital- und Präfixbäume
 | ||
| - Mehrdimensionale Verfahren
 | ||
| - Geometrische Zugriffsstrukturen
 |