Databases Samenvatting

Databases Samenvatting
Dieter Castel
Jonas Devlieghere
Karel Domin
Giel Dops
Dennis Frett
Kevin Fockaert
Kenneth Geets
John Gybels
Laurent Janssens
Ben Lefevere
13 januari 2015
Inhoudsopgave
1 Introduction to Databases
1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2 An Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.3 Characteristics of the Database Approach . . . . . . . . . . . . . . . . . . . . . . .
1.3.1 Self-Describing Nature of a Database System . . . . . . . . . . . . . . . . . .
1.3.2 Insulation between Programs and Data, and Data Abstraction . . . . . . . .
1.3.3 Support of Multiple Views of the Data . . . . . . . . . . . . . . . . . . . . .
1.3.4 Sharing of Data and Multiuser Transaction Processing . . . . . . . . . . . .
1.4 Actors on the Scene . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.4.1 Database Administrators . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.4.2 Database Designers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.4.3 End Users . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.4.4 System Analysts and Application Programmers (Software Engineers) . . . .
1.5 Workers behind the Scene . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.6 Advantages of Using the DBMS Approach . . . . . . . . . . . . . . . . . . . . . . .
1.6.1 Controlling Redundancy . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.6.2 Restricting Unauthorized Access . . . . . . . . . . . . . . . . . . . . . . . . .
1.6.3 Providing Persistent Storage for Program Objects . . . . . . . . . . . . . . .
1.6.4 Providing Storage Structures and Search Techniques for Efficient Query Processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.6.5 Providing Backup and Recovery . . . . . . . . . . . . . . . . . . . . . . . . .
1.6.6 Providing Multiple User Interfaces . . . . . . . . . . . . . . . . . . . . . . .
1.6.7 Representing Complex Relationships among Data . . . . . . . . . . . . . . .
1.6.8 Enforcing Integrity Constraints . . . . . . . . . . . . . . . . . . . . . . . . .
1.6.9 Permitting Inferencing and Actions Using Rules . . . . . . . . . . . . . . . .
1.6.10 Additional Implications of Using the Database Approach . . . . . . . . . . .
1.8 When Not to Use a DBMS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
10
10
11
11
11
11
11
12
12
12
12
12
12
13
13
13
13
2 Overview of Database Languages and Architectures
2.1 Data Models, Schemas, and Instances . . . . . . . . .
2.1.1 Categories of Data Models . . . . . . . . . . .
2.1.2 Schemas, Instances and Database State . . . .
2.2 Three-Schema Architecture and Data Independence .
2.2.1 The Three-Schema Architecture . . . . . . . .
2.2.2 Data Independence . . . . . . . . . . . . . . .
2.3 Database Languages and Interfaces . . . . . . . . . .
2.3.1 DBMS Languages . . . . . . . . . . . . . . . .
2.3.2 DBMS Interfaces . . . . . . . . . . . . . . . .
2.4 The Database System Environment . . . . . . . . . .
2.4.1 DBMS Component Modules . . . . . . . . . .
15
15
15
16
16
16
16
17
17
17
18
18
1
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
13
13
14
14
14
14
14
14
2.4.2 Database System Utilities . . . . . . . . . . . . . . . . . . . . . .
2.4.3 Tools, Application Environments, and Communications Facilities .
Centralized & Client/Server Architectures for DBMSs . . . . . . . . . . .
2.5.1 Centralized DBMSs Architecture . . . . . . . . . . . . . . . . . .
2.5.2 Basic Client/Server Architectures . . . . . . . . . . . . . . . . . .
2.5.3 Two-Tier Client/Server Architectures for DBMSs . . . . . . . . .
2.5.4 Three-Tier and n-Tier Architectures for Web Applications . . . .
Classification of Database Management Systems . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
18
18
18
18
19
19
19
19
3 The Basic (Flat) Relational Model
3.1 Relational Model Concepts . . . . . . . . . . . . . . . . . . . . . . . . . .
3.1.1 Domains, Attributes, Tuples, and Relations . . . . . . . . . . . .
3.1.2 Characteristics of Relations . . . . . . . . . . . . . . . . . . . . .
3.1.3 Relational Model Notation . . . . . . . . . . . . . . . . . . . . . .
3.2 Relational Model Constraints and Relational Database Schemas . . . . .
3.2.1 Domain Constraints . . . . . . . . . . . . . . . . . . . . . . . . .
3.2.2 Key Constraints and Constraints on NULL values . . . . . . . . . .
3.2.3 Relational Databases and Relational Database Schemas . . . . . .
3.2.4 Integrity, Referential Integrity and Foreign Keys . . . . . . . . . .
3.2.5 Other Types of Constraints . . . . . . . . . . . . . . . . . . . . .
3.3 Update Operations, Transactions and Dealing with Constraint Violations
3.3.1 The Insert Operation . . . . . . . . . . . . . . . . . . . . . . . . .
3.3.2 The Delete Operation . . . . . . . . . . . . . . . . . . . . . . . .
3.3.3 The Update Operation . . . . . . . . . . . . . . . . . . . . . . . .
3.3.4 The Transaction Concept . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
20
20
20
20
21
21
21
21
22
22
22
23
23
23
23
23
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
24
24
24
24
25
25
25
26
26
26
27
27
27
27
27
28
28
28
29
29
29
29
29
2.5
2.6
4 SQL: Data Definition, Constraints, and Basic Queries and Updates
4.1 SQL Data Definition and Data Types . . . . . . . . . . . . . . . . . . . . . . .
4.1.1 Schema and Catalog Concepts in SQL . . . . . . . . . . . . . . . . . .
4.1.2 The CREATE TABLE Command in SQL . . . . . . . . . . . . . . . .
4.1.3 Attribute Data Types and Domains in SQL . . . . . . . . . . . . . . .
4.2 Specifying Constraints in SQL . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2.1 Specifying Attribute Constraints and Attribute Defaults . . . . . . . .
4.2.2 Specifying Key and Referential Integrity Constraints . . . . . . . . . .
4.2.3 Giving Names to Constraints . . . . . . . . . . . . . . . . . . . . . . .
4.2.4 Specifying Constraints on Tuples Using CHECK . . . . . . . . . . . . .
4.3 Basis Retrieval Queries in SQL . . . . . . . . . . . . . . . . . . . . . . . . . .
4.3.1 The SELECT-FROM-WHERE Structure of Basic SQL Queries . . . .
4.3.2 Ambiguous Attribute Names, Aliasing, Renaming, and Tuple Variables
4.3.3 Unspecified WHERE Clause and Use of the Asterisk . . . . . . . . . .
4.3.4 Tables as Sets in SQL . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.3.5 Substring Pattern Matching and Arithmetic Operators . . . . . . . . .
4.3.6 Ordering of Query Results . . . . . . . . . . . . . . . . . . . . . . . . .
4.3.7 Discussion and Summary of Basic SQL Retrieval Queries . . . . . . . .
4.4 INSERT, DELETE, and UPDATE Statements in SQL . . . . . . . . . . . . .
4.4.1 The INSERT Command . . . . . . . . . . . . . . . . . . . . . . . . . .
4.4.2 The DELETE Command . . . . . . . . . . . . . . . . . . . . . . . . . .
4.4.3 The UPDATE Command . . . . . . . . . . . . . . . . . . . . . . . . . .
4.5 Additional Features of SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5 SQL: Advanced Queries, Assertions, Triggers, and Views
5.1 More Complex SQL Retrieval Queries . . . . . . . . . . . . . .
5.1.1 Comparisons Involving NULL and Three-Valued Logic
5.1.2 Nested Queries, Tuples, and Set/Multiset Comparisons
5.1.3 Correlated Nested Queries . . . . . . . . . . . . . . . .
5.1.4 The EXISTS and UNIQUE Functions in SQL . . . . .
5.1.5 Explicit Sets and Renaming of Attributes in SQL . . .
5.1.6 Joined Tables in SQL and Outer Joins . . . . . . . . .
5.1.7 Aggregate Functions in SQL . . . . . . . . . . . . . . .
5.1.8 Grouping: The GROUP BY and HAVING Clauses . .
5.2 Specifying Constraints as Assertions and Actions as Triggers .
5.2.1 Specifying General Constraints as Assertions in SQL .
5.2.2 Introduction to Triggers in SQL . . . . . . . . . . . . .
5.3 Views (Virtual Tables) in SQL . . . . . . . . . . . . . . . . . .
5.3.1 Concept of a View in SQL . . . . . . . . . . . . . . . .
5.3.2 Specification of Views in SQL . . . . . . . . . . . . . .
5.3.3 View Implementation, View Update, and Inline Views .
5.4 Schema Change Statements in SQL . . . . . . . . . . . . . . .
5.4.1 The DROP Command . . . . . . . . . . . . . . . . . .
5.4.2 The ALTER Command . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
30
30
30
30
31
31
32
32
33
33
34
34
34
34
34
34
35
35
35
35
6 Formal Relational Languages: The Algebra and Calculus
6.1 Unary Relational Operations: SELECT & PROJECT . . . . . . . . . .
6.1.1 The SELECT Operation . . . . . . . . . . . . . . . . . . . . . .
6.1.2 The PROJECT Operation . . . . . . . . . . . . . . . . . . . . .
6.1.3 Sequences of Operations and the RENAME Operation . . . . .
6.2 Relational Algebra Operations from Set Theory . . . . . . . . . . . . .
6.2.1 The UNION, INTERSECTION, and MINUS Operations . . . .
6.2.2 The CARTESIAN PRODUCT (CROSS PRODUCT) Operation
6.3 Binary Relational Operations: JOIN and DIVISION . . . . . . . . . . .
6.3.1 The JOIN Operation . . . . . . . . . . . . . . . . . . . . . . . .
6.3.2 Variations of JOIN: The EQUIJOIN and NATURAL JOIN . . .
6.3.3 A Complete Set of Relational Algebra Operations . . . . . . . .
6.3.4 The DIVISION Operation . . . . . . . . . . . . . . . . . . . . .
6.3.5 Notation for Query Trees . . . . . . . . . . . . . . . . . . . . . .
6.4 Additional Relational Operations . . . . . . . . . . . . . . . . . . . . .
6.4.1 Generalized Projection . . . . . . . . . . . . . . . . . . . . . . .
6.4.2 Aggregate Functions and Grouping . . . . . . . . . . . . . . . .
6.4.3 Recursive Closure Operations . . . . . . . . . . . . . . . . . . .
6.4.4 OUTER JOIN Operations . . . . . . . . . . . . . . . . . . . . .
6.4.5 The OUTER UNION Operation . . . . . . . . . . . . . . . . . .
6.6 The Tuple Relational Calculus . . . . . . . . . . . . . . . . . . . . . . .
6.6.1 Tuple Variables and Range Relations . . . . . . . . . . . . . . .
6.6.2 Expressions and Formulas in Tuple Relational Calculus . . . . .
6.6.3 The Existential and Universal Quantifiers . . . . . . . . . . . .
6.6.4 Sample Queries in Tuple Relational Calculus . . . . . . . . . . .
6.6.5 Notation for Query Graphs . . . . . . . . . . . . . . . . . . . .
6.6.6 Transforming the Universal and Existential Quantifiers . . . . .
6.6.7 Using the Universal Quantifiers in Queries . . . . . . . . . . . .
6.6.8 Safe Expressions . . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
36
36
36
37
37
38
38
39
39
39
40
41
41
42
42
42
43
44
44
44
45
45
46
46
46
46
47
47
47
3
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
6.7
The Domain Relational Calculus
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
48
7 Conceptual Data Modeling Using Entities and Relationships
7.1 Using High-Level Conceptual Data Models for Database Design . . . . . . . . . . .
7.3 Entity Types, Entity Sets, Attributes, and Keys . . . . . . . . . . . . . . . . . . . .
7.3.1 Entities and Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.3.2 Entity Types, Entity Sets, Keys, and Value Sets . . . . . . . . . . . . . . . .
7.4 Relationship Types, Relationship Sets, Roles & Structural Constraints . . . . . . . .
7.4.1 Relationship Types, Sets and Instances . . . . . . . . . . . . . . . . . . . . .
7.4.2 Relationship Degree, Role Names, and Recursive Relationships . . . . . . . .
7.4.3 Constraints on Binary Relationship Types . . . . . . . . . . . . . . . . . . .
7.4.4 Attributes of Relationship Types . . . . . . . . . . . . . . . . . . . . . . . .
7.5 Weak Entity Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.7 ER Diagrams, Naming Conventions, and Design Issues . . . . . . . . . . . . . . . .
7.7.1 Summary of Notation for ER Diagrams . . . . . . . . . . . . . . . . . . . . .
7.7.2 Proper Naming of Schema Constructs . . . . . . . . . . . . . . . . . . . . . .
7.7.3 Design Choices for ER Conceptual Design . . . . . . . . . . . . . . . . . . .
7.7.4 Alternative Notations for ER Diagrams . . . . . . . . . . . . . . . . . . . . .
7.8 Relationship Types of Degree Higher than Two . . . . . . . . . . . . . . . . . . . .
7.8.1 Choosing between Binary and Ternary (or Higher-Degree) Relationships . .
7.8.2 Constraints on Ternary (or Higher-Degree) Relationships . . . . . . . . . . .
7.9 Subclasses, Superclasses, and Inheritance . . . . . . . . . . . . . . . . . . . . . . . .
7.10 Specialization and Generalization in EER . . . . . . . . . . . . . . . . . . . . . . . .
7.10.1 Specialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.10.2 Generalization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.11 Constraints and Characteristics of Specialization and Generalization Hierarchies . .
7.11.1 Constraints on Specialization and Generalization . . . . . . . . . . . . . . .
7.11.2 Specialization and Generalization Hierarchies and Lattices . . . . . . . . . .
7.11.3 Utilizing Specialization and Generalization in Refining Conceptual Schemas .
7.12 Modeling of UNION Types Using Categories in EER . . . . . . . . . . . . . . . . .
7.13 A Sample UNIVERSITY EER Schema, Design Choices, and Formal Definitions . .
7.13.1 The UNIVERSITY Database Example . . . . . . . . . . . . . . . . . . . . .
7.13.2 Design Choices for Specialization/Generalization . . . . . . . . . . . . . . . .
7.14 Data Abstraction, Knowledge Representation, & Ontology Concepts . . . . . . . . .
7.14.1 Classification and Instantiation . . . . . . . . . . . . . . . . . . . . . . . . .
7.14.2 Identification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.14.3 Specialization and Generalization . . . . . . . . . . . . . . . . . . . . . . . .
7.14.4 Aggregation and Association . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.14.5 Ontologies and the Semantic Web . . . . . . . . . . . . . . . . . . . . . . . .
49
49
49
49
50
50
50
50
50
51
51
51
51
51
51
51
52
52
52
52
52
52
52
53
53
53
53
54
54
54
54
55
55
55
55
55
55
8 Mapping a Conceptual Design into a Logical Design
8.1 Relational Database Design using ER-to-Relational Mapping . . . . . .
8.1.1 ER-to-Relational Mapping Algorithm . . . . . . . . . . . . . . .
8.1.2 Discussion and Summary of Mapping for ER Model Constructs
8.2 Mapping EER Model Constructs to Relations . . . . . . . . . . . . . .
8.2.1 Mapping of Specialization or Generalization . . . . . . . . . . .
8.2.2 Mapping of Shared Subclasses (Multiple Inheritance) . . . . . .
8.2.3 Mapping of Categories (Union Types) . . . . . . . . . . . . . . .
56
56
56
58
58
58
59
59
4
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
12 SQL Application Programming Using C and Java
12.1 Database Programming: Techniques and Issues . . . . . . . . . .
12.1.1 Approaches to Database Programming . . . . . . . . . . .
12.1.2 Impedance Mismatch . . . . . . . . . . . . . . . . . . . . .
12.1.3 Typical Sequence of Interaction in Database Programming
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
60
60
60
60
61
13 SQL Web Programming Using C PHP
13.1 A Simple PHP Example . . . . . . . . . . . . . . . . . . . . . . .
13.2 Overview of Basic Features of PHP . . . . . . . . . . . . . . . . .
13.2.1 PHP Variables, Data Types, and Programming Constructs
13.2.2 PHP Arrays . . . . . . . . . . . . . . . . . . . . . . . . . .
13.2.3 PHP Functions . . . . . . . . . . . . . . . . . . . . . . . .
13.2.4 PHP Server Variables and Forms . . . . . . . . . . . . . .
13.3 Overview of PHP Database Programming . . . . . . . . . . . . .
13.3.1 Connecting to a Database . . . . . . . . . . . . . . . . . .
13.3.2 Collecting Data from Forms and Inserting Records . . . .
13.3.3 Retrieval Queries from Database Tables . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
62
62
62
62
63
63
63
64
64
64
64
14 Database Design Theory: Introduction to Normalization Using
Multivalued Dependencies
14.1 Informal Design Guidelines for Relation Schemas . . . . . . . . . .
14.1.1 Imparting Clear Semantics to Attributes in Relations . . . .
14.1.2 Redundant Information in Tuples and Update Anomalies . .
14.1.3 NULL values in Tuples . . . . . . . . . . . . . . . . . . . . . .
14.1.4 Generation of Spurious Tuples . . . . . . . . . . . . . . . . .
14.1.5 Summary and Discussion of Design Guidelines . . . . . . . .
14.2 Functional Dependencies . . . . . . . . . . . . . . . . . . . . . . . .
14.2.1 Definition of Functional Dependency . . . . . . . . . . . . .
14.3 Normal Forms Based on Primary Keys . . . . . . . . . . . . . . . .
14.3.1 Normalization of Relations . . . . . . . . . . . . . . . . . . .
14.3.2 Practical Use of Normal Forms . . . . . . . . . . . . . . . .
14.3.3 Definitions of Keys and Attributes Participating in Keys . .
14.3.4 First Normal Form . . . . . . . . . . . . . . . . . . . . . . .
14.3.5 Second Normal Form . . . . . . . . . . . . . . . . . . . . . .
14.3.6 Third Normal Form . . . . . . . . . . . . . . . . . . . . . . .
14.4 General Definitions of Second & Third Normal Forms . . . . . . . .
14.5 Boyce-Codd Normal Form . . . . . . . . . . . . . . . . . . . . . . .
Functional and
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
15 Database Design Theory: Normalization Algorithms
15.1 Further Topics in Functional Dependencies: Inference Rules, Equivalence, and Minimal Cover . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15.1.1 Inference Rules for Functional Dependencies . . . . . . . . . . . . . . . . . .
15.1.2 Equivalence of Sets of Functional Dependencies . . . . . . . . . . . . . . . .
15.1.3 Minimal Sets of Functional Dependencies . . . . . . . . . . . . . . . . . . . .
15.2 Properties of Relational Decompositions . . . . . . . . . . . . . . . . . . . . . . . .
15.2.1 Dependency Preservation Property of a Decomposition . . . . . . . . . . . .
15.2.2 Nonadditive (Lossless) Join Property of a Decomposition . . . . . . . . . . .
15.2.3 Testing Binary Decompositions for the Nonadditive Join Property . . . . . .
15.2.4 Successive Nonadditive Join Decompositions . . . . . . . . . . . . . . . . . .
15.3 Algorithms for Relational Database Schema Design . . . . . . . . . . . . . . . . . .
5
65
65
65
65
66
66
66
66
66
68
68
68
69
69
69
70
71
71
72
72
72
73
73
73
74
74
74
74
74
15.3.1 Dependency-Preserving Decomposition into 3NF Schemas . . . . . . . . . .
15.3.2 Nonadditive Join Decomposition into BCNF Schemas . . . . . . . . . . . . .
15.3.3 Dependency-Preserving and Nonadditive (Lossless) Join Decomposition into
3NF Schemas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15.4 About Nulls, Dangling Tuples, and Alternative Relational Designs . . . . . . . . . .
15.4.1 Problems with NULL Values and Dangling Tuples . . . . . . . . . . . . . . .
15.4.2 Discussion of Normalization Algorithms and Alternative Relational Designs .
74
75
75
75
75
75
16 Database File Organizations: Unordered, Ordered, and Hashed
16.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16.1.1 Memory Hierarchies and Storage Devices . . . . . . . . . .
16.1.2 Storage of Databases . . . . . . . . . . . . . . . . . . . . .
16.2 Secondary Storage Devices . . . . . . . . . . . . . . . . . . . . . .
16.3 Buffering of Blocks . . . . . . . . . . . . . . . . . . . . . . . . . .
16.4 Placing File Records on Disk . . . . . . . . . . . . . . . . . . . . .
16.4.1 Records and Record Types . . . . . . . . . . . . . . . . . .
16.4.2 Files, Fixed-length Records, and Variable-Length Records
16.4.3 Record Blocking and Spanned versus Unspanned Records .
16.4.4 Allocating File Blocks on Disk . . . . . . . . . . . . . . . .
16.4.5 File Headers . . . . . . . . . . . . . . . . . . . . . . . . . .
16.5 Operations on Files . . . . . . . . . . . . . . . . . . . . . . . . . .
16.6 Files of Unordered Records (Heap Files) . . . . . . . . . . . . . .
16.7 Files of Ordered Records (Sorted Files) . . . . . . . . . . . . . . .
16.8 Hashing Techniques . . . . . . . . . . . . . . . . . . . . . . . . . .
16.8.1 Internal Hashing . . . . . . . . . . . . . . . . . . . . . . .
16.8.2 External Hashing for Disk Files . . . . . . . . . . . . . . .
16.8.3 Hashing Techniques That Allow Dynamic File Expansion .
16.9 Other Primary File Organizations . . . . . . . . . . . . . . . . . .
16.9.1 Files of Mixed Records . . . . . . . . . . . . . . . . . . . .
16.10Parallelizing Disk Access Using RAID Technology . . . . . . . . .
16.11New Storage Systems . . . . . . . . . . . . . . . . . . . . . . . . .
16.11.1 Storage Area Networks . . . . . . . . . . . . . . . . . . . .
16.11.2 Network-Attached Storage . . . . . . . . . . . . . . . . . .
16.11.3 iSCSI Storage Systems . . . . . . . . . . . . . . . . . . . .
Files of
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
Records
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
76
76
76
76
77
77
77
77
77
78
78
78
79
80
80
80
80
81
81
82
82
82
82
82
82
82
17 Database File Indexing Techniques, B-Trees, and B+-Trees
17.1 Types of Single-Level Ordered Indexes . . . . . . . . . . . . .
17.1.1 Primary Indexes . . . . . . . . . . . . . . . . . . . . .
17.1.2 Clustering Indexes . . . . . . . . . . . . . . . . . . . .
17.1.3 Secondary Indexes . . . . . . . . . . . . . . . . . . . .
17.2 Multilevel Indexes . . . . . . . . . . . . . . . . . . . . . . . . .
17.3 Dynamic Multilevel Indexes Using B-trees & B+-Trees . . . .
17.3.1 Search Trees and B-trees . . . . . . . . . . . . . . . . .
17.3.2 B+-trees . . . . . . . . . . . . . . . . . . . . . . . . . .
17.4 Indexes on Multiple Keys . . . . . . . . . . . . . . . . . . . . .
17.4.1 Ordered Index on Multiple Attributes . . . . . . . . . .
17.4.2 Partitioned Hashing . . . . . . . . . . . . . . . . . . .
17.4.3 Grid Files . . . . . . . . . . . . . . . . . . . . . . . . .
17.5 Other Types of Indexes . . . . . . . . . . . . . . . . . . . . . .
17.5.1 Hash Indexes . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
83
83
83
84
84
84
85
85
86
87
87
87
87
87
87
6
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
17.5.2 Bitmap Indexes . . . . . . . . . . .
17.5.3 Function-Based Indexing . . . . . .
17.6 Some General Issues Concerning Indexing
17.6.1 Logical versus Physical Indexes . .
17.6.2 Discussion . . . . . . . . . . . . . .
17.6.3 Column-Based Storage of Relations
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
18 Introduction to Query Processing and Query Optimization Techniques
18.1 Translating SQL Queries into Relational Algebra . . . . . . . . . . . . . . .
18.2 Algorithms for External Sorting . . . . . . . . . . . . . . . . . . . . . . . . .
18.3 Algorithms for SELECT and JOIN Operations . . . . . . . . . . . . . . . . .
18.3.1 Implementing the SELECT Operation . . . . . . . . . . . . . . . . .
18.3.2 Implementing the JOIN Operation . . . . . . . . . . . . . . . . . . .
18.4 Algorithms for PROJECT and Set Operations . . . . . . . . . . . . . . . . .
18.5 Implementing Aggregate Operations and OUTER JOINs . . . . . . . . . . .
18.5.1 Implementing Aggregate Operations . . . . . . . . . . . . . . . . . .
18.5.2 Implementing OUTER JOINs . . . . . . . . . . . . . . . . . . . . . .
18.6 Combining Operations Using Pipelining . . . . . . . . . . . . . . . . . . . . .
18.7 Using Heuristics in Query Optimization . . . . . . . . . . . . . . . . . . . . .
18.7.1 Notation for Query Trees and Query Graphs . . . . . . . . . . . . . .
18.7.2 Heuristic Optimization of Query Trees . . . . . . . . . . . . . . . . .
18.7.3 Converting Query Trees into Query Execution Plans . . . . . . . . .
18.8 Using Selectivity and Cost Estimates in Query Optimization . . . . . . . . .
18.8.1 Cost components for Query Execution . . . . . . . . . . . . . . . . .
18.8.2 Catalog Information Used in Cost Functions . . . . . . . . . . . . . .
18.8.3 Examples of Cost Functions for SELECT . . . . . . . . . . . . . . . .
18.8.4 Examples of Cost Functions for JOIN . . . . . . . . . . . . . . . . . .
18.8.5 Multiple Relation Queries and JOIN Ordening . . . . . . . . . . . . .
18.8.6 Example to Illustrate Cost-Based Query Optimization . . . . . . . .
18.9 Overview of Query Optimization in Oracle . . . . . . . . . . . . . . . . . . .
18.10Semantic Query Optimization . . . . . . . . . . . . . . . . . . . . . . . . . .
20 Foundations of Database Transaction Processing
20.1 Introduction to Transaction Processing . . . . . . . . . . . . . . .
20.1.1 Single-User versus Multiuser Systems . . . . . . . . . . . .
20.1.2 Transactions, Database Items, Read and Write Operations,
20.1.3 Why Concurrency Control Is Needed . . . . . . . . . . . .
20.1.4 Why Recovery Is Needed . . . . . . . . . . . . . . . . . . .
20.2 Transaction and System concepts . . . . . . . . . . . . . . . . . .
20.2.1 Transaction States and Additional Operations . . . . . . .
20.2.2 The System Log . . . . . . . . . . . . . . . . . . . . . . . .
20.2.3 Commit Point of a Transaction . . . . . . . . . . . . . . .
20.3 Desirable Properties of Transactions . . . . . . . . . . . . . . . . .
20.4 Characterizing Schedules Based on Recoverability . . . . . . . . .
20.4.1 Schedules (Histories) of Transactions . . . . . . . . . . . .
20.4.2 Characterizing Schedules Based on Recoverability . . . . .
20.5 Characterizing Schedules Based on Serializability . . . . . . . . .
20.5.1 Serial, Nonserial, and Conflict-Serializable Schedules . . . .
20.5.2 Testing for Conflict Serializability of a Schedule . . . . . .
20.5.3 How Serializability Is Used for Concurrency Control . . . .
7
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
88
88
88
88
88
88
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
89
89
89
90
90
91
92
93
93
93
93
93
94
94
95
96
96
96
96
97
97
98
98
98
99
. . . . . . . . . . 99
. . . . . . . . . . 99
and DBMS Buffers 99
. . . . . . . . . . 100
. . . . . . . . . . 100
. . . . . . . . . . 101
. . . . . . . . . . 101
. . . . . . . . . . 101
. . . . . . . . . . 101
. . . . . . . . . . 102
. . . . . . . . . . 102
. . . . . . . . . . 102
. . . . . . . . . . 102
. . . . . . . . . . 103
. . . . . . . . . . 103
. . . . . . . . . . 103
. . . . . . . . . . 103
20.5.4 View Equivalence and View Serializability . . . . . . . . . . . . . . . . . . . 104
20.5.5 Other Types of Equivalence of Schedules . . . . . . . . . . . . . . . . . . . . 104
20.6 Transaction Support in SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
21 Introduction to Protocols for Concurrency Control in Databases
21.1 Two-Phase Locking Techniques for Concurrency Control . . . . . . .
21.1.1 Types of Locks and System Lock Tables . . . . . . . . . . . .
21.1.2 Guaranteeing Serializability by Two-Phase Locking . . . . . .
21.1.3 Dealing with Deadlock and Starvation . . . . . . . . . . . . .
21.2 Concurrency Control Based on Timestamp Ordering . . . . . . . . . .
21.2.1 Timestamps . . . . . . . . . . . . . . . . . . . . . . . . . . . .
21.2.2 The Timestamp Ordering Algorithm . . . . . . . . . . . . . .
21.3 Multiversion Concurrency Control Techniques . . . . . . . . . . . . .
21.3.1 Multiversion Technique Based on Timestamp Ordering . . . .
21.3.2 Multiversion Two-Phase Locking Using Certify Locks . . . . .
21.4 Validation (Optimistic) Concurrency Control Techniques . . . . . . .
21.5 Granularity of Data Items and Multiple Granularity Locking . . . . .
21.5.1 Granularity Level Considerations for Locking . . . . . . . . . .
21.5.2 Multiple Granularity Level Locking . . . . . . . . . . . . . . .
21.6 Using Locks for Concurrency Control in Indexes . . . . . . . . . . . .
21.7 Other Concurrency Control Issues . . . . . . . . . . . . . . . . . . . .
21.7.1 Insertion, Deletion, and Phantom Records . . . . . . . . . . .
21.7.2 Interactive Transactions . . . . . . . . . . . . . . . . . . . . .
21.7.3 Latches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
105
105
105
107
108
110
110
110
112
112
112
113
114
114
115
115
116
116
117
117
22 Introduction to Database Recovery Protocols
22.1 Recovery Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . .
22.1.1 Recovery Outline and Categorization of Recovery Algorithms .
22.1.2 Caching (Buffering) of Disk Blocks . . . . . . . . . . . . . . .
22.1.3 Write-Ahead Logging, Steal/No-Steal, and Force/No-Foce . .
22.1.4 Checkpoints in the System Log and Fuzzy Checkpoints . . . .
22.1.5 Transaction Rollback and Cascading Roll back . . . . . . . . .
22.1.6 Transactions Actions That Do Not Affect the Database . . . .
22.2 NO-UNDO/REDO Recovery Base on Deffered Update . . . . . . . .
22.3 Recovery Rechniques Based on Immediate Update . . . . . . . . . . .
22.4 Shadow Paging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
22.4.1 Before Transaction . . . . . . . . . . . . . . . . . . . . . . . .
22.4.2 During Transaction . . . . . . . . . . . . . . . . . . . . . . . .
22.4.3 Recovery Process . . . . . . . . . . . . . . . . . . . . . . . . .
22.4.4 Disadvantages . . . . . . . . . . . . . . . . . . . . . . . . . . .
22.5 The Aries Recovery Algorithm . . . . . . . . . . . . . . . . . . . . . .
22.5.1 Analysis Phase . . . . . . . . . . . . . . . . . . . . . . . . . .
22.5.2 REDO Phase . . . . . . . . . . . . . . . . . . . . . . . . . . .
22.5.3 UNDO Phase . . . . . . . . . . . . . . . . . . . . . . . . . . .
22.5.4 Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
22.5.5 Log Sequence Number (LSN) . . . . . . . . . . . . . . . . . .
22.5.6 Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
22.5.7 Checkpoints . . . . . . . . . . . . . . . . . . . . . . . . . . . .
22.5.8 Recovery from crash . . . . . . . . . . . . . . . . . . . . . . .
22.6 Recovery in Multidatabse Systems . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
118
118
118
119
120
122
122
123
123
124
125
125
126
126
126
126
127
127
127
127
127
128
128
128
128
8
22.7 Database Backup and Recovery from Catastrophic Failures . . . . . . . . . . . . . . 129
22.7.1 Handling more Catastrophic Failures . . . . . . . . . . . . . . . . . . . . . . 129
22.7.2 Increase frequency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
9
Hoofdstuk 1
Introduction to Databases
1.1
Introduction
Een database heeft volgende eigenschappen:
• Het is een representatie van een aspect in de echte wereld, een miniwereld, ook wel universe
of discourse (UoD) genaamd.
• Een database is een verzameling van gerelateerde informatie/data.
• Een database wordt ontworpen, gebouwd en ingevuld voor een specifiek doel.
• Aanpassingen moeten zo snel mogelijk weergegeven worden in de database.
Een database management system (DBMS) is een set van programma’s die de gebruiker toelaat
een database te cre¨eren en te onderhouden.
1.2
An Example
Het manipuleren van een database omvat querying en updating. Een query moet gespecifieerd zijn
in een bepaalde query-taal, behorende tot het DBMS, alvorens hij kan worden uitgevoerd.
1. Het ontwikkelen van een applicatie voor een bestaande database, of het ontwikkelen van een
compleet nieuwe database start met een fase genaamd requirements specification and
analysis. De eisen/voorwaarden van de database worden hier in detail vastgelegd.
2. De eisen/voorwaarden worden omgevormd tot een conceptual design dat weergegeven en
bewerkt kan worden op een computer.
3. Het conceptual design wordt omgezet naar een logical design, dat ge¨ımplementeerd kan
worden in een commercieel DBMS.
4. Het logical design wordt omgezet in een physical design, waar men de verdere specificaties
voor opslag en toegang tot de database zal vastleggen. Hierna kan men beginnen de database
te bevolken.
10
1.3
Characteristics of the Database Approach
Een database bestaat uit een enkele opslagplaats waar gegevens worden bijgehouden die ´e´en keer
gedefinieerd worden en nadien toegankelijk zijn voor alle gebruikers.
1.3.1
Self-Describing Nature of a Database System
Een basiskenmerk van een databasesysteem is dat het systeem niet enkel de database zelf bevat
maar ook een complete definitie of beschrijving van de databasestructuur en zijn beperkingen.
Deze definitie wordt bijgehouden in de DBMS catalogus. De informatie in deze catalogus is de
zogenaamde meta-data, en beschrijft de structuur van de primaire database.
1.3.2
Insulation between Programs and Data, and Data Abstraction
In traditionele bestandsverwerking is de structuur van de data files ingebouwd in het programma
dat gebruik maakt van het bestand. Als de structuur van een bestand gewijzigd wordt, zullen dus
ook alle programma’s die gebruik maken van het bestand, aangepast moeten worden. Een DBMS
daarentegen bewaart de structuur van de bestanden in de catalogus, apart van de programma’s die
het gebruiken. We noemen dit program-data independence.
Een operation (functie of methode) bestaat uit 2 delen. De interface (signature) van een operatie
bevat de naam van de operatie en de data types van zijn argumenten (parameters). De implementatie
van de operatie is apart gedefinieerd en kan aangepast worden zonder dat de interface gewijzigd moet
worden. Gebruikersprogramma’s kunnen met de data werken door middel van operatienamen en
-parameters, onafhankelijk van hoe de operaties ge¨ımplementeerd zijn. We noemen dit programoperation independence.
De karakteristiek die program-data independence en program-operation independence toelaat,
wordt de data abstraction genoemd. Een data model is een soort van data abstraction die voor
een conceptual representation van de data zorgt.
1.3.3
Support of Multiple Views of the Data
Een database heeft vaak meerdere gebruikers die eventueel een ander zicht (view ) willen op de
database. Een view kan een subset van de database zijn maar het kan ook zelf virtuele data
bevatten die afgeleid is van de data in de database maar er niet opgeslagen is.
1.3.4
Sharing of Data and Multiuser Transaction Processing
Een multiuser DBMS moet toelaten dat meerdere gebruikers tegelijkertijd toegang hebben tot
de database. Hiervoor moet de DBMS over concurrency control software beschikken om te
verzekeren dat het updaten van data door meerdere gebruikers correct verloopt zodat ook het
resultaat hiervan correct is.
Een transactie is een uitvoerend programma of proces dat ´e´en of meerdere database accesses
omvat. De isolation-eigenschap verzekert dat elke transactie uitgevoerd wordt, afgezonderd van
andere transacties. De atomicity-eigenschap verzekert dat alle transacties ofwel volledig uitgevoerd
worden, ofwel niet uitgevoerd worden.
11
1.4
Actors on the Scene
Actors on the scene zijn de personen die dagelijks een grote database gebruiken.
1.4.1
Database Administrators
Er is nood aan een chief administrator, we noemen deze de database administrator (DBA). Hij
is verantwoordelijk voor autorisatie, co¨ordinatie, monitoring en de software en hardware resources.
Hij is ook de persoon die verantwoordelijk gesteld kan worden voor problemen zoals veiligheidslekken en een slechte responstijd van het systeem.
1.4.2
Database Designers
Database designers zijn de personen die verantwoordelijk zijn voor het identificeren van de data
die opgeslagen moet worden op de database en voor het kiezen van de juiste datastructuren om
deze op te slagen data voor te stellen in de database.
1.4.3
End Users
Eindgebruikers zijn de personen wiens job eruit bestaat een database te bevragen, up te daten
en rapporten te maken. We kunnen ze onderverdelen in verschillende categorie¨en:
• Casual end users hebben de database occasioneel nodig en hebben mogelijk elke keer andere
gegevens nodig.
• Naive of parametric end users bevragen en updaten de database constant.
• Sophisticated end users (zoals ingenieurs of wetenschappers) kennen de eigenschappen en mogelijkheden van de database zeer goed zodat ze hun eigen applicaties kunnen implementeren.
• Standalone users hebben meestal een persoonlijke database.
1.4.4
System Analysts and Application Programmers (Software Engineers)
System analysts bepalen de eisen van de eindgebruiker en ontwerpen de specificaties voor alleenstaande transacties die voldoen aan deze eisen. Application programmers implementeren deze
specificaties als programma’s die ze testen, debuggen en documenteren.
1.5
Workers behind the Scene
Dit stuk gaat over de mensen die de DBMS software en system environment ontwerpen, ontwikkelen
en de operaties ervan uitschrijven. Ze zijn meestal niet ge¨ınteresseerd in de inhoud van de database.
• DBMS system designers en implementers ontwerpen en implementeren de DBMS modules en
interfaces als een softwarepakket.
• Tool developers ontwerpen en implementeren tools. Tools zijn optionele pakketten die vaak
apart aangekocht kunnen worden.
• Operators en maintenance personnel is het system administration personnel. Ze zijn verantwoordelijk voor het runnen en het onderhoud van de hardware en software environment.
12
1.6
1.6.1
Advantages of Using the DBMS Approach
Controlling Redundancy
De redundantie is het meermaals opslaan van dezelfde data, dit leidt tot verschillende problemen.
• Een simpele update moet meerdere malen uitgevoerd worden, dit is duplication of effort.
• Opslagruimte wordt verspilt.
• Bestanden die dezelfde data voorstellen kunnen inconsistent worden omdat een update niet
wordt doorgevoerd op alle bestanden.
We moeten een database hebben die elk logical data item (bv. naam en geboortedatum) opslaat op
´e´en enkele plaats in de database, dit heet data normalization.
Soms is er echter nood aan gecontroleerde redundantie. Dit komt voor indien we alle data die
vaak samen opgevraagd wordt, in 1 bestand plaatsen. Hierdoor moet er bij een query slechts 1
bestand doorzocht worden i.p.v. meerdere. Dit heet denormalization.
1.6.2
Restricting Unauthorized Access
Als meerdere gebruikers een grote database delen, is het logisch dat niet iedereen toegang heeft tot
alle data. Een DBMS moet een security and authorization subsystem bevatten, waarmee de
DBA accounts kan aanmaken en restricties kan opleggen.
1.6.3
Providing Persistent Storage for Program Objects
Databases kunnen gebruikt worden om persistente opslag voor programma-objecten en datastructuren aan te bieden. Dit is ´e´en van de redenen voor object-oriented database systems. Een
complex object in C++ kan permanent opgeslagen worden in een object-geori¨enteerd DBMS. Zo
een object noemen we persistent, omdat het de be¨eindiging van het programma overleeft en later
direct kan teruggevonden worden.
1.6.4
Providing Storage Structures and Search Techniques for Efficient
Query Processing
Databasesystemen moeten de mogelijkheid hebben tot het effici¨ent uitvoeren van query’s en updates. Omdat een database vaak is opgeslagen op een disk, moet de DBMS speciale datastructuren en
technieken voorzien om de seektime te versnellen. Een oplossing hiervoor is werken met indexering.
Een DBMS biedt vaak buffering of caching modules aan, die bijgehouden worden in het hoofdgeheugen. De query processing and optimization module is verantwoordelijk voor het kiezen
van een effici¨ent query-uitvoeringsplan voor elke query, gebaseerd op de huidige opslagstructuur.
1.6.5
Providing Backup and Recovery
Een DBMS moet de mogelijkheid bezitten om te herstellen van hardware- of softwarefouten. Het
backup and recovery subsystem van de DBMS is verantwoordelijk voor het herstel. Het moet
kunnen herstellen, hervatten of een backup maken.
13
1.6.6
Providing Multiple User Interfaces
Dit omvat query-talen voor casual users, programming language interfaces voor application programmers, formulieren en commando’s voor parametric users en menu-gestuurde interfaces en natural
language interfaces voor standalone users. Vaak in combinatie met een GUI.
1.6.7
Representing Complex Relationships among Data
Een DBMS moet de mogelijkheid bieden om complexe relaties tussen data voor te stellen, evenals de
mogelijkheid om nieuwe relaties te defini¨eren en gerelateerde data snel en effici¨ent terug te vinden.
1.6.8
Enforcing Integrity Constraints
De meeste database applications hebben bepaalde integrity constraints die moeten gelden voor
de data. Een DBMS moet de mogelijkheid bieden om constraints te defini¨eren en ze te handhaven.
1.6.9
Permitting Inferencing and Actions Using Rules
Sommige databasesystemen hebben de mogelijkheid om informatie af te leiden uit reeds bestaande
data. Zulke systemen noemen we deductive database systems. In moderne databases bestaat
de mogelijkheid om triggers te associ¨eren met tabellen. Een trigger is een soort regel die toegepast
wordt bij een update op een tabel, wat resulteert in het uitvoeren van extra operaties zoals het
sturen van een boodschap. Nog sterker zijn active database systems, deze leveren actieve regels
die automatisch acties uitvoeren wanneer bepaalde gebeurtenissen of condities voorkomen.
1.6.10
Additional Implications of Using the Database Approach
• Potential for Enforcing Standards: de DBA wordt toegelaten om een bepaalde standaard te
defini¨eren voor de users.
• Reduced Application Development Time: eens een database is opgezet en runt, is er minder tijd
nodig om een nieuwe applicatie te ontwikkelen, gebruikmakend van de DBMS mogelijkheden.
• Flexibility: moderne DBMS’en laten verschillende soorten van evolutionaire veranderingen
toe in de structuur van de database zonder invloed op de opgeslagen data of applicaties.
• Availability of Up-to-Date information: vanaf het moment dat een gebruiker bepaalde data
heeft ge¨
updatet, moeten deze wijzigingen zichtbaar zijn voor andere gebruikers.
• Economies of Scale: systemen kunnen gedeeld worden om overlappingen te voorkomen op
verschillende niveaus.
1.8
When Not to Use a DBMS
Er zijn bepaalde situaties waarbij het gebruik van een DBMS een onnodige overhead kan veroorzaken, wat niet zou voorkomen bij het traditionele file processing. De overhead van een DBMS kan
volgende oorzaken hebben:
• Te hoge initi¨ele kosten voor hardware, software en training
• De algemeenheid van een DBMS
• Overhead voor het leveren van security, concurrency en recovery
14
Hoofdstuk 2
Overview of Database Languages and
Architectures
DBMS packages zijn gegroeid van ´e´en ge¨ıntegreerd systeem naar modulaire systemen. Deze bestaan
uit verschillende delen. Standaard wordt er gewerkt met twee modules: een client module die de
gebruikersinteractie moet verzorgen en een server module die zaken als dataopslag, toegang, en
het doorzoeken van de database op zich neemt.
2.1
Data Models, Schemas, and Instances
Een belangrijk kenmerk van databases is dat ze een soort van data abstraction voorzien. Hiermee bedoelt men dat zaken als de schijfopslag van de data worden genegeerd, terwijl enkel het
belangrijkste om de data te kunnen bestuderen en interpreteren wordt getoond.
Er worden ook meer en meer hoogniveau operaties ge¨ımplementeerd zodat manipulatie of interpretatie van de opgeslagen data zo eenvoudig mogelijk wordt. Dit wordt ook wel het dynamische
aspect van de database genoemd.
2.1.1
Categories of Data Models
Er zijn een drietal interessante, veel voorkomende datamodellen:
• Hoog-niveau of conceptuele datamodellen
Deze datamodellen gebruiken concepten als entiteiten, attributen en relaties:
– een entiteit stelt een object uit de echte wereld voor
– een attribuut stelt een eigenschap van zo een entiteit voor
– een relatie stelt een associatie voor tussen twee of meer entiteiten
• Representatieve of implementatie-datamodellen
Deze datamodellen worden in commerci¨ele databasesystemen het vaakst gebruikt. Ze maken
gebruik van relaties, maar ook van record structures.
• Laag-niveau of fysieke datamodellen
Deze datamodellen beschrijven hoe data in bestanden wordt opgeslagen in het geheugen door
informatie als het recordformaat, recordsortering en toegangspaden te beschrijven.
15
2.1.2
Schemas, Instances and Database State
Er moet bij elk datamodel een onderscheid gemaakt worden tussen de beschrijving van een database
en de database zelf.
De beschrijving van een database gebeurt in een database schema, ook wel een schema-diagram
genoemd. Dit schema wordt ontwikkeld v´o´or het maken van de database en wordt niet dikwijls
gewijzigd. Dit diagram geeft dus eigenlijk de structuur (de tabellen en hun kolomhoofden) weer
van een database.
De eigenlijke data van een database verandert regelmatig d.m.v. manipulaties. Elke momentopname in de tijd van de data in een database heet de database state (databasetoestand of
instantie).
Je kan het ook als volgt beschrijven: het schema is de intensie van de database, terwijl een
databasetoestand een extensie van dit schema is.
2.2
Three-Schema Architecture and Data Independence
De 3-schema architectuur probeert de volgende drie kenmerken te bereiken en visualiseren:
• Een catalog gebruiken om het schema in op te slaan zodat de database zelfbeschrijvend wordt.
• Isolatie tussen programma’s en opgeslagen data.
• Ondersteunen van meerdere user views (manieren om de data te kunnen interpreteren).
2.2.1
The Three-Schema Architecture
In deze architectuur kunnen schema’s op drie niveaus gedefini¨eerd worden:
• Het interne niveau heeft een intern schema dat de fysische opslagstructuur en de toegangspaden beschrijft.
• Het conceptuele niveau heeft een conceptueel schema (implementatiemodel) dat de structuur van de database weergeeft voor gebruikers.
• Het externe niveau of view niveau heeft een aantal user views (hoe gebruikers data zien).
Deze niveaus moeten uiteraard kunnen samenwerken. Bij het opvragen van data moet deze data
aangepast worden om binnen de view van een zekere gebruik te passen. Deze transformaties tussen
de verschillende niveaus heten mappings.
2.2.2
Data Independence
Data independence binnen de 3-schema architectuur houdt in dat je het schema van ´e´en niveau
kan veranderen zonder dat je het schema van het niveau direct daarboven moet aanpassen. Er zijn
twee types:
• Logical data independence houdt in dat je het conceptueel schema kan aanpassen zonder
dat je daarvoor de externe schema’s of applicaties moet voor aanpassen. Je moet dus de
structuur kunnen aanpassen en constraints kunnen defini¨eren zonder dat je daarvoor een
aanpassing moet doen aan die externe schema’s of applicaties.
• Physical data independence betekent dat je het intern schema kan aanpassen, zonder dat
je aan het conceptueel schema dat er boven draait moet moet raken.
De laatste soort onafhankelijkheid komt in de meeste databases wel voor, maar de eerste soort is
iets moeilijker te verkrijgen.
16
2.3
2.3.1
Database Languages and Interfaces
DBMS Languages
Er zijn 4 theoretische DBMS-talen die belangrijk zijn voor de goede werking van de database:
• De data definition language (DDL) wordt gebruikt om de conceptuele en interne schema’s
te defini¨eren.
• De storage definition language (SDL) specificieert het interne schema.
• De view definition language (VDL) bepaalt de user views en de mappings die ze hebben
naar het conceptueel schema.
• De data manipulation language (DML) staat in voor het manipuleren van data: opvragen,
toevoegen, verwijderen of aanpassen.
Deze zijn theoretisch omdat men in de praktijk niet werkt met aparte talen: alles wordt in ´e´en
ge¨ıntegreerde taal gedefinieerd.
Er zijn 2 soorten DMLs: high-level en low-level. Waar een high-level DML op zichzelf kan
steunen om query’s en dergelijke te processen (het wordt dan ook vaak query-taal genoemd), moet
een low-level DML ingebouwd worden in een algemene programeertaal om gebruik te kunnen maken
van hun functies zoals loops. In dit laatste geval is de low-level taal een data sublanguage van
de host language, de programmeertaal waarin de low-level taal geschreven is.
2.3.2
DBMS Interfaces
Volgende interfaces kunnen in de database aanwezig zijn:
• Menu-Based Interfaces for Web Clients or Browsing. Deze interfaces worden gebruikt
om de inhoud van de database te kunnen opvragen en bekijken met behulp van drop-down
menu’s.
• Forms-Based Interfaces. Deze interfaces maken gebruik van invulvelden om data op te
vragen of om nieuwe data toe te voegen.
• Graphical User Interfaces. Dit type interfaces maakt gebruik van de twee voorgaande
methodes om een nette interface te geven aan de gebruikers.
• Natural Language Interfaces. Hier wordt geprobeerd ingegeven woorden uit een spreektaal
te vertalen zodat de zin kan ge¨ınterpreteerd worden. Dit heet dan keyword-based querying.
• Speech Input and Output. Hierbij kan men via gesproken taal een query ingeven, het
resultaat wordt door de computer ook in gesproken taal gegeven.
• Interfaces for Parametric Users. Interfaces voor gebruikers die een beperkte set commando’s bij herhaling nodig hebben. Door hier een specifieke set van commando’s in te
voeren moeten er minder toetsen worden ingedrukt.
• Interfaces for the DBA. Uiteraard moeten ook de database administrators in staat zijn de
database te kunnen manipuleren. Zij hebben daar deze specifieke interfaces voor.
17
2.4
2.4.1
The Database System Environment
DBMS Component Modules
Elke database en zijn catalogus is opgeslagen op een schijf. Toegang tot deze schijf wordt geregeld
door het besturingssysteem. Daar zit uiteraard ook buffer management ingebakken om disk
read/write operations te schedulen. Bovendien is er nog een stored data manager die de toegang
tot informatie over het systeem beheert.
• Het user-gedeelte van de database bestaat uit de toegang voor de DBA staff, casual users,
application programmers en parametric users.
• Het query and transactie-gedeelte staat in voor het uitvoeren van queries op de data
en het teruggeven van het resultaat. Dit gebeurt in de runtime database processor,
gebruikmakend van de system catalog en de stored data manager. Voordat de query
wordt uitgevoerd is deze reeds gecompiled en geoptimaliseerd door de desbetreffende modules
in het user -gedeelte.
Zie eventueel figuur 2.3 op pagina 39.
2.4.2
Database System Utilities
Elke database heeft een aantal system utilities die helpen bij het beheer van de database:
• Loading. Deze utility staat in voor het inladen van bestaande data files in een bepaald
formaat (bv. tekstbestanden of sequenti¨ele bestanden) in de database.
• Backup. Deze tool maakt een gehele backup van de database om de data te kunnen herstellen bij een disk failure. Soms werkt deze tool met incrementele backup waarbij enkel de
veranderingen sinds de laatste toestand worden opgeslagen.
• Database storage reorganisation. Een tool om een set data te reorganiseren in files of in
een ander pad in de database.
• Performance monitoring. Deze utility houdt het gebruik van de database bij en maakt er
statistieken van die door de administrators kunnen ge¨ınterpreteerd worden.
2.4.3
Tools, Application Environments, and Communications Facilities
Er zijn nog een aantal extra tools die handig kunnen zijn, bijvoorbeeld een information repository. Hierin worden zaken als ontwerpsbeslissingen bijgehouden.
Er is vaak ook communication software nodig om vanop afstand aan de database te kunnen.
2.5
2.5.1
Centralized & Client/Server Architectures for DBMSs
Centralized DBMSs Architecture
De eerste databases werden gebouwd als mainframes met daarop aangesloten terminals, deze terminals hadden geen eigen rekenkracht. Omdat hardware goedkoper werd, begon men de terminals
te vervangen door PC’s en werkstations waarbij het hele DBMS nog steeds centraal draaide.
18
2.5.2
Basic Client/Server Architectures
Dit type architectuur werd ontwikkeld om te kunnen werken in omgevingen met een groot aantal
PC’s, werkstations, printers en allerhande servers. Het idee is om verscheidene servers specifieke
taken te geven in plaats van alles zomaar te centraliseren.
Server-side wordt alles verdeeld over verschillende types servers (printservers, fileservers, webservers, . . . ). Daarnaast is er ook de client-side, waarbij elke machine zijn gebruiker voorziet van de
nodige interfaces om met deze servers te kunnen werken. Al deze servers en machines zijn onderling
verbonden via een communicatienetwerk.
2.5.3
Two-Tier Client/Server Architectures for DBMSs
Een 2-tier client/server architecture is rechtstreeks gegroeid uit de gecentraliseerde architectuur. Interfaces en applicatieprogramma’s werden verhuisd van server- naar client-side. De server
heet in zo’n 2-tier systeem vaak de query server of transaction server omdat dit de functies
van de server zijn. Client-side is er een programma dat via een API met de database kan verbinden
en er query’s kan op uitvoeren binnen de rechten die toegekend zijn aan de client.
De softwarecomponenten zijn dus over 2 soorten systemen verdeeld zijn: clients en servers.
2.5.4
Three-Tier and n-Tier Architectures for Web Applications
Veel webapplicaties werken tegenwoordig met een 3-tier architecture. Er wordt een extra laag
ingebouwd tussen client en server: een application server of web server. Deze server draait
de applicatieprogramma’s en slaat procedures en constraints op waarmee men rekening mee moet
houden bij het opvragen van data van de database server.
Deze middle-tier geldt ook als extra veiligheidsmaatregel: je kan een client verifi¨eren voor je zijn
query doorstuurt naar de databaseserver.
Op de client-layer zijn dan de gebruikers- en webinterfaces aanwezig, terwijl op de server alle
data management services aanwezig zijn.
De verschillende layers kunnen nog verder uit mekaar gehaald worden tot n-tier architectures,
bijvoorbeeld een encryptie-/decryptieserver om communicatie van en naar de servers te beveiligen.
2.6
Classification of Database Management Systems
Om DBMSs te classificeren zijn er een zestal criteria om te beschouwen:
• Het gebruikte datamodel. In veel DBMSs is dat het relationele datamodel.
• Aantal ondersteunde gebruikers. Een single-user system ondersteunt maar ´e´en gebruiker
tegelijk, een multiuser system meerdere.
• Aantal plaatsen waarover de database verdeeld is. Een DBMS is gecentraliseerd als de
data op ´e´en plaats staat en gedistribueerd als de data verspreid is over meerdere plaatsen.
• Kost. Er zijn gratis systemen zoals MySQL en PostgreSQL maar er zijn ook betalende
systemen. Veel geld gaat meestal uit naar het onderhoud van de systemen en ondersteuning
als er problemen zijn. De prioriteiten liggen hier voor particulieren anders dan voor bedrijven.
• Het gekozen type access path. Men gebruikt meestal ge¨ınverteerde bestandstructuren.
• Het doel. Er zijn databases voor algemene doeleinden en voor speciale doeleinden.
19
Hoofdstuk 3
The Basic (Flat) Relational Model
3.1
Relational Model Concepts
Een relationele database bestaat uit verschillende relaties.
Mathematisch Een tabel uit simpele lineaire rijen, ook wel eens naar een flat file genoemd voor
de simpele, lineaire structuur. Rijen hebben elk hun eigen kolom met informatie erin.
Formeel Formeel gezien spreken we over tupels i.p.v. rijen en over attributen i.p.v. kolommen,
elk met een domein. De tabel wordt een relation genoemd.
3.1.1
Domains, Attributes, Tuples, and Relations
Domein Een domein D is een verzameling van onafscheidelijke (of atomische) waardes, bijvoorbeeld een “Naam” bestaande uit letters. Deze waardes zijn volgens de database niet meer te
scheiden. Bij een domein hoort altijd een logische definitie.
Elk domein heeft ook een data type of formaat. Een naam zal uit het datatype string
bestaan, dat zelf uit letters bestaat. Elke tupel zal zich aan dit domein moeten houden. De
kardinaliteit |D| van een domein is het aantal verschillende values dat het kan hebben.
Attributen Een rol (eigenschap) gespeeld door een domein D. Het domein van een attribuut Ai
wordt genoteerd als dom(Ai ).
Formeel: t = {(A1 , w1 ), . . . , (An , wn )} met elke wi ∈ dom(Ai ) of wi = NULL.
Relationeel schema Een relationeel schema R is een n-tupel over een lijst attributen. Een tupel
of rij is een object of verband tussen de attributen. De graad of ariteit van R stelt het aantal
attributen van R voor.
De relatie van een relationeel schema (relational intension) bestaat uit tupels met elk dezelfde attributen (relational extension).
r(R) ⊆ (dom(A1 ) × · · · × dom(An )) is een instantie (instance) van een relatie.
3.1.2
Characteristics of Relations
Ordenen van tupels Abstract gezien hebben tupels geen volgorde. Fysiek gezien moet er wel een
volgorde bestaan (voor het opslaan op de harde schijf).
Ordenen van waardes in een tupel De ordening van attributen (waardes) in een tupel heeft
abstract gezien geen belang, toch wordt meestal een ordening meegegeven.
Een tupel kan ook gezien worden als een set van (<attribuut>,<waarde>) paren waar elk
paar de waarde geeft van een mapping van een attribuut Ai tot een waarde wi van dom(Ai ).
20
Waardes van tupels Elke waarde is steeds atomair en van de eerste normaalvorm (cfr. hoofdstuk
14). Multivalued attributen moeten voorgesteld worden met aparte relaties. Samengestelde
attributen worden voorgesteld door hun afzonderlijke attributen.
Een NULL-waarde betekent dat het attribuut niet van toepassing is of dat de waarde onbekend
is.
Interpretatie van een relatie Relaties kunnen gezien worden als predicaten. De waardes van
elke tupel worden gezien als de waardes die aan de predicaat voldoen.
Een relatie kan ook gezien worden als een declaratie van een type of assertie. Iedere waarde
in die tupel kan dan gezien worden als een feit.
3.1.3
Relational Model Notation
Een relationeel schema R van graad n wordt genoteerd als R(A1 , A2 , . . . , An ). Voorbeelden van
relatienamen zijn Q, R of S, instanties van relaties worden geschreven als q, r of s. Tupels worden
genoteerd als t, u of v.
Een n-tupel t in een relatie r(R) wordt genoteerd als t = < w1 , w2 , . . . , wn >.
Een attribuut A van een relatie R wordt soms genoteerd als R.A. De waarden van een attribuut
Ai worden genoteerd als t.Ai of t[Ai ].
3.2
Relational Model Constraints and Relational Database
Schemas
Er bestaan drie soorten constraints in een database.
• Implicit constraints: de constraints die bij het data model horen.
• Explicit constraints: de constraints die rechtstreeks uitgedrukt worden in de schema’s van
het datamodel, gespecifieerd in de data definition language (DDL).
• Application-based constraints: de constraints die niet rechtstreeks in de schema’s kunnen
worden uitgedrukt. Ook wel business constraints genoemd.
3.2.1
Domain Constraints
De domeinrestricties beperken de mogelijke waarden van attributen: booleans, integers, doubles,
strings. Het domein van een attribuut is altijd enkelvoudig.
Bijvoorbeeld: een attribuut “leeftijd” is een geheel positief getal tussen 18 en 65.
3.2.2
Key Constraints and Constraints on NULL values
Een set van tupels moet uniek zijn, twee tupels mogen dus niet exact dezelfde waarden hebben.
Het gebruik van een (unieke) key lost dit probleem op.
Als U alle attributen van R voorstelt, dus U = {A1 , . . . , An }, dan defini¨eren we de supersleutel
K ⊆ U : de verzameling van attributen die een tupel in R ondubbelzinnig maken (in elke extensie).
Een kandidaatsleutel K is een supersleutel zonder de overtollige attributen. Deze is ook uniek,
er bestaat geen supersleutel K 0 ⊂ K. Een sleutel kan samengesteld of enkelvoudig zijn.
Uit de kandidaatsleutels wordt de primaire sleutel gekozen, deze wordt onderlijnd in het
schema. De andere kandidaatsleutels zijn de alternatieve sleutels, deze worden niet onderlijnd.
Er worden ook constraints vastgelegd die bepalen of een attribuut de waarde NULL mag bevatten.
21
3.2.3
Relational Databases and Relational Database Schemas
Een relationeel databaseschema S is een set van relatieschema’s S = {R1 , . . . , Rm } en een set
van integrity constraints IC. Een relationele databasetoestand DB van S is een set van
relatietoestanden DB = {r1 , . . . , rm } waarbij elke ri de integriteitconstraints in IC volgt.
De statica-regels slaan op 1 toestand van DB en gelden in elke extensie. De dynamica-regels
slaan op toestandsovergangen en gelden voor elke overgang tussen extensies.
3.2.4
Integrity, Referential Integrity and Foreign Keys
Volgens de entitity integrity constraint kan een primaire sleutel nooit NULL zijn. Deze constraint
bepaalt ook dat een tupel niet meer dan 1 keer mag voorkomen in een extensie.
De referential integrity constraint bepaalt dat een verwijzing naar een andere tupel geldig
moet zijn. Als een tupel naar een andere tupel verwijst, moet die andere ook tupel bestaan.
Een verzameling attributen FK van R1 is een foreign key (verwijssleutel ) dat refereert naar R2
als en slechts als:
• De attributen van FK hebben dezelfde domeinen als de de primaire sleutelattributen PK van
relatie R2 .
• Elke waarde van FK in R1 komt voor als de waarde van een tupel in R2 of is NULL.
∀t1 ∈ R1 : t1 [FK ] = NULL ∪ ∃t2 ∈ R2 : t1 [FK ] = t2 [PK ]
Een verwijssleutel kan naar een eigen relatie verwijzen, dit is dus een recursieve relatie.
3.2.5
Other Types of Constraints
Semantic integrity constraints zijn algemene constraints die niet opgelegd kunnen worden door
de data definition language, deze worden opgelegd door de applicaties zelf. Ook een constraint
specification language kan hiervoor zorgen. Een voorbeeld van zo’n constraint is het maximum
aantal werkuren dat een werknemer kan werken.
De functional dependency constraint cre¨eert een functionele relatie tussen 2 sets attributen
X en Y . Een waarde van X bepaalt een unieke waarde van Y in alle toestanden van een relatie:
X → Y . Zie hoofdstukken 14 en 15.
De constraints die tot nu vernoemd werden, zijn state constraints omdat ze bepalen of een
database zich een een geldige toestand bevindt.
Een andere soort constraints zijn de transition constraints en bepalen welke overgangen tussen
databasetoestanden geldig zijn.
Er zijn verscheidene dynamica-regels. De autorisatieregels bepalen welke acties een bepaalde
gebruiker mag uitvoeren. Er bestaan ook precondities en postcondities.
De overgangsregels beschrijven welke volgordes van extensies zijn toegestaan. Bijvoorbeeld:
enkel loonsverhogingen zijn toegestaan, geen verlagingen.
Intrarelationele restricties werken intern, dus binnen 1 relatie. Deze zijn meestal gemakkelijker te controleren. Hier tegenover staan de interrelationele restricties waarbij verschillende
relaties betrokken zijn. Een voorbeeld van deze laatste soort: het salaris van een werknemer moet
altijd kleiner zijn dan het loon van zijn overste.
Tegenwoordig laat men meer soorten restricties automatisch controleren door het DBMS.
22
3.3
3.3.1
Update Operations, Transactions and Dealing with
Constraint Violations
The Insert Operation
Bij het invoegen van nieuwe data moet gekeken worden dat alle bovenstaande constraints niet
overschreden worden. Moest er een constraint overschreden worden, zal het DBMS cascaden. De
toevoeging wordt dan geweigerd en de gebruiker krijgt een melding.
3.3.2
The Delete Operation
Deze operatie kan alleen de referential integrity overschrijden (verwijzing naar een onbestaande of
ongeldige tupel). Het DBMS kan verscheidene dingen doen bij een overschreden constraint:
• De verwijdering weigeren.
• De verwijzende tupels ook weglaten.
• De verwijzende waarden aanpassen (bijvoorbeeld op NULL of default zetten).
• Verschillend reageren in verschillende situaties (ingesteld door de gebruiker).
3.3.3
The Update Operation
Voornamelijk een primaire sleutel aanpassen kan problemen opleveren, er is namelijk een gevaar
voor de uniciteit van de sleutel. De beste oplossing is het verwijderen en direct terug toevoegen van
de tupel.
Bij een wijziging van een verwijssleutel, moet ook de referenti¨ele integriteit gecontroleerd worden.
3.3.4
The Transaction Concept
Een database voert operaties meestal uit in de vorm van transactie zodat er altijd terug naar een
valid state gegaan kan worden moest de huidige operatie mislukken.
23
Hoofdstuk 4
SQL: Data Definition, Constraints, and
Basic Queries and Updates
SQL (Structured Query Language) is een ANSI/ISO-standaardtaal voor een relationeel DBMS.
Het is een gestandaardiseerde taal die gebruikt kan worden voor taken zoals het bevragen en het
aanpassen van gegevens in een relationele databank. SQL kan met vrijwel alle moderne relationele
databankproducten worden gebruikt.
4.1
SQL Data Definition and Data Types
SQL gebruikt de termen table, row en column voor de termen relation, tuple en attribute die in het
formele, relationele model gebruikt worden. Het belangrijkste SQL-commando voor het defini¨eren
van data is het create-statement om schema’s, relaties, domeinen, enz. te cre¨eren.
4.1.1
Schema and Catalog Concepts in SQL
Oudere versies van SQL kenden het concept van relationele database-schema’s niet. Alle tabellen
werden beschouwd als een deel van hetzelfde schema.
Een SQL schema wordt ge¨ıdentificeerd door een schemanaam en bevat een authorization
identifier om de gebruiker of het account die het schema beheert, te identificeren. Het bevat ook
descriptors voor elk element in het schema. Schema elements omvatten tables, views, domains,
constraints, enz.
SQL maakt ook gebruik van een catalog: een verzameling van schema’s in een SQL-omgeving
(een installatie op een computersysteem van een DBMS die gebruik maakt van SQL).
Het aanmaken van een nieuw schema gaat als volgt.
CREATE SCHEMA COMPANY AUTHORIZATION ‘owner’ ;
4.1.2
The CREATE TABLE Command in SQL
Het commando create table wordt gebruikt om een niuewe relatie te defini¨eren door een naam
op te geven en de attributen te specifi¨eren.
Er zijn twee manieren om een nieuwe tabel te defini¨eren, de tweede manier is de aangeraden
manier. Op de plaats van de puntjes moeten nog de attributen met hun datatypes (en domeinen)
ingevuld worden. Dit zien we in 4.1.3.
CREATE TABLE EMPLOYEE (. . . );
CREATE TABLE COMPANY.EMPLOYEE (. . . );
24
4.1.3
Attribute Data Types and Domains in SQL
Voor elk attribuut wordt er tussen de haakjes in het create table-statement een naam en een
datatype ingevuld. Eventueel worden er nog per attribuut enkele restricties toegevoegd. Na de
attributen kunnen er nog tabelrestricties toegevoegd worden.
Er bestaan verschillende soorten datatypes:
• Numeric data types omvatten integers (integer, int en smallint) en floating-point
getallen van verschillende precisie: float (of real) en double precision.
• Character-string data types zijn ofwel fixed-length (char(n) en character(n) met n
het aantal karakters) ofwel variable-length (varchar(n), char varying(n) of character
varying(n) met n het maximum aantal karakters).
• Bit-string data types zijn fixed-length (bit(n)) of variable-length (bit varying(n)).
• Boolean data types hebben de waarden TRUE of FALSE. In SQL is er door de aanwezigheid
van NULL-waarden nog een derde waarde mogelijk: UNKNOWN.
• Het DATE-datatype bestaat uit 10 posities heeft als componenten year, month en day in
de vorm YYYY-MM-DD.
Het TIME-datatype heeft maximum 8 posities en heeft als componenten hour, minute en
second in de vorm HH:MM:SS. Het TIME WITH TIME ZONE-datatype bevat nog 6
extra posities voor een afwijking t.o.v. de standaard universele tijdzone.
• Het TIMESTAMP-datatype bevat de date- en time-velden, plus minimaal 6 posities voor
decimale delen van een seconde en een optionele with time zone-qualifier.
• Het INTERVAL-datatype specifieert een interval (een relatieve waarde) die gebruikt kan
worden om de absolute waarde van een date, time of timestamp te verhogen of te verlagen.
4.2
4.2.1
Specifying Constraints in SQL
Specifying Attribute Constraints and Attribute Defaults
Omdat SQL NULL-waarden toelaat als attribuutwaarde, kunnen we een constraint NOT NULL specifi¨eren als NULL niet toegelaten is als waarde voor een bepaald veld.
Men kan ook een default value defini¨eren voor een attribuut d.m.v. default <value>. Als
er geen default waarde gedefinieerd is, is de default waarde NULL.
Een ander type constraint kan attribuut- en domeinwaarden beperken d.m.v. check x waarbij
x een attribuut- of domeindefinitie is. Bijvoorbeeld:
Dnumber INT NOT NULL
CHECK (Dnumber > 0 AND Dnumber < 21);
De check-clausule kan men ook gebruiken samen met de create domain-statement.
CREATE DOMAIN D NUM AS INTEGER
CHECK (D NUM > 0 AND D NUM < 21);
25
4.2.2
Specifying Key and Referential Integrity Constraints
PRIMARY KEY definieert ´e´en of meerdere attributen die de primaire sleutel van een relatie
vormen. Bijvoorbeeld: de primaire sleutel van department kan als volgt gedefinieerd worden.
Deze restrictie gebeurt bij onmiddellijk bij de definitie van het attribuut.
Dnumber INT PRIMARY KEY;
Men kan een restrictie ook specifi¨eren door met het sleutelwoord CONSTRAINT een restrictie
(met een naam) te defini¨eren. Dit is later makkelijker aanpasbaar.
CONSTRAINT DEPTPK
PRIMARY KEY (Dnumber ),
UNIQUE definieert de alternatieve (secundaire) sleutels. De manieren om alternatieve sleutels te
defini¨eren zijn analoog aan de manieren om primaire sleutels te defini¨eren.
Referenti¨
ele integriteit wordt gespecifieerd door FOREIGN KEY. Bij een integrity violation
zal SQL standaard de restrict-actie uitvoeren. De update-operatie wordt dus geweigerd.
De gebruiker kan ook een andere actie instellen, een referential triggered action kan aan elke
foreign key toegevoegd worden. De andere acties zijn set null, cascade en set default. Zo’n
actie moet meegegeven worden bij een trigger: on delete of on update.
Bijvoorbeeld: we bepalen dat de foreign key “Mgr ssn” in department refereert naar de primaire sleutel “Ssn” in employee. Deze constraint wordt toegevoegd in de definitie van de tabel
department, na de definities van de attributen.
CONSTRAINT DEPTMGRFK
FOREIGN KEY (Mgr ssn) REFERENCES EMPLOYEE(Ssn)
ON DELETE SET DEFAULT
ON UPDATE CASCADE,
4.2.3
Giving Names to Constraints
Het is het beste om alle constraints een naam te geven (zie de voorbeelden in de vorige sectie). De
namen van alle constraints in eenzelfde schema moeten uniek zijn.
4.2.4
Specifying Constraints on Tuples Using CHECK
Als toevoeging op de key- en referentie-constraints zijn er nog andere table-constraints die gedefinieerd kunnen worden door optionele CHECK-clausules op het einde van een CREATE TABLE-statement toe te voegen. Dit zijn de tuple-based constraints omdat ze voor elke tupel
individueel nagekeken worden telkens wanneer een tupel wordt toegevoegd of aangepast.
Bijvoorbeeld: het moment dat een manager aangesteld wordt om een bepaald departement te
leiden, kan uiteraard niet plaatsvinden voordat het departement opgericht wordt. De volgende
constraint wordt toegevoegd achteraan de CREATE TABLE-statement van department.
CHECK (Dept create date <= Mgr start date);
26
4.3
Basis Retrieval Queries in SQL
SQL heeft ´e´en basisoperatie om gegevens op te vragen: SELECT. Deze operatie is niet hetzelfde
als de select-operatie in relationele algebra.
4.3.1
The SELECT-FROM-WHERE Structure of Basic SQL Queries
De basisvorm van het SELECT-statement is hieronder gegeven. Dit wordt ook wel het mapping
block of het select-from-where block genoemd.
SELECT <attributenlijst>
FROM <tabellenlijst>
WHERE <condities>
Hierbij wordt <condities> ingevuld door een Booleaanse conditie: de selectievoorwaarde. Een
conditie als (Dnumber = Dno) noemen we een joinconditie omdat het 2 tupels combineert.
Voor voorbeelden van select-from-where blokken, zie pagina 94-96.
4.3.2
Ambiguous Attribute Names, Aliasing, Renaming, and Tuple Variables
In SQL kunnen we dezelfde naam gebruiken voor 2 of meerdere attributen, zolang ze zich in verschillende relaties bevinden. Bijvoorbeeld:
WHERE CAR.Name = BICYCLE.Name;
Als we een query hebben die tweemaal gebruik maakt van dezelfde relatie, kunnen we de aparte
verwijzingen aparte namen geven: een alias. Deze aliassen zijn dan een soort kopie¨en van de
originele relatie. Bijvoorbeeld:
SELECT E.Fname, E.Lname, S.Fname, S.Lname
FROM EMPLOYEE AS E, EMPLOYEE AS S
WHERE E.Super ssn = S.Ssn;
Het is ook mogelijk om de attributen van een relatie te hernoemen. Bijvoorbeeld:
FROM EMPLOYEE AS E(Fn, Mi, Ln, Ssn, Bd, Addr, Sex, Sal, SSsn, Dno)
4.3.3
Unspecified WHERE Clause and Use of the Asterisk
Als de WHERE-clausule ontbreekt, wordt er geen conditie opgelegd wordt op de tupels. Alle
tupels van de relatie (gespecifieerd in de FROM-clausule) voldoen aan de query.
Als er meer dan 1 relatie gespecifieerd is in de FROM-clausule en als er geen WHERE-clausule
is, dan wordt het Carthesisch product van de relaties genomen.
Als men alle attributen wil selecteren in de SELECT-clausule, zet men gewoon een asterisk (*)
achter SELECT. Dan moet men niet alle mogelijke attributen opsommen.
4.3.4
Tables as Sets in SQL
SQL behandelt een tabel meestal niet als een set maar als een multiset. Duplicaten van tupels
kunnen meer dan ´e´en keer voorkomen in een tabel en in het resultaat van een query. SQL verwijdert
duplicaten niet automatisch uit het resultaat van een query, dit heeft verschillende redenen.
• Het verwijderen van duplicaten is een intensieve taak. Men kan dit toch doen door alle tupels
te sorteren en dan de duplicaten te verwijderen.
27
• Het kan zijn dat de gebruiker de duplicaten wel wil zien in het resultaat van zijn query.
• Als een aggregaatfunctie wordt toegepast op tupels (zie 5.1.7), willen we in de meeste gevallen
geen duplicaten verwijderen.
Als we toch alle duplicaten uit het resultaat willen verwijderen, kunnen we SELECT DISTINCT
gebruiken. Als we de duplicaten wel willen zien, kunnen we SELECT ALL gebruiken, dit is de
standaard optie.
SQL maakt ook gebruik van de wiskundige set theory dat onderdeel is van de relationele algebra (zie H6). Er bestaan 3 verzamelingsoperaties: UNION, EXCEPT en INTERSECT. Het
resultaat van deze operatoren is een set van tupels, dit wil zeggen dat duplicaten verwijderd worden. SQL heeft ook corresponderende operaties voor multisets, hierbij wordt het keyword ALL
toegevoegd, bijvoorbeeld UNION ALL. Deze operaties worden als volgt gebruikt.
(<select-from-where block >) UNION (<select-from-where block >)
4.3.5
Substring Pattern Matching and Arithmetic Operators
In SQL kunnen we vergelijkingscondities defini¨eren op basis van substrings, dit doen we met de
vergelijkingsoperator LIKE. We kunnen dit gebruiken voor string pattern matching, we plaatsen
hiervoor de substring tussen 2 %-tekens. Het %-teken staat voor 0 of meerdere willekeurige tekens,
een underscore ( ) vervangt een enkel karakter. Bijvoorbeeld: we willen de namen opvragen van de
werknemers die in Houston wonen.
SELECT Fname, Lname
FROM EMPLOYEE
WHERE Address LIKE ‘%Houston%’ ;
We kunnen ook gewone wiskundige operaties gebruiken: optellen (+), aftrekken (-), vermenigvuldigen (*) en delen (/). Twee strings kunnen we samenvoegen met de samenvoegingsoperator ||.
De vergelijkingsoperator BETWEEN kan je gebruiken om alle tupels met een attribuutwaarde
tussen 2 constanten te selecteren. De volgende 2 condities zijn identiek.
(Salary > 30000) AND (Salary 6 40000)
Salary BETWEEN 30000 AND 40000
4.3.6
Ordering of Query Results
SQL laat met ORDER BY toe het resultaat van een query te sorteren volgens de waarden van 1
of meerdere attributen die voorkomen in dit resultaat. We kunnen gebruik maken van DESC en
ASC (standaard) om de resultaten in dalende (resp. stijgende) volgorde weer te geven.
SELECT Fname, Lname
FROM EMPLOYEE
ORDER BY Fname DESC, Lname ASC;
4.3.7
Discussion and Summary of Basic SQL Retrieval Queries
Kort samengevat kan een retrieval query in SQL uit 4 delen bestaan:
SELECT <attributenlijst>
FROM <tabellenlijst>
[ WHERE <conditie> ]
[ ORDER BY <attributenlijst> ];
28
4.4
4.4.1
INSERT, DELETE, and UPDATE Statements in SQL
The INSERT Command
INSERT wordt gebruikt om een enkele tupel toe te voegen aan een relatie. Hiervoor specifi¨eren we
de relatienaam en een lijst van waarden voor deze tupel. De waarden moeten in dezelfde volgorde
staan als de attributen in de relatie (zoals beschreven in CREATE TABLE).
INSERT INTO DEPARTMENT
VALUES (‘Research’, 5, ‘333445555’, ‘1988-05-22’ );
We kunnen een attribuut weglaten als NULL toegelaten is of als er een default waarde bestaat.
INSERT INTO EMPLOYEE(Fname, Lname, Ssn)
VALUES (‘Richard’, ‘Marini’, ‘653298653’ );
4.4.2
The DELETE Command
DELETE wordt gebruikt om bepaalde tuples te verwijderen uit een relatie en bevat een WHEREclausule om de tuples te selecteren.
DELETE FROM EMPLOYEE
WHERE Lname = ‘Brown’;
Om de hele tabel te verwijderen, kunnen we DROP TABLE gebruiken.
4.4.3
The UPDATE Command
UPDATE wordt gebruikt om attribuutwaarden van 1 of meerdere geselecteerde tupels aan te
passen. Ook hier is een WHERE-clausule nodig om de aan te passen tuples te selecteren. Een
bijkomende SET specifieert de aan te passen attributen en hun nieuwe waarden.
UPDATE PROJECT
SET Plocation = ‘Bellaire’, Dnum = 5
WHERE Pnumber = 10;
4.5
Additional Features of SQL
• In hoofdstuk 5 bespreken we verschillende technieken om complexe retrieval query’s te maken.
• SQL heeft verschillende technieken om programma’s te schrijven in verschillende programmeertalen om toegang te krijgen tot databases.
• Er was vroeger de mogelijkheid om indices te cre¨eren: CREATE INDEX.
• SQL heeft transaction control commands, zie hoofdstuk 20.
• SQL kan omgaan met privileges.
• In SQL is het mogelijk om triggers te defini¨eren.
• SQL heeft verschillende eigenschappen overge¨erfd van objectgeori¨enteerde modellen, dit leidt
tot geavanceerde relationele systemen: object-relational.
• SQL en relationele databases kunnen overweg met nieuwe technologie¨en zoals XML.
29
Hoofdstuk 5
SQL: Advanced Queries, Assertions,
Triggers, and Views
5.1
5.1.1
More Complex SQL Retrieval Queries
Comparisons Involving NULL and Three-Valued Logic
In SQL kan NULL 3 verschillende betekenissen hebben:
1. Unknown value. Een veld dat leeggelaten wordt (bv. de geboortedatum niet invullen).
2. Unavailable or withheld value. Data die verborgen gehouden wordt (bv. een persoon
heeft een telefoon, maar wil zijn nummer niet geven om persoonlijke redenen).
3. Not applicable attribute. Data die niet van toepassing is (bv. een diploma-veld voor een
persoon die geen studies voltooid heeft).
Omdat het vaak niet mogelijk is om te achterhalen over welk type NULL het gaat, gaat men in SQL
ervan uit dat elke NULL-waarde anders is dan elke andere NULL-waarde. Als men een vergelijking
(bv. AND, OR en NOT) uitvoert met een NULL-waarde, kan de juiste uitkomst zowel TRUE als
FALSE zijn. Daarom wordt de uitkomst van zo’n vergelijking altijd met UNKNOWN aangeduid. SQL
gebruikt dus three-valued logic in plaats van de standaard Boolean logic (two-valued ).
Tabel 5.1 op pagina 112 toont alle mogelijke uitkomsten in deze logica.
De algemene regel is dat in select-project-join queries enkel de combinaties van tupels die evalueren naar TRUE geselecteerd worden. Combinaties van tupels die evalueren naar FALSE of UNKNOWN
worden dus niet geselecteerd. De uitzonderingen op deze regel zien we in 5.1.6.
SQL laat queries toe om na te gaan of een bepaalde waarde NULL is. In plaats van de gewone
vergelijkingsoperatoren, gebruikt men IS of IS NOT.
WHERE Super ssn IS NOT NULL;
5.1.2
Nested Queries, Tuples, and Set/Multiset Comparisons
Voor sommige queries is het nodig dat er bepaalde waarden uit de database gehaald worden die dan
gebruikt worden in een vergelijkingsconditie. Dit soort queries kan in SQL makkelijk geformuleerd
worden met zogenaamde nested queries. Dit zijn volledige select-from-where blokken binnen de
WHERE-clausule van een andere query (de outer query).
We introduceren ook de vergelijkingsoperator IN, hiermee kan een waarde vergeleken worden
met een set (verzameling) van waarden. De operator evalueert naar TRUE als het element een
onderdeel is van de verzameling.
30
SELECT DISTINCT Pnumber
FROM PROJECT
WHERE Pnumber IN (<select-from-where block >);
Je kan ook tupels van waarden vergelijken door ze binnen haakjes te zetten. Bijvoorbeeld: de
volgende query selecteert alle werknemers die werken aan een project met dezelfde (project, uren)combinatie als werknemer 123456789 aan dat project werkt.
SELECT DISTINCT Essn
FROM WORKS ON
WHERE (Pno, Hours) IN
( SELECT Pno, Hours
FROM WORKS ON
WHERE Essn = ‘123456789’ );
Er zijn nog andere operatoren om een enkele waarden v te vergelijken met een set of multiset. De
‘= ANY’-operator is in essentie hetzelfde als de IN-operator maar kan gecombineerd worden met
de volgende operatoren: >, >=, <, <= en <>.
Het keyword ALL kan ook gecombineerd worden met deze operatoren. Zo kan men bijvoorbeeld
de namen vragen van de werknemers die meer verdienen dan alle werknemers uit departement 5.
SELECT Fname, Lname
FROM EMPLOYEE
WHERE Salary > ALL
( SELECT Salary
FROM EMPLOYEE
WHERE Dno = 5 );
5.1.3
Correlated Nested Queries
Twee queries zijn correlated als de binnenste query afhankelijk is van de buitenste query. Dit is
het geval als bijvoorbeeld de binnenste query refereert naar de buitenste query. De binnenste query
moet voor iedere waarde van de buitenste query uitgevoerd worden.
We kunnen de volgende query als volgt zien. Voor elke employee-tupel ek : de binnenste query
haalt de “Essn”-waarden op van alle dependent-tupels met hetzelfde geslacht en dezelfde naam
als ek . Als de “Ssn”-waarde van ek voorkomt in het resultaat van de binnenste query, selecteer die
employee-tupel ek dan.
SELECT E.Fname, E.Lname
FROM EMPLOYEE AS E
WHERE E.Ssn IN
( SELECT Essn
FROM DEPENDENT AS D
WHERE E.Fname = D.Dependent name AND E.Sex = D.Sex );
5.1.4
The EXISTS and UNIQUE Functions in SQL
De EXISTS-functie wordt gebruikt om te kijken of het resultaat van een correlated nested query
leeg is of niet. De functie evalueert naar TRUE als als het resultaat van de nested query minstens 1
tuple bevat, anders naar FALSE. Er bestaat ook NOT EXISTS.
De volgende query kan men als volgt zien. Voor elke employee-tupel ek : haal alle dependenttupels op die verwant zijn aan ek . Als er geen gerelateerde dependent-tupels bestaan, zal ek
geselecteerd niet worden, in het andere geval wel.
31
SELECT E.Fname, E.Lname
FROM EMPLOYEE AS E
WHERE EXISTS
( SELECT *
FROM DEPENDENT AS D
WHERE E.Ssn = D.Essn );
Het is ook mogelijk om het verschil van twee verzamelingen te nemen, hiervoor gebruiken we de
EXCEPT-operator. Voor een voorbeeld verwijzen we naar query Q3A op pagina 117.
De UNIQUE(Q)-operator evalueert naar TRUE als er geen duplicaten voorkomen in het resultaat van de query Q, in het andere geval FALSE. Deze operator kan gebruikt worden om te testen
of het resultaat van een geneste queryeen set of een multiset is.
5.1.5
Explicit Sets and Renaming of Attributes in SQL
In plaats van een nested query te gebruiken in de WHERE-clausule, is het ook mogelijk om zelf een
expliciete set van waarden te defini¨eren. Bijvoorbeeld: de volgende query vraagt de “Essn”-waarden
op van alle werknemers die werken aan project 1, 2 of 3.
SELECT DISTINCT Essn
FROM WORKS ON
WHERE Pno IN (1, 2, 3);
Het is ook mogelijk om attributen in het resultaat te hernoemen met de AS-operator.
SELECT E.Lname AS Employee name, S.Lname AS Supervisor name
FROM EMPLOYEE AS E, EMPLOYEE AS S
WHERE E.Super ssn = S.Ssn;
5.1.6
Joined Tables in SQL and Outer Joins
Het concept van joined tables wordt gebruikt om te vermijden dat een gebruiker zeer veel ‘=’
moet gebruiken in de WHERE-clausule.
Bijvoorbeeld: we willen de namen van alle werknemers opvragen die voor het onderzoeksdepartement werken. De conditie (Dno = Dnumber) zorgt ervoor dat enkel zinvolle tupels gegenereerd
worden met de JOIN-operator.
SELECT Fname, Lname
FROM ( EMPLOYEE JOIN DEPARTMENT ON Dno = Dnumber )
WHERE Dname = ‘Research’;
We kunnen ook gebruik maken van NATURAL JOIN om tabellen samen te voegen. Hierbij wordt
er geen conditie meegegeven maar wordt er gejoind op elk paar attributen met dezelfde naam. Als
de naam van de attributen waarop we willen joinen niet overeenkomen, kunnen we de AS-operator
gebruiken om ze te hernoemen.
SELECT Fname, Lname
FROM ( EMPLOYEE NATURAL JOIN
DEPARTMENT AS DEPT(Dname, Dno, Mssn, Msdate)
)
WHERE Dname = ‘Research’;
Standaard wordt er gejoind met een inner join, hiertegenover staat een outer join. Voor meer
uitleg, zie hoofdstuk 6.
Het is ook toegelaten om joins te nesten, dit noemen we een multiway join.
32
5.1.7
Aggregate Functions in SQL
Aggregaatfuncties laten toe om tupels in een resultaat samen te vatten. De ingebouwde aggregaatfuncties zijn COUNT, SUM, MAX, MIN en AVG.
De COUNT-functie telt het aantal tupels die een bepaalde conditie voldoen en geeft dit aantal
terug als resultaat. Bijvoorbeeld: de volgende query geeft het aantal werknemers terug.
SELECT COUNT (*)
FROM EMPLOYEE;
De volgende query geeft als resultaat het aantal unieke lonen uit de employee-relatie.
SELECT COUNT (DISTINCT Salary)
FROM EMPLOYEE;
COUNT kan ook bij de WHERE-clausule gebruikt worden om bijvoorbeeld werknemers op te
vragen die 2 of meer dependents hebben.
SELECT E.Fname, E.Lname
FROM EMPLOYEE AS E
WHERE ( SELECT COUNT (*)
FROM DEPENDENT AS D
WHERE E.Ssn = D.Essn ) >= 2;
Op deze manier kunnen ook de andere aggregaatfuncties gebruikt worden.
5.1.8
Grouping: The GROUP BY and HAVING Clauses
We willen vaak aggregaatfuncties toepassen op bepaalde groepen van tupels waarbij de groepen
gedefinieerd worden door een bepaald attribuut. Het attribuut waarop gegroepeerd moet worden, duiden we aan met GROUP BY. Als er NULL-waarden voorkomen in het attribuut waarop
gegroepeerd wordt, zal er voor deze tupels een aparte groep gemaakt worden.
Bijvoorbeeld: we willen voor elk departement het departementsnummer, het aantal werknemers
en hun gemiddeld loon opvragen. We nemen als groep ‘alle werknemers met hetzelfde departementsnummer’. Figuur 5.1a op pagina 123 is een visualisatie van deze query.
SELECT Dno, COUNT (*), AVG (Salary)
FROM EMPLOYEE
GROUP BY Dno
Soms willen we enkel informatie over groepen die voldoen aan een bepaalde voorwaarde, hiervoor
kunnen we de clausule HAVING gebruiken.
Het verschil tussen HAVING en een conditie opleggen in WHERE is dat we bij de HAVINGclausule een conditie kunnen opleggen voor een volledige groep tupels. De WHERE-clausule
daarentegen kan enkel condities opleggen aan individuele tupels.
Bijvoorbeeld: we willen van elk project met meer dan 2 werknemers het projectnummer, de
projectnaam en het aantal werknemers opvragen.
SELECT Pnumber, Pname, COUNT (*)
FROM PROJECT, WORKS ON
WHERE Pnumber = Pno
GROUP BY Pnumber, Pname
HAVING COUNT (*) > 2;
33
5.2
5.2.1
Specifying Constraints as Assertions and Actions as
Triggers
Specifying General Constraints as Assertions in SQL
CREATE ASSERTION wordt gebruikt om extra constraints op te leggen, naast de restricties
op tabellen of attribuutwaarden (die bij het aanmaken van een tabel gecre¨eerd worden). Elke latere
wijziging in de gegevensbank wordt slechts toegelaten als er aan de assertie voldaan is.
Bijvoorbeeld: we willen opleggen dat een werknemer nooit meer kan verdienen dan zijn manager.
CREATE ASSERTION SALARY CONSTRAINT
CHECK (
NOT EXISTS (
SELECT *
FROM EMPLOYEE E, EMPLOYEE M, DEPARTMENT D
WHERE E.Salary > M.Salary
AND E.Dno > D.Dnumber
AND D.Mgr ssn > M.Ssn
)
);
5.2.2
Introduction to Triggers in SQL
Bij CREATE TRIGGER wordt er een actie opgegeven die ondernomen zal worden als er niet aan
een bepaalde voorwaarde is voldaan. Triggers zullen dus een database monitoren. Een typische
trigger bevat de volgende elementen:
• Een event die bepaalt wanneer een conditie gecheckt moet worden (meestal bij een update).
• De conditie die bepaalt wanneer een actie uitgevoerd moet worden.
• De actie zelf, dit is een SQL-query of een extern programma.
Voor een voorbeeld van een trigger, zie R5 op pagina 128-129.
5.3
5.3.1
Views (Virtual Tables) in SQL
Concept of a View in SQL
Een view is een tabel die afgeleid wordt uit andere tabellen, de tupels van een view worden niet
expliciet opgeslagen. De defini¨
erende tabellen kunnen ‘echte’ tabellen of ook views zijn. Een
view is enkel virtueel en wordt niet gematerialiseerd.
Views zijn handig als beveiligingsmechanisme, een gebruiker krijgt maar zicht op een deel van de
database. Er is ook geen redundantie doordat er geen nieuwe (expliciete) tabellen gemaakt worden.
5.3.2
Specification of Views in SQL
Men kan een view aanmaken met CREATE VIEW. Een view heeft een bepaalde naam, een
attributenlijst en een query om aan deze attributen te geraken. Na het aanmaken van een view kan
men hierop queries uitvoeren alsof het een echte tabel was.
Een view wordt verwijderd met het commando DROP VIEW.
34
Bijvoorbeeld: we willen een view hebben van alle werknemers die aan een project werken.
CREATE VIEW WORKS ON 1
AS
SELECT Fname, Lname, Pname, Hours
FROM EMPLOYEE, PROJECT, WORKS ON
WHERE Ssn = Essn AND Pno = Pnumber;
5.3.3
View Implementation, View Update, and Inline Views
Het is niet simpel om queries die verwijzen naar views effici¨ent te implementeren. Er bestaan 2
benaderingen om dit probleem aan te pakken.
• Query modification
De query van de view wordt met algoritmes omgevormd tot een query op de onderliggende
tabellen. Het grote nadeel van deze methode is dat de resulterende queries soms heel complex
kunnen zijn, vooral bij views die gedefinieerd zijn door reeds complexe queries.
• View materialization
Als men meerdere queries die naar een bepaalde view verwijzen, na elkaar wil uitvoeren,
kan men tijdelijk de view materialiseren (opslaan als een ’echte’ tabel). Hierbij moet er
natuurlijk een effici¨ent systeem bedacht worden om de echte tabellen up-to-date te houden
met de opgeslagen view.
Niet elke query die verwijst naar een view kan zinvol zijn. Bijvoorbeeld: een query die een attribuut
aanpast dat in de view door de aggregaatfunctie SUM gegenereerd wordt, heeft geen zinvolle vertaling naar een query op een ’echte’ tabel. Soms kan er ook ambigu¨ıteit optreden bij het aanpassen
van een view.
Over het algemeen is een update op een view enkel haalbaar als deze query zonder ambigu¨ıteit
vertaald kan worden naar een zinvolle query op de onderliggende tabellen.
5.4
5.4.1
Schema Change Statements in SQL
The DROP Command
Het DROP-commando wordt gebruikt om schema-elementen (met een naam) te verwijderen, dit
zijn tabellen, domeinen of constraints. Men kan ook een schema zelf verwijderen.
Er zijn 2 manieren waarop een DROP SCHEMA uitgevoerd kan worden.
• CASCADE. Alle schema-elementen en het schema zelf worden verwijderd.
• RESTRICT. Het schema wordt enkel verwijderd als het geen elementen bevat.
Bij DROP TABLE is er een analoog gedrag: bij CASCADE wordt de tabel verwijderd. Bij
RESTRICT wordt de tabel enkel verwijderd als er geen referenties naar de tabel bestaan.
5.4.2
The ALTER Command
De definitie van een tabel of andere benoemde schema-elementen kan veranderd worden met het
ALTER-commando. Er kan bijvoorbeeld een kolom toegevoegd worden aan een tabel of de naam
van een kolom kan veranderd worden.
ALTER TABLE COMPANY.EMPLOYEE
DROP COLUMN Address CASCADE;
ALTER TABLE COMPANY.DEPARTMENT
ALTER COLUMN Mgr ssn SET DEFAULT ‘333445555’ ;
35
Hoofdstuk 6
Formal Relational Languages: The
Algebra and Calculus
In dit hoofdstuk behandelen we twee formele talen voor het relationele model: relationele algebra
en relationele calculus.
6.1
6.1.1
Unary Relational Operations: SELECT & PROJECT
The SELECT Operation
De select-operatie wordt gebruikt om een subset van tupels uit een extensie op te vragen die
voldoen aan een bepaalde conditie. Intu¨ıtief kan het gezien worden als een filter. We beginnen met
een voorbeeld om de werknemers op te vragen die meer verdienen dan 3000.
σ Salary > 3000 (employee)
Een generiek select-statement uit een database ziet er als volgt uit.
σF (R) = σ<conditie> (R)
Het sigma-symbool (σ) wordt hier gebruikt om select aan te duiden. Het selectiecriterium F
(of conditie) is een logische formule die attributen uit de relatie R gebruikt. Een generieke conditie
heeft ´e´en van de volgende vormen.
<attribuutnaam> <vergelijking> <constante>
<attribuutnaam> <vergelijking> <andere attribuutnaam>
De <vergelijking> gebruikt meestal een van de volgende operatoren: {=, <, >, 6, >, 6=}. Condities
kunnen samengesteld worden met de operatoren {∧, ∨, ¬} om meervoudige formules te maken.
De select-operator is unair, hij wordt dus toegepast op een enkele relatie. De select-operator
is ook commutatief, voor het resultaat maakt het dus niet uit in welke volgorde ze uitgevoerd
worden. Dit kan wel een verschil maken in performantie. Er geldt dus:
σC1 (σC2 (. . . (σCn (r)) . . . )) = σC1 ∧ C2 ∧ ... ∧ Cn (r)
In SQL wordt de select-conditie meestal gespecifieerd in het where-gedeelte. Hieronder staat
een voorbeeld van een select-operatie en de bijhorende SQL-query.
σ(Dno = 4) ∧ (Salary > 25000) (employee)
SELECT *
FROM EMPLOYEE
WHERE Dno = 4 AND Salary > 25000
36
6.1.2
The PROJECT Operation
Als we een relatie als een tabel voorstellen, kiest de select-operatie enkele rijen (tupels) hieruit.
De project-operatie daarentegen selecteert bepaalde kolommen. Dus als we enkel ge¨ınteresseerd zijn in bepaalde attributen van een relatie, gebruiken we de project-operatie. Om bijvoorbeeld de voornamen en lonen van alle werknemers op te vragen, gebruiken we de volgende query.
π Fname, Salary (employee)
Hierbij is π dus het symbool voor project. De generieke vorm van een project-operatie heeft de
volgende vorm:
πX (R) = π<attributenlijst> (R)
De attributenlijst is de lijst van attributen die we willen opvragen van de relatie R, met komma’s
tussen de individuele attributen.
Als er attributen opgevraagd worden die geen key zijn, is de kans groot dat er duplicaten
optreden. De project-operatie verwijdert deze duplicaten en geeft dus een lijst met unieke
tupels terug. Moesten duplicaten niet verwijderd worden, zou het resultaat geen tupel zijn maar
een multiset of bag. In het formele model is dit niet toegelaten, in SQL wel.
De project-operatie is niet commutatief, er geldt dat πX (πY (r)) enkel gedefinieerd is als X ⊆ Y .
De project-operatie is dus idempotent, enkel de laatste (buitenste) projectie van opeenvolgende
projecties moet uitgevoerd worden. Dit is makkelijk in te zien met de volgende query’s, de volgende
query vraagt enkel de voornamen op van de werknemers.
π Fname (πBdate, Fname (employee))
De volgende query is ongeldig omdat “Bdate” niet voorkomt in de tupels van voornamen.
π Bdate, Fname (πFname (employee))
Hieronder staat een voorbeeld van een project-operatie en de bijhorende SQL-query.
π Bdate, Salary (employee)
SELECT DISTINCT Bdate, Salary
FROM EMPLOYEE
Merk op dat als we distinct uit de SQL-query weglaten, de duplicate tupels niet verwijderd worden
en we dus niet hetzelfde resultaat krijgen als in de formele relationele algebra.
6.1.3
Sequences of Operations and the RENAME Operation
In de praktijk willen we meestal resultaten van meerdere queries. Dit kan op 2 manieren gebeuren:
ofwel alle queries nesten ofwel gebruik maken van tussenresultaten en daar de opeenvolgende
queries op uitvoeren. In het tweede geval moeten we namen geven aan de tussenresultaten.
Om bijvoorbeeld de voornaam, achternaam en het salaris op te vragen van alle werknemers in
departement 5, kunnen we als volgt te werk gaan:
π Fname, Lname, Salary (σ Dno = 5 (employee))
Door met tussenresultaten te werken, kan men ook het volgende doen:
dep5 emps ← σ Dno = 5 (employee)
result ← π Fname, Lname, Salary (dep5 emps)
37
De tweede manier (met tussenresultaten) is beter leesbaar. Deze manier kunnen we ook gebruiken
om de attribuutnamen in het resultaat een andere naam te geven. Dit gaat als volgt.
temp ← σ Dno = 5 (employee)
R (FirstName, LastName, Salary) ← π Fname, Lname, Salary (temp)
We kunnen ook een formele rename-operatie invoeren, deze heeft de volgende generieke vorm.
ρ S(B1 ,...,Bn ) (R) = ρS (R) = ρ (B1 ,...,Bn ) (R)
Hierbij is R een relatie van graad n, S de nieuwe naam voor de relatie, Bi de nieuwe attribuutnamen
en ρ het symbool van de rename-operatie. In de generieke vorm hierboven hernoemen we in de
eerste term zowel de relatie als de attribuutnamen, in de tweede term enkel de relatie en in de derde
term enkel de attributen.
In SQL gebeurt de rename-operatie met de as-functie.
SELECT E.Fname AS FirstName, E.Lname AS LastName, E.Salary AS Salary
FROM EMPLOYEE AS E
WHERE E.Dno = 5
6.2
Relational Algebra Operations from Set Theory
6.2.1
The UNION, INTERSECTION, and MINUS Operations
De volgende groep van operaties uit de relationele algebra, zijn de standaard wiskundige verzamelingsoperatoren.
Om bijvoorbeeld de “Ssn”-nummers op te vragen van de werknemers die in departement 5
werken of de werknemers die baas zijn van een werknemer uit departement 5, kunnen we de union
(unie) als volgt gebruiken.
dep5 emps ← σ Dno = 5 (employee)
result1 ← π Ssn (dep5 emps)
result2(Ssn) ← π Super ssn (dep5 emps)
result ← result1 ∪ result2
result1 bevat de “Ssn”-nummers van alle werknemers uit departement 5, result2 bevat alle
“Ssn”-nummers van de bazen van werknemers uit departement 5. result bevat dan de unie van
beide resultaten (zonder duplicaten).
Naast union bestaan er ook intersection (doorsnede) en set difference (verschil), ook wel
minus of except genoemd. Dit zijn binaire operaties die enkel gebruikt worden op twee verzamelingen van hetzelfde type. Dit wordt ook wel union compatibility of type compatibility
genoemd. Twee relaties worden compatibel genoemd als ze dezelfde graad hebben en als de corresponderende attributen hetzelfde domein hebben.
We nemen de conventie aan dat de resultaatverzameling dezelfde attribuutnamen gebruikt als
de eerste relatie waarop de operatie toegepast wordt.
Het is makkelijk in te zien dat union en intersection commutatief en associatief zijn. set
difference is dat over het algemeen niet.
In SQL komen union, intersect en except overeen met de eerder beschreven operaties. Daarnaast bestaan er in SQL ook union all, intersect all en except all, deze verwijderen de
duplicaten niet.
38
6.2.2
The CARTESIAN PRODUCT (CROSS PRODUCT) Operation
Het Carthesisch product of kruisproduct (×) is ook een binaire operatie, maar de twee verzamelingen
moeten niet union compatible zijn, in tegenstelling tot de eerder besproken operaties.
Als we bijvoorbeeld A × B uitvoeren, wordt elke tupel uit A gecombineerd met elke tupel uit
B. Stel A bevat n elementen en B bevat m elementen, dan zal het resultaat van het kruisproduct
exact m · n tupels bevatten.
Formeler: een kruisproduct Q = R × S heeft als schema Q(A1 , . . . , An , B1 , . . . , Bm ) en bevat
elke combinatie van tupels uit R en S.
Voorbeeld: op de tabellen voornamen en achternamen voeren we de volgende operatie uit om
de tabel resultaat te bekomen.
resultaat ← voornamen × achternamen
VOORNAMEN
Voorn id Voorn
1
George
2
Albert
ACHTERNAMEN
Achtern id Achtern
1
Orwell
2
Hoffman
=⇒
Voorn id
1
1
2
2
RESULTAAT
Voorn Achtern id
George
1
George
2
Albert
1
Albert
2
Achtern
Orwell
Hoffman
Orwell
Hoffman
We zien meteen dat het resultaat op zich geen betekenis heeft. Over het algemeen is ze enkel nuttig
als we nadien alle ongeldige combinaties wegfilteren, dit doen we meestal door de keys te vergelijken.
echt resultaat ← σ Voorn id = Achtern id (resultaat)
ECHT RESULTAAT
Voorn id Voorn Achtern id Achtern
1
George
1
Orwell
2
Albert
2
Hoffman
Omdat het Carthesisch product zonder de select-operatie niet zo nuttig is (omdat er dan duplicaten bestaan), heeft men de join-operatie ontwikkeld, deze combineert direct de 2 operaties. In
de volgende sectie gaan we hier dieper op in.
In SQL noemt men het Carthesisch product cross join.
6.3
6.3.1
Binary Relational Operations: JOIN and DIVISION
The JOIN Operation
De join-operatie (symbool: ./) wordt gebruikt om gerelateerde tupels van 2 relaties samen te
voegen tot ‘grotere’ tupels. join is eigenlijk een uitvoering van het Carthesisch product, gevolgd
door een selectie. We zullen het nut aantonen door middel van een voorbeeld:
dept mgr ← department ./ Mgr ssn = Ssn employee
result ← π Dname, Lname, Fname (dept mgr)
In de eerste query worden de tabellen departement en employee gejoind met de conditie
Mgr ssn = Ssn. We krijgen dus in dept mgr een lijst van alle departementen met voor elk
departement ook de departementsmanager. Daarna volgt een rename-operatie.
Het verschil tussen het Carthesisch product (×) en de join-operatie (./) is dat bij de joinoperatie direct een conditie meegegeven kan worden.
39
Een generieke join-operatie heeft de volgende vorm (met selectiecriterium F en relaties R, S):
R ./F S = R ./<conditie> S = σF (R × S)
Stel R heeft n tupels en S heeft m tupels, dan zal de join tussen R en S als resultaat n + m tupels
hebben. Ook hier kunnen {∧, ∨, ¬} gebruikt worden om condities samen te voegen.
Een conditie is een theta-join als in F = C1 ∧ · · · ∧ Cn elke Ck van de vorm Ai θ Bj is. Hierbij
geldt dat θ ∈ {=, <, >, 6, >, 6=} en dat dom(Ai ) = dom(Bj ).
Tupels waarvan een join-attribuut NULL is, zullen niet worden opgenomen in het resultaat.
6.3.2
Variations of JOIN: The EQUIJOIN and NATURAL JOIN
De meest gebruikte join-condities zijn deze met enkel gelijkheidscondities Ck in F . Deze noemen
we een equijoin. In het resultaat van een equijoin zal er in elke tupel minstens 1 paar attributen
gelijke waarden hebben.
Als deze attributen die gelijk moeten zijn dezelfde naam hebben, kunnen we gebruik maken van
een natural join. Hierbij moet er geen join-conditie meegegeven worden, maar zal er gejoind
worden op attributen met dezelfde naam. Als de attributen waarop we willen joinen niet dezelfde
naam hebben, moet er eerst een rename-operatie uitgevoerd worden.
Een natural join is dus gelijk aan het uitvoeren van een equijoin waarna men de overtollige
attributen weglaat. Dus per voorwaarde Ai = Bj wordt enkel Ai of Bj behouden.
De generieke notatie van een natural join is als volgt:
R ∗F S
Als X en Y attribuutlijsten zijn van gelijke lengte, dan kan men de natural join ook vereenvoudigd noteren als R ∗X,Y S. De conditie is dan X1 = Y1 ∧ · · · ∧ Xk = Yk . Enkel de attributen in X
blijven behouden na de join.
Een andere vereenvoudigde notatie is R ∗ S waarbij de lijsten X en Y impliciet zijn: ze bevatten
alle attributen die dezelfde naam hebben in R en S.
Als we bijvoorbeeld elke project-tupel willen joinen met elke department-tupel die het project
controleert, kan dit met de volgende query:
proj dept ← project ∗ ρ (Dname, Dnum, Mgr ssn, Mgr start date) (department)
Je kan zien dat er een rename-operatie uitgevoerd wordt: “Dnumber” uit de department-relatie
wordt hernoemd naar “Dnum” zodat de attribuutnaam overeenkomt met die in project. Daarna
wordt er een natural join uitgevoerd.
Het attribuut “Dnum” wordt hier het join-attribuut voor de natural join genoemd, omdat
het het enige attribuut is met dezelfde naam in beide relaties. Als er in beide relaties geen attributen
voorkomen met dezelfde naam zal het resultaat van een natural join leeg zijn.
Bovenstaande query had ook in 2 stappen uitgevoerd kunnen worden.
dept ← ρ (Dname, Dnum, Mgr ssn, Mgr start date) (department)
proj dept ← project ∗ dept
De join-operatie combineert dus data uit 2 relaties zodat gerelateerde informatie in 1 tabel getoond
kan worden. Dit soort operaties noemt men ook inner joins.
join-operaties kunnen ook gebeuren tussen meer dan 2 relaties, bijvoorbeeld:
project ./ Dnum = Dnumber department ./ Mgr ssn = Ssn employee
40
6.3.3
A Complete Set of Relational Algebra Operations
Het is aangetoond dat de set van relationele algebra operaties {σ, π, ∪, ρ, −, ×} een complete set
is. Dit wil zegen dat elke andere operatie uit de relationele algebra geschreven kan worden als een
combinatie van elementen uit deze set.
Bijvoorbeeld, de intersection-operatie kan uitgedrukt worden met union en minus.
R ∩ S ≡ (R ∪ S) − R − S) ∪ (S − R)
Veel operaties uit de relationele algebra zijn dus niet strikt noodzakelijk maar zijn ingevoerd om
het ingeven van queries makkelijker te maken.
6.3.4
The DIVISION Operation
De division-operatie heeft als symbool ÷ en is zinvol voor een speciale vorm van queries.
Een voorbeeld hiervan is “geef de namen van de werknemers die meewerken aan alle projecten
waaraan John Smith werkt”. Om deze query met de division-operatie neer te schrijven, doen we
het volgende:
1. We vragen de lijst op van projectnummers waaraan John Smith werkt.
smith ← σ Fname = ‘John’ ∧ Lname = ‘Smith’ (employee)
smith pnos ← π Pno (works on ./ Essn = Ssn smith)
2. We selecteren alle werknemers met alle projecten waar ze aan werken uit works on.
ssn pnos ← π Essn, Pno (works on)
3. We passen de division-operatie toe op de 2 relaties die we net gemaakt hebben.
ssns(Ssn) ← ssn pnos ÷ smith pnos
result ← π Fname, Lname (ssns ∗ employee)
Over het algemeen wordt de division-operatie op twee relaties uitgevoerd: R(Z) ÷ S(X), waarbij
de attributen van R een subset zijn van de attributen van S, dus X ⊆ Z. Als Y de verzameling
attributen van R is die geen attributen zijn van S, dan geldt Y = Z − X en Z = X ∪ Y .
Het resultaat van division is een relatie T (Y ) die het tupel t bevat als de tupels tR in R
voorkomen met tR [Y ] = t en met tR [X] = tS voor elke tupel tS in S.
Simpeler uitgelegd: voor elke tupel t die in het resultaat van division voorkomt, moet elke
waarde in t uit R in combinatie voorkomen met elke tupel in S.
Een voorbeeld om het duidelijk te maken:
PROJECT AF
Student Opdracht
Fred
Database1
Fred
Database2
Fred
Compiler1
Eugene Database1
Eugene Compiler1
Sarah Database1
Sarah Database2
÷
PROJECT
Opdracht
Database1
Database2
41
−→
RESULTAAT
Student
Fred
Sarah
Als we project af ÷ project uitvoeren, behoren enkel de tupels tot het resultaat die voldoen
aan de volgende voorwaarde: de juiste tupels komen voor in project af in combinatie met elke
tupel in project. Dus in het resultaat zullen enkel studenten opgenomen worden die voorkomen
met zowel opdracht “Database1” als “Database2”. Dit zijn Fred en Sarah.
Eugene wordt niet opgenomen omdat hij enkel voorkomt met Database1 en niet Database2.
De division-operatie kan geschreven worden als een combinatie van de operaties {π, ×, −}.
T1 ← πY (R)
T2 ← πY (S × T1 ) − R
T ← T1 − T2
De division-operatie is ingevoerd om met queries te kunnen werken waarin een universele kwantor ∀ voorkomt.
6.3.5
Notation for Query Trees
Hier beschrijven we de interne voorstelling van queries. Deze voorstelling noemen we een query
tree. Deze bevat de relationele algebra operaties die uitgevoerd worden en wordt soms als datastructuur gebruikt om intern queries voor te stellen in een RDBMS.
Een query tree bevat de input-relaties als bladeren van de boom en bevat de operaties als interne
knopen. Een query tree begint onderaan uit te voeren en voert telkens een knoop uit wanneer
zijn kind-knopen uitgevoerd zijn, de uitvoer stopt als de wortel uitgevoerd is. Telkens een knoop
uitgevoerd wordt, wordt deze vervangen door zijn resultaat.
Bijvoorbeeld: “Voor elk project met als locatie ‘Stafford’, geef de projectnumers, het departementsnummer dat het project controleert en de departemensmanager zijn achternaam, adres en
geboortedatum.” Dit stellen we voor met de volgende query:
raw result ← σ Plocation = ‘Stafford’ (project) ./ Dnum = Dnumber (department)
result ← π Pnumber, Dnum, Lname, Address, Bdate raw result ./ Mgr ssn = Ssn (employee)
De query tree die hiermee overeenkomt is figuur 6.9 op pagina 161. De bladeren P , D en E stellen
de 3 relaties project, department en employee voor. De relationele algebra operaties worden
voorgesteld in de interne knopen. Knoop 1 moet uitgevoerd worden v´o´or knoop 2 omdat deze
resultaten van knoop 1 gebruikt.
6.4
Additional Relational Operations
Sommige queries die vaak nodig zijn in commerci¨ele applicaties, kunnen niet voorgesteld worden met
de originele relationele algebra operaties. In deze sectie zullen we bijkomende operaties defini¨eren.
6.4.1
Generalized Projection
De generalized projection operatie breidt de ‘gewone’ projectie-operatie uit door toe te laten dat
er functies van attributen gebruikt worden. De generieke vorm is:
πF1 ,F2 ,...,Fn (R)
Hier zijn F1 , F2 , . . . , Fn functies op de attributen uit de relatie R.
42
Bijvoorbeeld, we hebben de relatie employee(Ssn, Salary, Deduction, Years service) en we willen
de volgende informatie:
Net Salary = Salary − Deduction
Bonus = 2000 × Years service
Tax = 0.25 × Salary
Dit kunnen we voorstellen met de volgende gegeneraliseerde projectie:
report ← ρ (Ssn, Net salary, Bonus, Tax) π Ssn, Salary − Deduction, 2000 × Years service, 0.25 × Salary (employee)
6.4.2
Aggregate Functions and Grouping
Ook queries die nood hebben aan aggregaatfuncties kunnen niet voorgesteld worden met gewone
relationele algebra operaties, bijvoorbeeld het opvragen van het gemiddelde loon van de werknemers.
Het symbool voor de aggregaatoperatie is F (een rare F). Een generieke aggregaatoperatie heeft
de volgende vorm.
<groeperingsattributen> F <functielijst> (R)
De groeperingsattributen is een lijst attributen uit de relatie R, de functielijst bestaat uit paren
(<functie><attribuut>). Hierin stelt <functie> een attribuut uit R voor en <attribuut> is 1 van
de volgende functies: sum, average, maximum, minimum, count.
Om bijvoorbeeld elk departementsnummer, het aantal werknemers in dat departement en hun
gemiddeld loon op te vragen, kunnen we de volgende query gebruiken.
ρ R(Dno, No of employees, Average sal) Dno F count Ssn, average Salary (employee)
In het bovenstaande voorbeeld hebben we direct de resultaten van de aggregaatfuncties count en
average hernoemd, als we dit niet doen krijgen ze de naam “<functie> <attribuut>”. Als we
geen groeperingsattribuut specifi¨eren, worden de functies toegepast op alle tupels in de relatie. Het
resultaat hiervan zal altijd bestaan uit 1 tupel.
De volgende tabel is het resultaat van de voorbeeldquery.
Dno
5
4
1
No of employees
4
3
1
Average sal
33250
31000
55000
De volgende tabel wordt bekomen als we geen rename-operatie uitvoeren op het resultaat
Dno
5
4
1
Count Ssn
4
3
1
Average Salary
33250
31000
55000
De onderstaande tabel krijgen we als we geen groeperingsattribuut meegeven.
No of employees
8
43
Average sal
35125
6.4.3
Recursive Closure Operations
Een ander soort van operaties die niet voorgesteld kunnen worden met gewone relationele algebra
zijn de recursive closure-operaties (recursieve sluiting). Deze operaties worden toegepast op een
recursieve relatie tussen tupels van hetzelfde type.
Bijvoorbeeld: we willen de baas van een werknemer op elk niveau opvragen, dus de baas e0 van
werknemer e, de baas e00 van werknemer e0 enzovoort. Met gewone relationele algebra is het mogelijk
om de bazen van elkaar op te vragen tot op een specifiek niveau door de tabellen een aantal keer te
joinen. Het is echter niet mogelijk om alle bazen op te vragen. Dit type operaties wordt hier niet
beschreven.
6.4.4
OUTER JOIN Operations
Hier zullen we uitbreidingen van de join-operatie bespreken die nodig zijn om bepaalde queries voor
te kunnen stellen. In de voorgaande beschrijvingen van join-operaties moest er telkens voldaan
zijn aan een bepaalde join-conditie. Dit noemen we inner joins, bij deze joins vallen altijd tupels
weg uit het resultaat, namelijk deze die niet voldoen aan de join-conditie.
Bij outer joins worden alle tupels in beide relaties behouden. Deze operaties zijn soms nodig als
toch blijkt dat de hele tabel nodig is, ook als niet alle tupels overeenkomen.
Bijvoorbeeld: we willen een lijst opvragen van alle werknemers en per werknemer de naam van
het departement dat die leidt. Als een werknemer geen departement leidt, wordt de departmenttupel voor die werknemer NULL in het resultaat. Dit is mogelijk als we een left outer joinoperatie gebruiken.
temp ← employee ./ Ssn = Mgr ssn (department)
result ← π Fname, Minit, Lname, Dname (temp)
Deze left outer join-operatie behoudt elke tupel van de linkse relatie in R ./ S. Als er in S
geen tupel voorkomt die overeenkomt met een tupel uit R, wordt deze in het resultaat aangevuld
met NULL-waarden.
Gelijkaardig hebben we ook de right outer join-operatie (./ ) die elke tupel in de rechtse
relatie (dus S) behoudt. Er bestaat ook een full outer join-operatie ( ./ ) die zowel alle tupels
in de eerste als in de tweede relatie behoudt.
6.4.5
The OUTER UNION Operation
De outer union-operatie (∪+ ) is ontwikkeld om de unie te nemen van tupels uit 2 relaties die
overeenkomstige attributen hebben maar niet union-compatible zijn.
Deze operatie neemt de union van tupels in 2 relaties R(X, Y ) en S(X, Z) die gedeeltelijk
compatibel zijn. Dit betekent dat slechts enkele attributen (bijvoorbeeld X) union-compatible
zijn. De union-compatible attributen komen slechts eenmaal voor in het resultaat. De attributen
die niet union-compatible zijn, worden ook behouden in het resultaat T (X, Y, Z).
De outer union-operatie is dus hetzelfde als de full outer join-operatie op de unioncompatible attributen.
Twee tupels t1 in R en t2 in S matchen als t1 [X] = t2 [X]. Deze zullen worden gecombineerd tot
een enkele tupel in t. Tupels in R en S die geen overeenkomstige tupel hebben in de andere relatie,
worden aangevuld met NULL-waarden.
44
Voorbeeld: we hebben 2 relaties met redelijk overeenkomstige schema’s:
student (Name, Ssn, Department, Advisor)
instructor (Name, Ssn, Department, Rank)
Als we de outer union-operatie toepassen op deze 2 relaties krijgen we als resultaat:
student or instructor (Name, Ssn, Department, Advisor, Rank)
Alle tupels uit beide relaties zullen voorkomen in het resultaat, tupels met dezelfde (Name, Ssn,
Department)-combinatie zullen slechts 1 keer voorkomen. Tupels uit de student-relatie zullen
onder het attribuut “Rank” NULL-waarden in het resultaat hebben. Bij tupels uit instructor
zal dit het geval zijn onder “Advisor”. Merk op dat dezelfde persoon nog altijd tweemaal kan
voorkomen in het resultaat als hij ingeschreven is als student ´en als instructor.
Er bestaat ook een inner union-operatie: Q = R ∪− S met Attr(Q) = Attr(R) ∩ Attr(S).
Analoog is outer union gedefinieerd als: Q = R ∪+ S met Attr(Q) = Attr(R) ∪ Attr(S).
6.6
The Tuple Relational Calculus
In deze en de volgende sectie introduceren we een andere, formele querytaal voor het relationele
model: de relational calculus. Er zijn 2 versies: tuple relational calculus (6.6) en domain
relational calculus (6.7). In beide gevallen gaat het om declaratieve expressies, we zeggen dus
niet hoe we aan het resultaat geraken maar wat we willen. Dit verschilt met relationele algebra
waarin een opeenvolging van queries wordt gegeven in een bepaalde volgorde (dus procedural ).
Men heeft aangetoond dat men in de relationele algebra dezelfde queries kan uitvoeren als in de
relationele calculus en vice versa. We zeggen dus dat hun expressive power identiek is.
We noemen een bepaalde querytaal L relationally complete als we in L elke query kunnen
beschrijven die in relationele calculus te schrijven valt.
6.6.1
Tuple Variables and Range Relations
Tupelcalculus is gebaseerd op het specifieren van tupelvariabelen, een tupelvariabele kan als
waarde elke individuele tupel aannemen uit een relatie. Een simpele query in tupelcalculus heeft
de volgende vorm:
t cond(t)
Hierbij is t de tupelvariabele en cond(t) is een Booleaanse expressie waarin t voorkomt. Het
resultaat van zo’n query is de verzameling van alle tupels t waarvoor cond(t) waar is.
Bijvoorbeeld: we vragen alle werknemers op die een loon hebben van meer dan $50000:
t employee(t) AND t.Salary > 50000
De conditie employee(t) zegt dat t moet behoren tot de werknemers. Elke werknemer waarvoor
(t.Salary > 50000) naar true evalueert, zal worden opgenomen in het resultaat.
De bovenstaande query geeft alle attribuutwaarden terug van werknemers die voldoen aan de
conditie. We kunnen ook maar enkele attributen selecteren:
t.Fname, t.Lname employee(t) AND t.Salary > 50000
Voor een query in tupelcalculus hebben we dus de volgende informatie nodig:
• Voor elke tupel t moeten we een range relation R specifi¨eren, dit is een conditie van de vorm
R(t). Als we dit niet doen, zal t waarden aannemen van tupels uit het hele universum.
In het voorbeeld hierboven: employee(t).
45
• Een conditie om enkel bepaalde combinaties van tupels te selecteren.
In het voorbeeld hierboven: t.Salary > 50000.
• De set van attributen die we willen opvragen.
In het voorbeeld hierboven: t.Fname, t.Lname.
6.6.2
Expressions and Formulas in Tuple Relational Calculus
Een generieke expressie in tupelcalculus heeft de volgende vorm:
t1 .Aj , t2 .Ak , . . . , tn .Am cond(t1 , t2 , . . . , tn , tn+1 , tn+2 , . . . , tn+m )
Hierbij zijn t1 , t2 , . . . , tn , tn+1 , . . . , tn+m tupelvariabelen en elke Ai is een attribuut van de relatie
ti . cond is een conditie opgebouwd uit calculus atoms die 1 van de volgende vormen hebben:
• R(ti ) met R de naam van een relatie. Dit atoom duidt de range van ti aan als de relatie met
naam R.
• (ti .A op tj .B) met op een vergelijkingsoperator uit de set {= , < , > , 6 , > , 6= , . . . }.
• (ti .A op c) met c een constante waarde.
Een formule is opgebouwd uit meerdere atomen, gecombineerd met de logische operatoren AND,
OR en NOT.
6.6.3
The Existential and Universal Quantifiers
We voegen nu ook kwantoren toe: de universele kwantor (∀) en de existenti¨
ele kwantor (∃).
Dit zou gekend moeten zijn, indien niet kan je best sectie 6.6.3 op pagina 173-174 lezen.
6.6.4
Sample Queries in Tuple Relational Calculus
We geven 1 voorbeeldquery in tupelcalculus waarin een kwantor gebruikt wordt. Voor andere
voorbeelden bekijk je best sectie 6.6.4 op pagina 174-175.
van alle werknemers die aan ‘Research’ werken.
nWe willen de naam en het adres
t.Fname, t.Lname, t.Address employee(t) AND
o
(∃d) department(d) AND d.Dname = ‘Research’ AND d.Dnumber = t.Dno
6.6.5
Notation for Query Graphs
In deze sectie stellen we een grafische manier voor om queries in relationele calculus voor te stellen.
Deze queries gebruiken geen kwantoren: select-project-join queries. De grafische weergave van
deze queries noemen we een query graph.
Relaties worden voorgesteld met relation nodes die aangeduid worden met enkele cirkels.
Constanten noemen we constant nodes en hebben een dubbele cirkel. Selectie- en join-condities
worden in de grafe voorgesteld als verbindingen (edges) en de attributen die we opvragen zijn
aangeduid in vierkante haakjes boven elke relatie.
Zo’n query graph duidt niet de volgorde aan waarin deze uitgevoerd moeten worden en is dus
een neutralere vorm dan de query tree om een query grafisch weer te geven.
Voor query-optimalisatie wordt meestal een query tree gebruikt omdat het handiger is om te
weten in welke volgorde dingen uitgevoerd moeten worden.
Een voorbeeld van een query graph vind je op pagina 175.
46
6.6.6
Transforming the Universal and Existential Quantifiers
Hier worden de logische regels beschreven om existenti¨ele en universele kwantoren te transformeren
naar elkaar door gebruik te maken van AND, OR en NOT. Als je deze regels niet meer kent, lees
dan even sectie 6.6.6 op pagina 176.
6.6.7
Using the Universal Quantifiers in Queries
Als we universele kwantoren willen gebruiken in een uitdrukking, moeten we op enkele dingen letten.
Neem als voorbeeld dat we alle werknemers uit departement 5 willen selecteren, het is logisch
dat we hierbij een universele kwantor kunnen gebruiken. Om een universele kwantor naar true te
laten evalueren, moet de formule waar zijn voor elk element uit het universum. Maar in onze query
willen we enkel de werknemers uit departement 5.
We kunnen dit oplossen door alle tupels waarin we niet ge¨ınteresseerd zijn, automatisch naar
true te laten evalueren. Dit doen we door de conditie de vorm NOT R(x) OR conditie(x) te
geven als we enkel ge¨ınteresseerd zijn in tupels uit de relatie R. Elke tupel die niet in R voorkomt
zal dus naar true evalueren.
In principe maken we hier een implicatie (∀x) R(x) ⇒ conditie(x) die we
omvormen tot een
disjunctie. In het voorbeeld wordt dit (∀x) department(x) ⇒ x.Dnum = 5 . Deze formule zegt:
“als x een departement is, dan moet het nummer 5 zijn”. Als we deze conditie in tupelcalculus
noteren, krijgen we (∀x) NOT department(x) OR x.Dnum = 5 .
6.6.8
Safe Expressions
We noemen uitdrukkingen die gegarandeerd een eindig aantal tupels teruggeven safe, in het andere
geval unsafe. De volgende query is unsafe omdat er oneindig veel tupels in het universum bestaan
die geen werknemer zijn.
t NOT employee(t)
We kunnen het concept van een safe uitdrukking preciezer defini¨eren aan de hand van het concept
van het domein van een uitdrukking in tupelcalculus. Het domein van het voorgaande voorbeeld is
de set van alle attribuutwaarden die voorkomen in een tupel van de employee-relatie.
Een uitdrukking noemen we veilig als alle waarden in het resultaat uit dit domein komen. Ons
voorbeeld is dus niet veilig omdat er ook tupels in het restultaat voorkomen die niet voorkomen in
employee (eigenlijk komt geen enkele tupel in het resultaat uit employee).
47
6.7
The Domain Relational Calculus
Naast tuple relational calculus hebben we ook domain relational calulus of domeincalculus.
Het verschil tussen domeincalculus en tupel calculus ligt in het type van variabelen die we
gebruiken in de formules. In de domeincalculus laten we de variabelen waarden aannemen uit de
domeinen van attributen in plaats van over tupels.
De generieke vorm van een domain calculus query is de volgende.
x1 , x2 , . . . , xn cond(x1 , x2 , . . . , xn , xn+1 , xn+2 , . . . , xn+m )
Hierbij zijn (x1 , x2 , . . . , xn , xn+1 , xn+2 , . . . , xn+m ) de domeinvariabelen die rangen over domeinen
van attributen, cond is een conditie. Een formule is ook hier opgebouwd uit atomen (die waar of
vals kunnen zijn), hier hebben ze echter een beetje een andere vorm dan in tupel calculus:
• R(x1 , x2 , . . . , xj ) met R de naam van een relatie van graad j. Om alles wat leesbaarder te
maken laten we kommas weg: R(x1 x2 x3 )
• (xi op xj ) met op een vergelijkingsoperator uit de set {= , < , > , 6 , > , 6= , . . . }.
• (xi op c) met c een constante.
Om bijvoorbeeld de geboortedatum en het adres van de werknemer John B. Smith op te vragen,
gebruiken we de volgende uitdrukking
n
u, v (∃q)(∃r)(∃s)(∃t)(∃w)(∃x)(∃y)(∃z)
o
employee(qrstuvwxyz) AND q = ‘John’ AND r = ‘B’ AND s = ‘Smith’
Hiervoor hebben we dus 10 variabelen nodig, 1 om over elk domein van attributen te gaan. Veel
van de gespecifieerde variabelen worden echter niet gebruikt. Bij domeincalculus is het dus nodig
om de volgorde te kennen waarin attributen opgeslagen zijn, vooraleer we ze kunnen opvragen.
Een andere (iets kortere) manier om de voorgaande query neer te schrijven, is het gebruiken van
constanten in de uitdrukking.
u, v employee(‘John’, ‘B’, ‘Smith’, t, u, v, w, x, y, z)
Om de naam en het adres van alle werknemers op te vragen die in het ‘Research’-departement
werken, gebruiken we de volgende uitdrukking.
n
q, s, v (∃z)(∃l)(∃m) employee(qrstuvwxyz) AND
o
department(lmno) AND l = ‘Research’ AND m = z
48
Hoofdstuk 7
Conceptual Data Modeling Using
Entities and Relationships
7.1
Using High-Level Conceptual Data Models for Database Design
1. Requirements collection and analysis. Data- en functievereisten onderzoeken voor gebruikers.
2. Conceptual design. Cre¨eren van het hoogniveau, conceptuele schema van de database.
3. Logical Design. Het maken van een database schema in de vorm van een implementation
data model op basis van het hoogniveau data model. Ook wel data model mapping genoemd.
4. Physical Design. Het daadwerkelijk opzetten van de interne opslagstructuren, bestandsorganisatie, indexen, toeganspaden, ... Hieronder valt ook het ontwikkelen van de applicatieprogramma’s om de databasetransacties te implementeren.
Zie ook figuur 7.1 op pagina 196 voor een diagram van deze fases.
7.3
7.3.1
Entity Types, Entity Sets, Attributes, and Keys
Entities and Attributes
Een entiteit is een ding in de echte wereld met een onafhankelijk bestaan, zij het fysiek of conceptueel. Elke entiteit heeft attributen, eigenschappen die de entiteit omschrijven. Deze attributen
zijn een groot stuk van de data die wordt opgeslagen.
Een attribuut kan verder opgesplitst worden in deelattributen, bijvoorbeeld: het attribuut
“Adres” kan bijvoorbeeld omschreven worden door de deelattributen “Straat”, “Huisnummer”,
“Postcode” en “Gemeente”. Dit noemt men een composite attribute. In het andere geval spreekt
men over een simple attribute.
Een attribuut kan single-valued of multivalued zijn. In het laatste geval is het mogelijk dat
een entiteit voor ´e´en attribuut meerdere waarden heeft (bv. een persoon heeft geen, ´e´en of meerdere
diploma’s).
Een attribuut kan stored zijn, of kan derived (afgeleid) zijn uit andere attributen (bv. de
“Leeftijd” kan afgeleid worden uit de “Geboortedatum”).
Een attribuut kan de waarde NULL hebben, wat wil zeggen dat het attribuut niet in gebruik is
voor een bepaalde entiteit of dat de waarde van het attribuut onbekend is.
49
Bij een combinatie van twee of meer van bovenstaande mogelijkheden spreken we van een complex attribute.
7.3.2
Entity Types, Entity Sets, Keys, and Value Sets
Een entity type is een verzameling van gelijksoortige entiteiten, in een database zullen die meestal
in een tabel per type worden verzameld. Een entity set is een momentopname van zo’n verzameling
in de tijd.
Een key attribute van een entiteitstype is een attribuut dat uniek is voor elke entiteit uit dat
type (bv. het rijksregisternummer van een persoon) en deze entiteit dus onderscheidt.
Een value set is een domein van waarden. Elk attribuut heeft een value set waar het zich aan
houdt, het kan dus enkel waarden uit dat opgelegd domein aannemen.
7.4
7.4.1
Relationship Types, Relationship Sets, Roles & Structural Constraints
Relationship Types, Sets and Instances
Een relatietype tussen n entiteitstypes bepaalt een set van associaties (verbanden) tussen de
entiteiten van deze entiteitstypes. Bijvoorbeeld: bij de twee entiteiten employee en department
kan een relatietype works for bestaan, hierbij werkt een employee dan bij een departement.
7.4.2
Relationship Degree, Role Names, and Recursive Relationships
De relatiegraad van een relatie is het aantal entiteitstypes die deel uitmaken van die relatie. In
het bovenstaande voorbeeld is works for dus van graad 2.
Recursieve relaties zijn relaties waarbij een entiteitstype meerdere keren voorkomt, telkens
in een andere rol. Bijvoorbeeld, supervision bepaalt een relatie tussen 2 employees.
7.4.3
Constraints on Binary Relationship Types
Er zijn 2 structural constraints van een relatietype:
• De kardinaliteitsratio van een binaire relatie bepaalt het maximum aantal relatie-instances
waaraan een entiteit kan deelnemen. Bijvoorbeeld, de kardinaliteitsratio van department
t.o.v. employee is 1:N , wat wil zeggen dat een departement N employees kan hebben, maar
een employee kan maar bij 1 departement werken.
• De deelnamebeperking (participation constraint of minimale kardinaliteit constraint)
bepaalt het minimum aantal relatie-instances waaraan een entiteit kan deelnemen. Elke zijde
van een relatie heeft ofwel een totale participatie, ofwel een parti¨ele participatie.
– Totale participatie: elke entiteit van een entiteitstype moet gerelateerd zijn aan een
entiteit van een ander entiteitstype. Bijvoorbeeld: elke employee moet werken voor een
departement, de participatie van employee in de works for-relatie is dus totaal.
– Parti¨
ele participatie: een deel entiteiten van een entiteitstype moet gerelateerd zijn
aan een ander entiteitstype. Bijvoorbeeld: slechts enkele employees beheren een departement, de participatie van employee in de manages-relatie is dus partieel.
50
7.4.4
Attributes of Relationship Types
Net zoals een entiteit omschreven wordt door attributen, kan ook een relatie attributen bevatten.
Bijvoorbeeld, de relatie works for kan het attribuut “Start date” hebben om aan te geven hoelang
iemand al voor een departement werkt.
7.5
Weak Entity Types
Zwakke entiteitstypes zijn identiek aan normale entiteitstypes met uitzondering dat ze geen key
attribute hebben. Ze hangen altijd af van een relatie omdat die relatie hun betekenis geeft. De
entiteit die een zwakke entiteit identificeert, is de eigenaar van de zwakke entiteit. Er is steeds een
totale participatie in de identificerende relatie.
Bijvoorbeeld, een dependent van een employee heeft geen key attribute maar elke dependent verwijst maar naar 1 bestaande employee.
Een zwak entiteitstype heeft meestal een partial key (discriminator), als er dan meerdere
zwakke entiteiten van eenzelfde eigenaar afhankelijk zijn, kan er gemakkelijk een onderscheid gemaakt worden.
7.7
7.7.1
ER Diagrams, Naming Conventions, and Design Issues
Summary of Notation for ER Diagrams
De notaties van de structuren in ER-diagrammen die hier overlopen zijn, staan op pagina 217.
7.7.2
Proper Naming of Schema Constructs
Voor entiteitstypes gebruiken we namen in het enkelvoud. Bij het opstellen van een database uit
een tekst geldt dat de zelfstandige naamwoorden meestal voor entiteitstypes zijn en de werkwoorden
voor relatietypes.
Entiteitstypes en relatietypes schrijven we volledig in hoofdletters. Attributen beginnen met een
hoofdletter. De namen van rollen zijn volledig in kleine letters.
7.7.3
Design Choices for ER Conceptual Design
Het gebeurt vaak bij het ontwerpen van de database dat een concept eerst als attribuut wordt
toegekend aan 1 entiteitstype, maar dat het uiteindelijk een relatietype wordt omdat het naar een
ander entiteitstype verwijst.
Het kan ook voorkomen dat een attribuut dat bij verschillende entiteitstypes aanwezig is, wordt
vervangen door een onafhankelijk entiteitstype. Het omgekeerde kan ook.
7.7.4
Alternative Notations for ER Diagrams
In plaats van het noteren van structurele constraints m.b.v. de kardinaliteitsratio en participatiebeperkingen (enkele of dubbele lijn), kan je ze ook noteren in de vorm (min,max). Deze waarden geven
dan het minimum en maximum aantal relatie-instances weer waaraan een entiteit moet verbonden
zijn. Als min gelijk is aan 0, is er sprake van parti¨ele participatie, anders totale participatie.
Zie figuur 7.15 op pagina 220 voor een voorbeeld hiervan.
51
7.8
7.8.1
Relationship Types of Degree Higher than Two
Choosing between Binary and Ternary (or Higher-Degree) Relationships
Het is uiteraard mogelijk om relaties te hebben met een graad groter dan 2. Ternaire relaties of
relaties van nog hogere graad komen weliswaar niet vaak voor, omdat het in theorie mogelijk is om
zo’n relatie op te splitsen in relaties van lagere graad. Dan verkrijgen we:
• maak 3 binaire relaties tussen de entiteitstypes van de ternaire relatie.
• maak van de ternaire relatie een zwak entiteitstype, dan zullen alle andere entiteitstypes van
de ternaire relatie een nieuwe, binaire relatie krijgen met het nieuwe, zwakke entiteitstype.
Afhankelijk van de situatie hoeft dit geen zwak entiteitstype te zijn, als er een unieke key kan
worden gevonden die elke entiteit van dit type kan identificeren.
7.8.2
Constraints on Ternary (or Higher-Degree) Relationships
Voor relatietypes van een hogere graad zijn er twee notaties: kardinaliteitsratio of min-max. Elk
heeft zijn eigen constraints. Bij de kardinaliteitsratio gebruiken we M en N om “een aantal”
deelnemers aan de relatie voor te stellen. Bij min-max geven het minimum en maximum aan
hoeveel entiteiten van een entiteitstype mogen deelnemen aan de relatie.
7.9
Subclasses, Superclasses, and Inheritance
Al het voorgaande viel onder het ER model. Dit schema breiden we uit tot EER, ofwel Enhanced
ER. Deze uitbreiding omvat subklassen, superklassen, alsook de daarmee gepaard gaande specialisatie en generalisatie. Ook voeren we overerving in voor attributen en relaties.
Op pagina 225 staat een voorbeeld van hoe dit in een schema genoteerd kan worden.
7.10
Specialization and Generalization in EER
7.10.1
Specialization
Specialisatie is het proces van het aanmaken van subklassen voor een entiteitstype. Het entiteitstype waarvoor subklassen worden gecre¨eerd is dan de superklasse van deze nieuwe subklassen.
Subklassen worden gemaakt om specifiekere attributen te kunnen toekennen aan een stuk van het
superklasse-entiteitstype. Deze worden ook wel lokale attributen genoemd.
Een entiteitstype kan meerdere specialisaties hebben, elk met 1 of meerdere subklassen.
7.10.2
Generalization
Generalisatie is in principe het omgekeerde proces: je groepeert enkele entiteitstypes door enkele
gemeenschappelijke attributen toe te kennen aan een nieuwe superklasse van deze entiteitstypes.
52
7.11
Constraints and Characteristics of Specialization and
Generalization Hierarchies
7.11.1
Constraints on Specialization and Generalization
Bij sommige specialisaties is het mogelijk om precies vast te leggen welke entiteiten in een subklasse terecht moeten komen. Zo’n subklassen heten dan predikaatgedefinieerde subklassen (of
predikaatgedefinieerd). De conditie die dit beslist is het bepalende predikaat.
Als alle subklassen in een specialisatie hun conditie op hetzelfde superklasse-attribuut hebben,
dan heet deze specialisatie een attribuutgedefinieerde specialisatie. Het attribuut heet dan het
bepalende attribuut.
Als de specialisatie bepaald is door andere kenmerken, spreken we van een gebruikersgedefinieerde subklasse.
De constraint disjointness (d) bepaalt dat een entiteit deel kan uitmaken van maximaal 1 subklasse
van een bepaalde specialisatie. Als de entiteiten van een specialisatie niet disjunct moeten zijn,
spreekt men van overlapping (o).
De constraint volledigheid kan totaal of partieel zijn. Bij totale specialisatie moet elke
entiteit van een superklasse ook deel moet uitmaken van minstens ´e´en subklasse ervan, dit wordt
genoteerd met een dubbele lijn. Bij parti¨
ele specialisatie moet dit niet (enkele lijn).
Deze 2 soorten constraints zijn onafhankelijk van elkaar.
7.11.2
Specialization and Generalization Hierarchies and Lattices
Subklassen kunnen nog verder onderverdeeld worden in meerdere subklassen. Hierbij moet een
onderscheid gemaakt worden tussen:
• Een specialisatie-hi¨
erarchie: een subklasse kan maar van 1 superklasse afhangen.
• Een specialisatie-tralie: een subklasse kan van meer dan 1 superklasse afhangen. Men
spreekt ook van een gedeelde subklasse.
Een subklasse erft de attributen van alle directe en indirecte superklassen.
Er wordt ook gesproken van generalisatie-hi¨erarchie en generalisatie-tralie. Deze zijn analoog aan
de specialisatie-varianten.
7.11.3
Utilizing Specialization and Generalization in Refining Conceptual Schemas
Bij het ontwikkelen van een database schema volgens het top-down principe zal er standaard
vertrokken worden vanuit een aantal klassen voor een aantal basis-identiteitstypes. Deze klassen
zullen al naargelang het doel van de database gespecialiseerd worden. Het kan gebeuren dat je merkt
dat een subklasse eigenlijk van meer dan ´e´en superklasse moet afhangen, wat een tralie cre¨eert.
Een tweede manier is het bottom-up principe. Dan begin je met zo specifiek mogelijke klassen te
maken, die je vervolgens naargelang hun doel generaliseert naar superklassen.
53
7.12
Modeling of UNION Types Using Categories in EER
Soms is het nodig om een entiteitstype in een relatie te kunnen voorstellen met meerder superklassen.
Die worden dan gegroepeerd in een unie (u), een subklasse van zo’n unie heet een categorie. Een
entiteit in de subklasse van de categorie behoort dan tot 1 superklasse (uit de unie van superklassen).
Een totale categorie houdt de unie van alle entiteiten in de superklassen bij (dubbele lijn).
Een parti¨
ele categorie houdt een deelverzameling van deze unie bij (enkele lijn).
Vergelijk met een gemeenschappelijke subklasse:
• Een gemeenschappelijke subklasse is een deelverzameling van een doorsnede van superklassen.
• Een entiteit in de subklasse behoort tot elke superklasse.
• Alle attributen van de superklassen worden overge¨erfd naar de subklassen.
7.13
A Sample UNIVERSITY EER Schema, Design Choices, and Formal Definitions
7.13.1
The UNIVERSITY Database Example
Lees het voorbeeld met nogal grote tekening in het boek op pagina’s 239 - 241.
7.13.2
Design Choices for Specialization/Generalization
Er zijn een aantal guidelines die je kan volgen bij het opmaken van een database schema:
• Maak enkel subklassen aan als het van belang is voor de database, anders wordt het schema
onnodig ingewikkeld.
• Subklassen met weinig lokale attributen en geen specifieke relaties kunnen best in hun superklasse gestoken worden. De lokale attributen zet je dan op waarde NULL voor entiteiten die
geen deel uitmaken van de “subklasse”.
Dit kan ook gedaan worden als alle subklassen weinig lokale attributen hebben.
• Unies en categorie¨en moeten worden vermeden tenzij het niet anders kan.
• Het kiezen voor disjunctie/overlapping en totale/parti¨ele constraints hangt af van het doel
van de database. Standaard kiest men voor overlapping en de parti¨ele contraint.
54
7.14
Data Abstraction, Knowledge Representation, & Ontology Concepts
Hier worden 4 abstractieconcepten besproken die worden gebruikt in EER modellen en knowledgerepresentation schema’s. Deze laatste zijn ook een soort database-modellen, maar waarbij wordt
uitgegaan van het goed representeren van reeds gegeven data.
7.14.1
Classification and Instantiation
Classificatie is het onderverdelen van objecten en entiteiten in objectklassen en entiteitstypes, ook
wel het identificeren genoemd.
Instantiatie is net het omgekeerde, namelijk het in het leven roepen van objecten en entiteiten
op basis van reeds gemaakte objectklassen en entiteitstypes.
7.14.2
Identification
Bij identificatie zijn klassen en objecten uniek identificeerbaar door een zogenaamde identifier.
Identificatie is nodig op twee niveau’s: om een onderscheid te maken tussen objecten en klassen, en
om objecten te kunnen identificeren en linken aan hun betekenis in de echte wereld.
7.14.3
Specialization and Generalization
Specialisatie betekent hier het verder onderverdelen van klassen van objecten in meer gespecialiseerde subklassen. Generalisatie is weer net het omgekeerde.
7.14.4
Aggregation and Association
Een aggregatie is een abstract concept om samengestelde objecten te maken uit een aantal componentobjecten. Dit kan bijvoorbeeld zijn: het combineren van attributen uit een aantal objecten
tot 1 aggregaatobject. De objecten moeten weliswaar reeds een zekere afhankelijkheid ten op zichte
van mekaar hebben, bijvoorbeeld van hetzelfde entiteitstype afkomstig zijn.
Een associatie wordt gebruikt om onafhankelijke objecten met mekaar te associ¨eren. Dit wordt
in EER voorgesteld met een relatie.
7.14.5
Ontologies and the Semantic Web
Een populair concept dezer dagen is het semantische web. Veel informatie is opgeslagen in documenten en de bedoeling is om die documenten op een geautomatiseerde manier te leren interpreteren.
Daarvoor moet dus een ontologie opgesteld worden, wat op volgende manieren kan:
• Met een thesaurus (woordenboek) de relatie tussen woorden weergeven die een concept
vormen.
• Een taxonomy beschrijft hoe een aantal concepten met mekaar geassocieerd zijn.
• Een gedetailleerd databaseschema wordt soms als een ontologie beschouwd omdat het concepten (entiteiten en attributen) beschrijft en de relaties ertussen.
• Een logische theorie die gebruik maakt van wiskundige logica om zo concepten te defini¨eren.
55
Hoofdstuk 8
Mapping a Conceptual Design into a
Logical Design
8.1
8.1.1
Relational Database Design using ER-to-Relational
Mapping
ER-to-Relational Mapping Algorithm
Stap 1: Mapping of Regular Entity Types
Voor elk normaal (sterk) entiteitstype E in het ER-schema maak je een relatie S die alle simple
attributes van E bevat. Kies ´e´en van de sleutelattributen van E als de primary key van S. Als er
meerdere sleutelattributen werden ge¨ıdentificeerd werden voor E, dan wordt de informatie die deze
attributen beschrijft, behouden om de secondary (unieke) keys van S te specifi¨eren.
Relaties die gecre¨eerd werden door de mapping van entiteitstypes worden soms entity relations
genoemd omdat elke tupel een entity instance voorstelt.
Stap 2: Mapping of Weak Entity Types
Voor elk zwak entiteitstype W in het ER-schema met als eigenaar een entiteitstype E maak je
een relatie S die alle simple attributes van W bevat. Als extra voeg je de primary key attributes
van de relatie(s) die overeenkomen met die van eigenaar E toe als foreign key attributes van S.
Dit zorgt voor de mapping van de identificerende relatie type van W . De primary key van S is de
combinatie van de primary key(s) van de owner(s) en de parti¨ele key van W .
Als er een weak entity W2 bestaat met als eigenaar ook een weak entity W1 , dan moet je eerst
W1 mappen voor W2 om eerst de primary key te kunnen defini¨eren.
Stap 3: Mapping of Binary 1:1 Relationship Types
Voor elke binary 1:1 relatietype R in het ER-schema identificeer je de relaties S en T die overeenkomen met de entiteitstypes in R. Er zijn drie manieren om dit te doen. De eerste is de handigste
manier en moet gebruikt worden, behalve bij speciale gevallen (zie verder).
• Foreign key approach
Kies ´e´en van de relaties S en neem als foreign key in S de primary key van T . Het is beter
om een entiteitstype te kiezen met totale participatie in R voor de rol van S. Voeg alle
simple attributes van het 1:1 binary relatietype R toe als attributen van S.
Voorbeeld: in department verwijst de foreign key “Mgr ssn” naar “Ssn” van een employee
omdat elk departement een manager heeft. Dit vormt dan het relatietype manages.
56
Het is mogelijk om de primary key van S als foreign key in T de nemen. Maar in het voobeeld
van company zou dan 98% van de foreign keys NULL zijn (zie pagina 273). Ook is het
mogelijk om foreign keys te hebben in S en T , maar dan cre¨eer je redundantie.
• Merged relation approach
Hier voegen we twee entiteitstypes en het relatietype samen in een enkele relatie. Dit is
mogelijk wanneer beide entiteitstypes totale participatie hebben, want dit betekent dat de
twee tabellen telkens exact hetzelfde aantal tupels zal hebben.
• Cross-reference of relationship relation approach
Bij deze methode maken we een derde relatie R met als doel om de primary keys van de
twee relaties S en T te cross-referencen. Deze methode is noodzakelijk voor M:N relaties. De
relatie R noemt men dan een relationship relation of soms ook lookup table. Dit omdat
elke tupel in R een relatie-instance representeert die gerelateerd is aan een koppel van S met
een koppel van T . Het nadeel is dat we hier een extra relatie nodig hebben en we een extra
join-operatie nodig hebben.
Stap 4: Mapping of Binary 1:N Relationship Types
Voor elk normaal, binair 1:N relatietype R identificeer je de relatie S die het participerende entiteitstype aan de N -kant voorstelt. T stelt het entiteitstype aan de 1-kant voor.
Voeg in S een foreign key toe die verwijst naar de primary key van de relatie T . Dit doen we
omdat elke entity instance aan de N -kant gerelateerd wordt aan maximum 1 entity instance van de
1-kant. Voeg alle simple attributes van het 1:N relatietype toe als attributen van S.
In het voorbeeld verwijst de foreign key “Dno” in employee naar de primary key “Dnumber”
van department. Dit moet de relatie works for voorstellen.
Stap 5: Mapping of Binary M:N Relationship Types
Voor elk binary M:N relatietype R cre¨eer je een nieuwe relatie S die R representeert. Neem als
foreign key attributen in S de primary keys van de deelnemende entiteitstypes, de combinatie van
deze foreign keys zal de primary key van S vormen. Voeg ook alle simple attributes van R toe als
attributen van S.
Merk op dat we een M:N relatietype niet kunnen voorstellen door 1 foreign key in ´e´en van de
deelnemende relaties. We moeten dus opnieuw een relationship relation S maken.
Voorbeeld: de foreign keys “Essn” en “Pno” in het works on-relatietype verwijzen naar de primary keys van employee en project. Deze foreign keys vormen de primary key van works on.
Stap 6: Mapping of Multivalued Attributes
Cre¨eer voor elk multivalued attribuut A een nieuwe relatie S met daarin een attribuut dat overeenkomt met A. In S zit ook een verwijssleutel K die het entiteitstype voorstelt dat A als multivalued
attribuut heeft. De primary key van S is de combinatie van A en K.
Voorbeeld: we maken voor het meerwaardig attribuut “Locations” een relatie dept locations
met daarin een foreign key “Dnumber” dat verwijst naar het departement waar “Locations” bijhoort.
Stap 7: Mapping of N -ary Relationship Types
Voor elk n-ary relatietype R (met n > 2) maak je een nieuwe relatie S die R voorstelt. Neem
als foreign key attributes in S de primary keys van de deelnemende entiteitstypes. Voeg ook alle
simple attributes van het n-ary relatietype toe als attributen van S. De primary key van S is de
combinatie van alle foreign keys.
57
8.1.2
Discussion and Summary of Mapping for ER Model Constructs
In een relationeel schema worden relatietypes niet expliciet voorgesteld, ze worden voorgesteld met
twee attributen A en B. E´en hiervan is een primary key, de andere een foreign key (over hetzelfde
domein) in de twee relaties S en T . Twee tupels in S en T zijn gerelateerd als ze beide dezelfde
waarde hebben voor A en B.
Bij de binary 1:1 of 1:N relatietypes is er meestal ´e´en enkele join-operatie nodig. Bij het M:N
relatietype zijn er 2 join-operaties nodig. Verder zijn er voor een n-ary relatietype n join-operaties
nodig om de relatie instances volledig te materialiseren.
ER model
Entiteitstype
1:1 of 1:N relatietype
M:N relatietype
n-ary relatietype
Enkelvoudig attribuut
Samengesteld attribuut
Meerwaardig attribuut
Value set
Key attribuut
8.2
8.2.1
Relationeel model
Entiteitsrelatie
Foreign key (of relationship relation)
Relationship relation en 2 foreign keys
Relationship relation en n foreign keys
Attribuut
Verzameling enkelvoudige attributen
Relatie en een foreign key
Domein
Primaire (of secundaire) sleutel
Mapping EER Model Constructs to Relations
Mapping of Specialization or Generalization
We kunnen een extra stap maken voor het mappen van specialisaties of generalisaties.
Stap 8: Options for Mapping Specialization or Generalization
Zet elke specialisatie met m subklassen {S1 , . . . , Sm } en een superklasse C om tot relatieschema’s.
Hierbij zijn {k, a1 , . . . , an } de attributen van C en is k de primary key. Er zijn meerdere opties.
• Option 8A: Multiple relations — superclass and subclasses
Maak een relatie L voor C met attr(L) = {k, a1 , a2 , . . . , an } en met de primary key PK (L) = k.
Maak ook relaties Li voor elke subklasse Si (met 1 6 i 6 m). Er geldt dan dat PK (Li ) = k
en dat attr(Li ) = {k} ∪ { attr(Si ) }.
Deze optie werkt voor elke specialisatie.
• Option 8B: Multiple relations — subclass relations only
Maak een relatie Li voor elke subklasse Si , met 1 6 i 6 m. Er geldt ook dat PK (Li ) = k en
dat attr(Li ) = { attr(Si ) } ∪ {k, a1 , . . . , an }.
Deze optie werkt enkel voor specialisaties waarvan de subklassen disjunct en totaal zijn (elke
entity in de superklasse moet tot minstens 1 van de subklassen behoren). Bij een niet-totale
specialisatie is er verlies van gegevens. Bij een niet-disjunctie specialisatie is er redundantie.
• Option 8C: Single relation with one type attribute
Maak ´e´en relatie L met attr(L) = {k, a1 , a2 , . . . , an } ∪ { attr(S1 ) } ∪ · · · ∪ { attr(Sm ) } ∪ {t} en
met primary key PK (L) = k. Het attribuut t noemt men een type attribute (of discrimating
attribute) waarvan de waarde aanduidt tot welke subklasse een tupel behoort. Men laat t weg
als de specialisatie predikaatgedefinieerd is.
Deze optie werkt enkel voor specialisaties waarvan de subklasses disjunct zijn. Er is een
gevaar voor veel NULL-waarden als er veel specifieke attributen in de subklassen zitten.
58
• Option 8D: Single relation with multiple type attributes
Maak 1 relatie L met attr(L) = {k, a1 , . . . , an } ∪ {attr(S1 )} ∪ · · · ∪ {attr(Sm )} ∪ {t1 , . . . , tm }
en met primary key PK (L) = k. Elke ti (met 1 6 i 6 m) is een Booleaans attribuut die
aanduidt of een tupel tot een subklasse Si behoort of niet.
Deze optie wordt gebruikt voor specialisaties waarvan de subklasses elkaar overlappen. Ook
hier is er een gevaar voor veel NULL-waarden.
Opties 8A en 8B kunnen multiple-relation options genoemd worden omdat er voor elke subklasse
een nieuwe relatie wordt gemaakt (bij 8A zelfs een nieuwe relatie voor de superklasse).
De opties 8C en 8D worden dan single-relation options genoemd omdat er telkens maar 1
nieuwe relatie wordt gemaakt.
Lees eventueel pagina 279-281, hier worden de opties in detail en met voorbeelden uitgelegd.
8.2.2
Mapping of Shared Subclasses (Multiple Inheritance)
Een gedeelde subklasse is een subklasse die behoort tot meerdere superklassen, er is sprake van
multiple inheritance. Deze superklassen moeten allemaal hetzelfde key-attribuut hebben omdat
we anders de subklasse modelleren als een categorie (union type).
Zie figuur 8.6 op pagina 281 voor een voorbeeld hiervan (met figuur 7.26 op pagina 237).
8.2.3
Mapping of Categories (Union Types)
We voegen een extra stap toe aan de procedure om categorie¨en te kunnen mappen. Een categorie
(of union type) is een subklasse van de unie van twee of meer superklassen. Deze superklassen
kunnen verschillende keys hebben omdat ze behoren tot verschillende entiteitstypes.
Zie figuur 8.7 op pagina 282 voor een voorbeeld hiervan (met figuur 7.26 op pagina 237).
Stap 9: Mapping of Union Types (Categories)
Bij deze stap is het gebuikelijk om een nieuw key-attribuut te maken, genaamd een surrogate key.
We maken een relatie aan die correspondeert met de categorie en voegen alle attributen van de
categorie toe aan deze relatie. De primary key van de relatie is dan de surrogate key. We voegen
ook de surrogate key toe als foreign key in elke relatie die correspondeert met een superklasse van
de categorie. Dit om de overeenkomst in waardes tussen de surrogate key en de primary key van
elke superklasse te specifi¨eren.
Voor een categorie waarbij de superklasses dezelfde key hebben, is een surrogate key niet nodig.
59
Hoofdstuk 12
SQL Application Programming Using C
and Java
12.1
Database Programming: Techniques and Issues
Hoewel de meeste databasesystemen interactive interfaces hebben om direct SQL-commando’s in
uit te voeren, wordt bij de meeste database-interacties toch meestal een applicatieprogramma of
database-applicatie gebruikt.
12.1.1
Approaches to Database Programming
• Embedding database commands in a general-purpose programming language
Database statements zijn ingebouwd in de programmeertaal zelf. Een precompiler of preprocessor zoekt deze dan in de programmacode en vervangt de statements in het programma door
functie-aanroepen naar de DBMS-gegenereerde code. Deze techniek heet embedded SQL.
• Using a library of database functions
Voor een bepaalde programmeertaal bestaat een bibliotheek met functies die toegang verschaffen tot de database. De resultaten van die functie worden dan beschikbaar gesteld aan
het programma in een API (application programming interface).
• Designing a brand-new language
Een volledig nieuwe database-programmeertaal wordt ontwikkeld die compatibel is met het
gegevensmodel en de querytaal. Dit wordt weinig toegepast in de praktijk.
12.1.2
Impedance Mismatch
De term impedance mismatch wordt gebruikt om het probleem aan de duiden tussen het verschil
van de database en de programmeertaal. Voor verschillende programmeertalen moeten bindings
ontworpen worden om de verschillen tussen het gegevensmodel en het model van de programmeertaal
te overbruggen.
Een binding definieert de overeenkomsten van de attribuuttypes (bv. varchar ) met de datatypes
van de programmeertaal (bv. string).
Zo’n binding moet ook het resultaat van een query (verzameling van tupels) aan een datastructuur in het programma koppelen. Omdat een voorstelling in een tabelstructuur in een programmeertaal vaak onmogelijk is, worden de tupels 1 voor 1 geanalyseerd (met een iterator).
Deze problemen worden geminimaliseerd als de programmeertaal hetzelfde model gebruikt als
de database (zoals Oracle’s PL/SQL).
60
12.1.3
Typical Sequence of Interaction in Database Programming
Een client program kan verbinding maken met 1 of meer databaseservers.
1. Het programma opent een connection met de databaseserver (met een adres van de server en
eventueel een loginnaam en een paswoord).
2. Er is interactie tussen het programma en de database: de database levert resultaten van
queries die het programma naar de database stuurt.
3. De verbinding met de database wordt gesloten.
61
Hoofdstuk 13
SQL Web Programming Using C PHP
13.1
A Simple PHP Example
PHP is een general-purpose scripting language, geschreven in C. PHP is vooral goed voor het
aanpassen en manipuleren van tekstpagina’s en dynamische HTML-pagina’s.
PHP loopt op de middle-tier web server waar PHP-commando’s de HTML-files zullen manipuleren om de dynamische pagina’s te maken. De gegenereerde HTML-pagina wordt dan naar de
client tier verzonden. Het DBMS bevindt zich op de bottom-tier database server.
Zie pagina 469-470 voor een voorbeeld van PHP.
13.2
Overview of Basic Features of PHP
13.2.1
PHP Variables, Data Types, and Programming Constructs
In PHP worden namen voor variabelen voorafgegaan met het $-teken. In de naam van een variabele
mogen letters, cijfers en het underscore-teken ( ) voorkomen. De namen zijn case sensitive en het
eerste karakter mag geen cijfer zijn. De waarde die aan een variabele wordt toegekend, bepaalt wat
voor type deze variabele is. Het type kan dus bij een nieuwe toekenning veranderen.
In PHP zijn er veel manieren om strings te processen. Hier volgen de drie meest gebruikte
manieren om strings en tekst uit te drukken.
• Single-quoted strings. Bijvoorbeeld $var = ‘wereld!’.
• Double-quoted strings. Hierin worden variabelen omgezet naar de waarde die ze op dat
moment hebben (bv. ‘‘Hallo $var’’). De herkenning van deze variabele door de interpreter
wordt interpolating variables genoemd. Dit gebeurt niet bij single-quoted strings.
• Here documents. Dit wordt gebruikt om lange teksten toe te kennen aan een variabele.
Men begint met het schrijven van <<<DOCNAME, hierna volgt de eigenlijke tekst die opgeslagen
wordt in een variabele. Het einde van de tekst wordt aangeduid met het codewoord (in dit
geval DOCNAME) op een lege regel. De variabelen worden hier ook ge¨ınterpoleerd.
Single-quoted strings worden gebruikt als er geen variabelen in de string voorkomen, anders worden
double-quoted strings of here documents gebruikt.
Om strings aan elkaar te plakken, wordt de period-operator (.) gebruikt.
In PHP bestaan uiteraard ook integers en floating point getallen, ook de Booleaanse variabele
bestaat. For-lussen, while-lussen en if-statements bestaan ook.
62
13.2.2
PHP Arrays
Arrays zijn belangrijk in PHP omdat ze lijsten van elementen toelaten. Een 1-dimensionale array
kan gebruikt worden voor een lijst van keuzes. Bij 2-dimensionale arrays wordt de eerste dimensie
gebruikt als de rijen van een tabel en de tweede dimensie als de kolommen (attributen) per rij.
Een numerische array associeert een index (startend met 0) met elk element.
$fruit1 = array (‘appel’, ‘banaan’, ‘aardbei’);
Een associatieve array voorziet elementparen (key ⇒ value). Hierbij wordt een element opgeroepen via de key, alle keys moeten dus uniek zijn.
$fruit2 = array (‘F1’ => ‘appel’, ‘F2’ => ‘banaan’, ‘F3’ => ‘aardbei’);
Als er geen keys worden gegeven bij het aanmaken van een array, worden de keys automatisch
numerisch. Beide soorten arrays hebben geen limiet op de grootte. Arrays kunnen doorlopen
worden via een foreach-loop of via een for-loop.
13.2.3
PHP Functions
Het defini¨eren van functies en het oproepen van functies werkt hetzelfde als in Java.
• De argumenten van de functies zijn passed by value. De meegegeven waarden worden dus
‘gekopi¨eerd’ naar de functie-argumenten wanneer de functie wordt opgeroepen.
• Return values van een functie worden achter het keyword return gegeven. Een functie kan
eender welk type variabele teruggeven.
• De regels voor variabelen in PHP zijn analoog aan de regels in andere programmeertalen.
Globale variabelen buiten de functie kunnen niet gebruikt worden in deze functie, tenzij ze
gerefereerd worden met de speciale array $GLOBALS. Bijvoorbeeld $GLOBALS[‘abc’] zal de
waarde opvragen van de globale variabele $abc (gedefinieerd buiten de functie).
13.2.4
PHP Server Variables and Forms
Er zijn een aantal built-in entries in de array $ SERVER die informatie kunnen geven over de server
waar de interpreter op draait. Een aantal van deze entries zijn:
• $ SERVER[‘SERVER NAME’] geeft de website terug waarop de interpreter draait.
• $ SERVER[‘REMOTE ADDRESS’] is het IP-adres van de computer die met de server communiceert (bv. 129.107.61.8).
• $ SERVER[‘REMOTE HOST’] is de websitenaam van de client computer (bv. wiki.wina.be).
• $ SERVER[‘PATH INFO’] is het deel van de URL dat na de slash komt, achteraan de URL.
• $ SERVER[‘QUERY STRING’] geeft de string terug die in de URL achter het vraagteken staat.
In deze string kunnen variabelen en waarden meegegeven worden.
• $ SERVER[‘DOCUMENT ROOT’] is de root directory waar de files op de server staan, deze files
zijn beschikbaar voor client users.
Een andere built-in array is $ POST, deze is ook automatisch globaal. $ POST maakt het mogelijk
voor de programmeur om inputwaarden (gegeven door de user) binnen te krijgen. De keys in deze
array zijn de namen van de inputparameters.
63
13.3
Overview of PHP Database Programming
Er bestaan veel libraries voor PHP met daarin handige functies, deze worden gegroepeerd in PEAR
(PHP Extension and Application Repository). De PEAR DB library geeft functies voor toegang
tot een database, hiermee kunnen verschillende databases worden aangesproken (bv. MySQL).
13.3.1
Connecting to a Database
Om de databasefuncties te kunnen gebruiken, moet eerst de PEAR DB library module ingeladen
worden. Daarna kan men met een database verbinden via $d = DB::connect(‘string’); waarbij
string de informatie over de database voorstelt.
In principe kunnen nu de meeste SQL commando’s doorgegeven worden aan de verbonden
database via de query functie. De functie $q = $d->query(‘query’); neemt een SQL-commando
als string en geeft deze door aan de database voor uitvoering. Als de database iets teruggeeft, wordt
dit resultaat bijgehouden in een query-variabele (in dit voorbeeld $q).
Zie pagina 477-479 voor een duidelijk en uitgewerkt voorbeeld.
13.3.2
Collecting Data from Forms and Inserting Records
Het is gebruikelijk in database-applicaties om informatie te verzamelen met HTML. Bijvoorbeeld,
bij het bestellen van een ticket wordt persoonlijke informatie ingevoerd en dan bijgehouden in een
database record op een database server. Bij zo’n toepassingen wordt de variabele $ POST gebruikt,
hierboven al beschreven.
Omdat er met het INSERT commando ‘slechte’ strings kunnen worden meegegeven, kan men
beter de veiligere placeholders gebruiken (met het ?-symbool).
Zie pagina 479-480 voor een duidelijk en uitgewerkt voorbeeld.
13.3.3
Retrieval Queries from Database Tables
We geven 3 voorbeelden van retrieval queries de resultaten te interpreteren.
• While-loop. Een while-loop overloopt elke rij in het resultaat. De functie $q->fetchrow()
haalt de volgende record in het resultaat binnen. De loop start bij het eerste record.
• Dynamic query. De condities in deze query zijn gebaseerd op wat de user ingeeft, op basis
van deze condities wordt bepaald welke rijen geselecteerd worden. Omdat deze query dus
sterk afhangt van de input gegeven door de user, worden hier best placeholders gebruikt.
• getAll() query. Deze methode geeft een andere manier voor een loop over de rijen van de
query. De functie $q->getAll() geeft alle records van de query terug in 1 enkele variabele.
Een foreach-loop kan gebruikt worden om te itereren over de individuele records.
Zie pagina 480-481 voor een duidelijk en uitgewerkt voorbeeld.
64
Hoofdstuk 14
Database Design Theory: Introduction
to Normalization Using Functional and
Multivalued Dependencies
14.1
Informal Design Guidelines for Relation Schemas
De volgende vier informele richtlijnen kunnen gebruikt worden om de kwaliteit van een relationeel
schema te bepalen.
14.1.1
Imparting Clear Semantics to Attributes in Relations
Wanneer verschillende attributen samen gegroepeerd worden tot een relationeel schema, wordt
ervan uitgegaan dat attributen die bij een relatie horen ook een werkelijke betekenis hebben. De
semantiek van een relatie verwijst naar de betekenis ten gevolge van de interpretatie van attributen
in een tupel. Meestal is een eenvoudig uit te leggen schema ook beter.
Richtlijn 1. Ontwerp een relationeel schema zodat zijn betekenis eenvoudig uit te leggen is. Combineer geen attributen van verschillende entiteits- en relatietypes in een nieuwe relatie.
14.1.2
Redundant Information in Tuples and Update Anomalies
E´en van de doelen van het ontwerpen van een schema is de benodigde opslagplaats voor de relaties
te minimaliseren. Het groeperen van attributen in aparte relaties zorgt voor een verminderd geheugengebruik. Wanneer dit niet zou gebeuren en bijvoorbeeld het resultaat van een natural join van
twee relaties als nieuwe relatie bijgehouden wordt, dan is het te verwachten dat verschillende tupels
overlappende informatie bevatten. Terwijl deze informatie, wanneer ze in aparte relaties beschreven
wordt, slechts ´e´en keer wordt opgeslagen.
Een bijkomend probleem bij het opslaan van natural joins van relaties, is dat deze leiden tot
zogenaamde update anomalies. Laat R de relatie zijn die bekomen wordt uit de natural join van
S en T : R = S ∗ T . Dan kunnen deze anomalie¨en onderverdeeld worden als volgt.
Insertion anomalies. Bij het toevoegen van een tupel s (van relatie S) aan relatie R, moeten
alle attributen van de tupel t uit T waarmee s gejoind werd, gekend zijn en correct ingevoerd
worden. Alleen dan is deze tupel s consistent met de andere tupels uit S die met t gejoind
werden. Als enkele waarden niet gekend zijn, kan men NULL gebruiken.
Als bovendien de primaire sleutel van R deze uit S bevat, is het onmogelijk tupels uit T toe
te voegen die geen overeenkomstige tupel hebben in S.
65
Deletion anomalies. Stel, in R komt een tupel s voor die samenhangt met een bepaalde tupel t,
deze s is de laatste tupel die samenhangt met die tupel t. Als men dan die tupel s verwijdert
(en dus ook t), zijn we alle informatie over die tupel t kwijt.
Modification anomalies. Als men de waarde van een attribuut in een tupel t wijzigt, dan moeten
alle andere tupels in R die t bevatten, ook gewijzigd worden.
Zie de voorbeelden op pagina 491-493.
Richtlijn 2. Ontwerp een relationeel schema op zo’n manier dat er geen toevoeg-, weglaat- of
wijzigingsanomalie¨en aanwezig zijn in de relaties. Moesten deze er toch zijn, vermeld dit dan
duidelijk.
14.1.3
NULL values in Tuples
Wanneer veel attributen samengevoegd worden in 1 relatie, maar als sommige attributen maar
voor enkele tupels een zinvolle waarde hebben, kunnen er veel NULL-waarden in de tabel worden
toegevoegd. Dit kan leiden tot problemen bij onder andere joins en aggregaatfuncties.
Richtlijn 3. Vermijd, voor zover dit mogelijk is, om attributen die vaak NULL-waarden opleveren,
aan relaties toe te voegen.
14.1.4
Generation of Spurious Tuples
Richtlijn 4. Ontwerp een relationeel schema op zo’n manier dat bij het joinen, met gelijkheidscondities op attributen die primaire sleutels of verwijssleutels zijn, geen spurious (onechte)
tupels gecre¨eerd worden. Vermijd relaties die overeenkomstige attributen hebben die geen
primaire sleutel – verwijssleutel verband hebben
14.1.5
Summary and Discussion of Design Guidelines
De vier richtlijnen die besproken werden, laten op een informele manier toe de kwaliteit van een
relationeel schema te garanderen. In de rest van dit hoofdstuk presenteren we formele concepten
om de kwaliteit van individuele relationele schema’s te kunnen bepalen.
14.2
Functional Dependencies
14.2.1
Definition of Functional Dependency
Definitie. Zij R een relatieschema met R = {A1 , A2 , . . . , An } en X en Y attributenverzamelingen
die deelverzamelingen zijn van R.
Een functionele afhankelijkheid X → Y specifieert een restrictie op de mogelijke tupels
die in alle mogelijke extensies r van R kunnen voorkomen.
De restrictie bepaalt dat als er voor 2 tupels t1 en t2 in r geldt dat t1 [X] = t2 [X], dan moet
er ook gelden dat t1 [Y ] = t2 [Y ].
Formeel: X → Y als en slechts als X 6= ∅ en als er in alle mogelijke extensies r van R geldt:
t1 , t2 ∈ r en t1 [X] = t2 [X] =⇒ t1 [Y ] = t2 [Y ].
De attributen in Y hangen dus af van de attributen in X (of ze worden bepaald door de attributen
in X). Anders gezegd: Y is functioneel afhankelijk (FD) van X.
66
Enkele opmerkingen:
• De woorden “in alle mogelijke extensies” hangt af van de betekenis van de relatie. Uit die
betekenis volgen bepaalde restricties waaraan de extensies moeten voldoen.
Een FD is dus een eigenschap van een relationeel schema R, niet een eigenschap van een
bepaalde relatietoestand van R.
• Als X een kandidaatsleutel is van een relatie R, dan geldt X → Y voor elke Y ∈ R. Dit komt
omdat geen 2 tupels in een legale toestand r(R) dezelfde sleutelwaarde mogen hebben.
• Als in R geldt dat X → Y , wil dat niets zeggen over Y → X in R.
Een functionele afhankelijkheid is een eigenschap van de betekenis van de attributen. Ze beschrijft
expliciet bepaalde restricties waaraan een relatie steeds moet voldoen. Men kan functionele afhankelijkheden in schema’s aanduiden met behulp van pijlen.
Als er een functionele afhankelijkheid optreedt in een schema, dan wordt deze vastgelegd door
middel van een restrictie. Op deze manier wordt ervoor gezorgd dat de FD geldt voor alle tupels
in alle extensies van R. Een extensie r(R) is een legale extensie als ze voldoet aan alle functionele
afhankelijkheidsrestricties.
We bespreken 3 basic afleidingsregels, deze zijn correct en volledig.
• FD1 – Reflexiviteitsregel: Y ⊆ X ⇒ X → Y .
• FD2 – Uitbreidingsregel: { X → Y } |= XZ → Y Z.
• FD3 – Transitiviteitsregel: { X → Y , Y → Z } |= X → Z.
Er bestaan ook 3 extra afleidingsregels, deze kunnen bewezen worden met de basic afleidingsregels.
• FD4 – Decompositieregel: { X → Y Z } |= X → Y .
• FD5 – Verenigingssregel: { X → Y , X → Z } |= { X → Y Z }.
• FD6 – Pseudo-transitiviteitsregel: { X → Y , W Y → Z } |= W X → Z.
Uit de betekenis van relaties en attributen leidt men eerst een verzameling functionele afhankelijkheden F af. Met de afleidingsregels kunnen dan alle FD’s gevonden worden die uit F volgen. De
sluiting F + van F is de verzameling van alle FD’s die door F ge¨ımpliceerd worden.
XF + is de sluiting van X ten opzichte van F , met andere woorden: de verzameling van alle
attributen die bepaald zijn door X. Om F + te berekenen, moet men dan voor elke X ∈ F waarvoor
geldt dat X → Y , met de afleidingsregels XF + afleiden.
Een voorbeeld van zo’n sluiting ten opzichte van F : { Ssn }+ = { Ssn , EName }. Merk op dat
X ook meerdere attributen kan bevatten.
Zij E en F verzamelingen FD’s van R.
E wordt overdekt door F a.s.a. E ⊆ F + . Alle FD’s in E volgen dan uit F via de afleidingsregels
en E + ⊆ F + . Om na te gaan of E wordt overdekt door F moet men voor alle X → Y in E de
sluiting XF + bepalen en controleren of Y ⊆ XF + .
E en F zijn equivalent a.s.a. E + = F + .
67
14.3
Normal Forms Based on Primary Keys
14.3.1
Normalization of Relations
Normalisatie van data is een proces waarbij relationele schema’s geanalyseerd worden op basis van
hun functionele afhankelijkheden en primaire sleutels, hierdoor verkrijgt men de gewenste eigenschappen die de redundantie minimaliseren en anomalie¨en beperken. Kortom: normalisatie brengt
een relatie in een bepaalde normaalvorm. Hoe hoger de normaalvorm, des te minder functionele
afhankelijkheden zich kunnen voordoen.
De normalisatieprocedure levert:
• Een formeel model voor het analyseren van relationele schema’s op basis van hun sleutels en
functionele afhankelijkheden.
• Een serie normaalvormtesten die uitgevoerd kunnen worden op individuele relationele schema’s
zodat de relationele database genormaliseerd kan worden tot het gewenste niveau.
Definitie. Een normaalvorm legt bepaalde eisen op aan relaties. De normaalvorm van een relatie is de hoogste normaalvormvoorwaarde waaraan ze voldoet en geeft dus de graad van
normalisatie aan.
De attributenverzameling van een relatieschema SR noteren we met UR , de verzameling afhankelijkheden schrijven we als FR . Er geldt dat SR = <UR , FR >.
Definitie. Een verzameling relatieschema’s δ(SR ) = {SR1 , SR2 , . . . , SRk } is een decompositie van
SR a.s.a. UR = UR1 ∪ UR2 ∪ · · · ∪ URk .
Decompositie is dus het opdelen van relatieschema’s die niet voldoen aan de eisen in relatieschema’s
die wel voldoen aan de eisen. Een goede decompositie van een schema bevat dezelfde informatie
maar bevat geen onnodige relaties. Een goede decompositie is ook effici¨ent te onderhouden.
Definitie. Het normaliseren van een gegevensbank is voor elke relatie in die gegevensbank een
decompositie bepalen zodat alle resulterende relaties in een bepaalde normaalvorm zijn.
De normaalvormen toegepast op afzonderlijke relaties bieden geen voldoende voorwaarde voor een
goed relationeel schema. Er moet nog rekening gehouden worden met eigenschappen van het relationeel schema als een geheel, waaronder hoofdzakelijk de volgende eigenschappen:
• De nonadditive join of lossless join eigenschap garandeert dat, na decompositie van de
relaties, er geen onechte tupels gegenereerd worden bij het joinen van relaties.
• De dependency preservation eigenschap garandeert dat de functionele afhankelijkheden
behouden blijven na decompositie.
14.3.2
Practical Use of Normal Forms
Normalisatie wordt gebruikt bij het ontwerpen van een database om de kwaliteit van het ontwerp
te garanderen. Soms kunnen sommige relaties echter in een lagere normaalvorm gehouden worden
om performantieredenen. Dit komt omdat een hogere normaalvorm een speciaal geval is van de
normaalvorm er net onder.
Alternatieve definitie. Er wordt gesproken van decompositie wanneer de join van twee relaties
in hogere normaalvorm bewaard wordt als een basis relatie, in lagere normaalvorm.
68
14.3.3
Definitions of Keys and Attributes Participating in Keys
Definitie. Een supersleutel K van een relatie R determineert elk attribuut in R.
Anders gezegd: K is een supersleutel van een relatie R met schema SR = <U, F > a.s.a. K ⊆ U
zodat voor geen 2 verschillende tupels t1 en t2 uit een legale extensie geldt dat t1 [K] = t2 [K].
Anders gezegd: K is een supersleutel voor R a.s.a. K ⊆ U en K → U ∈ F + .
Anders gezegd: K is een supersleutel a.s.a. KF+ = U .
Definitie. K is een kandidaatsleutel voor R met schema SR = <U, F > a.s.a. K is een supersleutel voor R en geen enkele echte deelverzameling van K is een supersleutel voor R.
Definitie. Een attribuut A is een sleutelattribuut voor een relatie R met schema SR = <U, F >
a.s.a. er bestaat een sleutel K voor R waarvoor geldt A ∈ K.
Uit de kandidaatsleutels kiest men een primaire sleutel, de andere kandidaatsleutels noemt men
secundaire sleutels. Attributen in de primaire sleutel mogen nooit NULL zijn.
Een relatieschema SR = <U, F > is in de nulde normaalvorm als er geen voorwaarden zijn opgelegd
aan de attributen. De attributen mogen dus samengesteld of meerwaardig zijn.
14.3.4
First Normal Form
Definitie. Een relatieschema SR = <U, F > is in de eerste normaalvorm (1NF) a.s.a. het domein
van elk attribuut van U enkelvoudig is.
Anders gezegd: een attribuut van U mag geen verzamelingen of tupels als waarde hebben.
Als in een relatie toch meerwaardige attributen voorkomen, worden er meerdere tupels voorzien
(redundantie) of wordt er een nieuwe relatie gecre¨eerd met dezelfde sleutel.
Eventuele samengestelde attributen worden opgesplitst in meerdere attributen.
Geneste attributen (meervoudige attributen die samenstellingen zijn) worden op gelijkaardige
manier weggewerkt.
Merk op dat de nieuwe gegevensbank dezelfde informatie bevat als de oorspronkelijke. Er is tevens
geen enkele eis gesteld aan de verzameling van functionele afhankelijkheden F .
14.3.5
Second Normal Form
De tweede normaalvorm is vooral belangrijk als aanloop naar de derde normaalvorm.
Definitie. Zij X → Y .
Y is partieel functioneel afhankelijk van X als er een Z ⊂ X bestaat zodat Z → Y .
Anders is Y volledig functioneel afhankelijk van X.
Anders gezegd: Y is partieel afhankelijk als een attribuut A ∈ X kan verwijderd worden uit
X en er na de verwijdering nog steeds geldt dat X → Y .
Definitie. Een relatieschema SR = <U, F > is in de tweede normaalvorm (2NF) a.s.a. voor geen
enkel niet-sleutelattribuut A van U geldt dat A partieel functioneel afhankelijk is van een
kandidaatsleutel van R.
Anders gezegd: voor elk niet-sleutelattribuut moet de hele primaire sleutel nodig zijn om het
determineren.
69
Testen of een schema voldoet aan 2NF, gebeurt door de functionele afhankelijkheden te testen
waarbij het linkerlid een deel is van de primaire sleutel. Als de primaire sleutel uit 1 enkel attribuut
bestaat, is automatisch voldaan aan de voorwaarde.
Om een relatieschema SR1 = <UR1 , FR1 > van 1NF naar 2NF te brengen, moet voor elk attribuut
A dat partieel functioneel afhankelijk is van een kandidaatsleutel K, het volgende gedaan worden:
1. Zoek een subset K 0 ⊂ K waarvan A volledig functioneel afhankelijk is.
2. Elimineer A uit UR1 .
3. Maak een nieuw relatieschema SR2 met als attributenverzameling UR2 = K 0 ∪ A.
Op die manier blijft alle informatie behouden, er wordt wel een nieuw relatieschema toegevoegd.
14.3.6
Third Normal Form
Definitie. Een functionele afhankelijkheid X → Y in R is een triviale functionele afhankelijkheid
a.s.a. Y ⊆ X.
Definitie. Een functionele afhankelijkheid X → Y is een transitieve functionele afhankelijkheid
a.s.a. er een Z bestaat zodat de volgende 3 voorwaarden voldaan zijn:
1. Z is volledig en niet-triviaal functioneel afhankelijk van X.
2. Z is geen (echte of onechte) deelverzameling van een kandidaatsleutel.
3. Y is niet-triviaal functioneel afhankelijk van Z.
We zeggen dat Y transitief functioneel afhankelijk is van X via Z.
Anders gezegd: X → Y en X → Z → Y .
Definitie. Een 2NF-relatieschema SR = <U, F > is in de derde normaalvorm (3NF) a.s.a. voor
geen enkel niet-sleutelattribuut A van U geldt dat:
A is transitief functioneel afhankelijk van een of andere kandidaatsleutel van R.
Alternatieve definitie. Een 1NF-relatieschema SR = <U, F > is in de derde normaalvorm (3NF)
a.s.a. voor elke niet-triviale functionele afhankelijkheid X → A van F + geldt dat:
A is een sleutelattribuut of X is een supersleutel voor R.
Om een relatieschema SR2 = <UR2 , FR2 > van 2NF naar 3NF te brengen, moet voor elk nietsleutelattribuut A dat transitief functioneel afhankelijk is van een kandidaatsleutel K via Z, het
volgende gedaan worden:
1. Elimineer A uit UR2 .
2. Maak een nieuw relatieschema SR3 met als attributenverzameling UR3 = Z ∪ A.
Een relatieschema voldoet niet aan de algemene definitie van 3NF als:
• een niet-sleutelattribuut een ander niet-sleutelattribuut determineert (transitieve afhankelijkheid).
• een echte deelverzameling van een sleutel in R een niet-sleutelattribuut functioneel determineert (parti¨ele afhankelijkheid).
Zie tabel 14.1 op pagina 509 voor een overzicht van de 3 normaalvormen die we tot nu bespraken.
70
14.4
General Definitions of Second & Third Normal Forms
Het zijn parti¨ele en transitieve afhankelijkheden die leiden tot de update-anomalie¨en die eerder
besproken werden. In het boek werden tot nu toe de parti¨ele en transitieve afhankelijkheden van de
primaire sleutel verboden door 2NF en 3NF. Er wordt echter geen rekening gehouden met eventuele
andere kandidaatsleutels.
In deze samenvatting werd wel al rekening gehouden met de parti¨ele en transitieve afhankelijkheden. 14.4 in het boek mag dus overgeslagen worden als je deze samenvatting strikt volgt. Het
lezen van 14.4 kan echter geen kwaad.
14.5
Boyce-Codd Normal Form
In de derde normaalvorm zijn er nog steeds functionele afhankelijkheden toegestaan binnen de
sleutels zelf. Deze worden weggewerkt in de Boyce-Codd normaalvorm.
Definitie. Een 3NF-relatieschema SR = <U, F > is in de Boyce-Codd normaalvorm a.s.a.
voor geen enkel sleutelattribuut A van U geldt dat:
A is partieel of transitief functioneel afhankelijk van een of andere kandidaatsleutel van R.
Alternatieve definitie. Een 1NF-relatieschema SR = <U, F > is in de Boyce-Codd normaalvorm a.s.a. voor elke niet-triviale functionele afhankelijkheid X → A in F + geldt dat X een
supersleutel is voor R.
Merk op dat deze 2 definities enorm veel lijken op de definities van 3NF, met maar kleine verschillen.
Om van 1NF naar BCNF over te gaan, volg je het pad van 1NF naar 3NF maar houd je rekening
met sleutelattributen.
BCNF werkt alle ongewenste functionele afhankelijkheden weg. Helaas is BCNF niet altijd
bereikbaar zonder andere problemen te cre¨eren. Daarenboven worden sommige functionele afhankelijkheden moeilijker te controleren.
71
Hoofdstuk 15
Database Design Theory: Normalization
Algorithms
15.1
Further Topics in Functional Dependencies: Inference
Rules, Equivalence, and Minimal Cover
15.1.1
Inference Rules for Functional Dependencies
Met F wordt de verzameling van alle gespecifi¨eerde functionele afhankelijkheden in een schema R
aangeduid. De afhankelijkheden die in F zijn opgenomen hebben een duidelijke betekenis. In het
schema R zullen echter nog functionele afhankelijkheden aanwezig zijn die niet in F zitten. Deze
afhankelijkheden kunnen van F afgeleid worden.
Definitie. Formeel wordt de verzameling van alle afhankelijkheden in F en al deze die kunnen
afgeleid worden uit F de sluiting van F genoemd. Aangeduid als F +
Een FD X → Y wordt ge¨ımpliceerd door een verzameling afhankelijkheden F als X → Y geldt
voor elke geldige extensie r van R. Het is te zeggen, als voor een geldige extensie r F geldt, dan
moet ook X → Y gelden. Om F + op te bouwen vanuit F hebben we afleidingsregels nodig, enkele
worden nu besproken. (F |= X → Y duidt aan de X → Y ge¨ımpliceerd wordt door F).
IR1 (Reflexiviteitsregel): Als X ⊇ Y, dan X → Y.
IR2 (Uitbreidingsregel) : {X → Y } |= XZ → Y Z
IR3 (Transitiviteitsregel) : {X → Y, Y → Z} |= X → Z
IR4 (Decompositieregel) : {X → Y Z} |= X → Y
IR5 (Verenigingsregel) : {X → Y, X → Z} |= X → Y Z
IR6 (Pseudo-transitiviteitsregel) : {X → Y, W Y → Z} |= W X → Z
Voor bewijzen van deze stellingen zie pagina (531 in de 6de editie van het handboek).
72
Het is bewezen, door Armstrong, dan de eerste drie afleidingsregels correct en volledig zijn.
Correct houdt in dat alle afhankelijkheden die afgeleid kunnen worden ook werkelijk ge¨ımpliceerd
worden. Volledig houdt in dat alle afhankelijkheden die ge¨ımpliceerd worden ook afgeleid kunnen
worden. Deze regels noemt men de afleidingsregels van Armstrong.
Definitie. Voor elke verzameling attributen X, die voorkomt als linkerlid in een functionele afhankelijkheid uit F, bepalen we de verzameling X + van attributen die functioneel afhankelijk
zijn van X gebaseerd op de afhankelijkheden F. X + noemen we de sluiting van X tov. F.
Voor het algoritme om X + te bepalen, zie pagina (532).
15.1.2
Equivalence of Sets of Functional Dependencies
Definitie. Een verzameling functionele afhankelijkheden F overdekt een andere verzameling afhankelijkheden E als voor elke FD in E ook in F + zit.
Definitie. Twee verzamelingen functionele afhankelijkheden F en E zijn equivalent als E + = F + .
Anders gezegd, elke FD in E kan worden afgeleid uit F en omgekeerd. Nog anders, E en F
zijn equivalent als geldt: F overdekt E en E overdekt F.
Om te kijken of F een verzameling E overdekt, berekenen we X + ten opzichte van F voor elke
X → Y in E en dan te kijken of deze X + Y bevat. Als dit zo is voor elke FD in E, dan wordt E
overdekt door F.
15.1.3
Minimal Sets of Functional Dependencies
Informeel is een minimale overdekking van een verzameling FD’s E een verzameling functionele
afhankelijkheden F waarvoor geldt dat elke afhankelijkheid uit E zit in sluiting F + van F. Hierbij
komt nog dat als een FD uit F verwijdert wordt, dit niet meer zou gelden. We zeggen dat een
verzameling afhankelijkheden F minimaal is als voldaan is aan volgende voorwaarden :
• Elke afhankelijk uit F heeft als rechterlid ´e´en enkel attribuut.
• Geen enkele afhankelijkheid X → A, kan vervangen worden door een afhankelijkheid Y → A,
waar Y een echte deelverzameling is van X. Gebeurt dit toch, dan is de bekomen verzameling
niet equivalent aan F.
• We kunnen geen enkele afhankelijkheid uit F verwijderen en toch nog een verzameling FD’s
uitkomen die equivalent is aan F.
Definitie. Een minimale overdekking van een verzameling functionele afhankelijkheden E is een
minimale verzameling afhankelijkheden die equivalent is aan E. Er bestaat altijd minstens ´e´en
zo’n overdekking. (zie algoritme 15.2 p. 534)
Een algoritme voor het vinden van een sleutel van een relatie, gegeven een verzameling FD’s
staat op pagina 535.
15.2
Properties of Relational Decompositions
Wanneer een relatie R door middel van decompositie opgedeeld wordt in een verzameling van relaties
D = {R1 , R2 , ...Rn } en hierdoor vervangen wordt, dan noemen we D en decompositie van R.
SmHierbij eisen we dat elk attribuut uit R ook vertegenwoordigt wordt in D. Het is te zeggen :
i=1 Ri = R.
73
15.2.1
Dependency Preservation Property of a Decomposition
Definitie. Gegeven een verzameling afhankelijkheden F op R, de projectie van F op Ri , πRi (F )
waar Ri een deelverzameling is van R, is de verzameling afhankelijkheden X → Y in F +
zodat de attributen in X ∪ Y vervat zitten in Ri . We zeggen dat een decompositie D =
{R1 , R2 , ..., Rn } van R afhankelijkheidsbewarend is ten opzichte van F, als de unie van de
projecties van F op elke Ri in D equivalent is aan F.
Bewering 1. Het is altijd mogelijk een decompositie D te vinden die afhankelijkheden bewaard
tov. F en waarbij elke relatie uit D in 3NF is.
15.2.2
Nonadditive (Lossless) Join Property of a Decomposition
Definitie. Een decompositie D van R heeft de lossless (nonadditive) join eigenschap ten opzichte
van een verzameling afhankelijkheden F op R als, voor elke relatie extensie r van R die voldoet
aan F, geldt dat : *(πR1 (r),...πRm (r)) = r, met * de natuurlijke join van alle relaties in D. (π
is hier de PROJECT operatie uit relationele algebra).
De nonadditive join eigenschap zorgt ervoor dat bij er bij een natuurlijke join van relaties geen
onechte tupels ontstaan. Voor een algoritme om te testen of een decompositie lossless is, zie pagina
538-539. (Zie oefenzitting 6 voor uitleg over het algoritme)
15.2.3
Testing Binary Decompositions for the Nonadditive Join Property
Property NJB: Een decomposite D = {R1 , R2 } van R heeft de lossless join eigenschap ten opzichte van een verzameling FD’s F op R als en slechts als
• De FD ((R1 ∩ R2 ) → (R1 − R2 )) in F + zit OF
• De FD ((R1 ∩ R2 ) → (R2 − R1 )) in F + zit.
15.2.4
Successive Nonadditive Join Decompositions
Bewering 2. Als een decompositie D = {R1 , R2 , ..., Rm } van R lossless is tov. F en een decompositie Di = {Q1 , Q2 , ...Qn } van Ri lossless is tov de projectie van F op Ri , dan is de decompositie
D2 = {R1 , R2 , ..., Ri−1 , Q1 , Q2 , ..., Qn , Ri+1 , ..., Rm } ook lossless tov. F.
15.3
Algorithms for Relational Database Schema Design
Er worden 3 belangrijke algoritme aangebracht en uitgelegd in het boek, heel deze sectie is belangrijk
en wordt bijgevolg niet echt samengevat.
15.3.1
Dependency-Preserving Decomposition into 3NF Schemas
Het algoritme dat vermeld werd bij bewering 1 staat uitgelegd op pagina 542 en bespreekt hoe een
relatie kan omgezet worden in een verzameling relaties die de functionele afhankelijkheden bewaren.
Bewering 3. Elk relationeel schema dat door dit algoritme gemaakt wordt is in 3NF
74
15.3.2
Nonadditive Join Decomposition into BCNF Schemas
Een algoritme dat een decompositie van een relationeel schema oplevert die de lossless join eigenschap heeft, wordt besproken op pagina 543 en 544.
15.3.3
Dependency-Preserving and Nonadditive (Lossless) Join Decomposition into 3NF Schemas
Een uitbreiding van het algoritme voor afhankelijkheidsbewarende decompositie zorgt ervoor dat
ook de lossless join eigenschap gegarandeert wordt. (zie p. 544-546)
15.4
About Nulls, Dangling Tuples, and Alternative Relational Designs
15.4.1
Problems with NULL Values and Dangling Tuples
Wanneer de waarde NULL voorkomt in een tupel, bij een attribuut dat gebruikt wordt om de relatie
te joinen met een andere, wordt dit tupel uit die join weggelaten. Dit levert vaak niet het gewenste
effect op en kan verholpen worden door een outer join te gebruiken in plaats van een inner join.
NULLs kunnen ook een effect hebben op functies als SUM en AVERAGE.
Verbonden hieraan is het concept van hangende tupels. Als een relatie te ver wordt opgedeeld
en ´e´en entiteit voorgesteld als samenstelling van verschillende relaties, dan is het mogelijk dat een
tupel dat behoord tot de entiteit, niet behoord tot ´e´en of meer van deze relaties. Wanneer deze
relaties vervolgens gejoined worden om de oorspronkelijke entiteit terug te krijgen verschijnt dit
tupel niet in het resultaat, we noemen dit tupel een (dangling) hangend tupel.
15.4.2
Discussion of Normalization Algorithms and Alternative Relational Designs
Een van de problemen van de normalisatie algoritmes die net besproken werden, is dat telkens alle
functionele afhankelijkheden geleverd moeten worden. Bij het weglaten van zelfs maar ´e´en of twee
afhankelijkheden kan een fout schema gegenereerd worden.
Deze algoritmen zijn ook niet deterministisch, het is te zeggen afhankelijk van de volgorde waarin
afhankelijkheden behandeld worden, kunnen verschillende schemas gemaakt worden. Sommige van
deze mogelijke schemas kunnen minder gewenst zijn dan anderen.
75
Hoofdstuk 16
Database File Organizations: Unordered,
Ordered, and Hashed Files of Records
16.1
Introduction
Er zijn 3 hoofdcategorie¨en in storage hierarchy.
• Primary storage staat rechtstreeks in contact met de CPU en wordt gebruikt voor verwerking en opslag, bv. cache memory (SRAM), main memory (DRAM), flash memory.
• Secondary storage is aan het systeem verbonden voor opslag, bv. magnetische schijven.
• Tertiary storage is verwijderbaar van het systeem en wordt gebruikt voor archivering en
backup, bv. optische media (CD, DVD) of magnetische banden.
16.1.1
Memory Hierarchies and Storage Devices
Als je van boven naar onder gaat in de storage hierarchy, daalt de snelheid (en prijs) en stijgt de
capaciteit. Opslagcapaciteit wordt gemeten in kilo-, mega-, giga-, tera- en petabytes (telkens
stappen van 103 beginnend met 1 Kbyte = 1000 bytes).
Main memory databases hebben al hun gegevens in het hoofdgeheugen (en backup op secundair geheugen). Deze zijn handig voor realtime toepassingen.
Een jukebox (zowel optisch als tape) kan automatisch tertiary storage binnen het systeem
brengen. Dit is belangrijk voor zeer grote archieven.
16.1.2
Storage of Databases
Persistent data blijft bewaard over langere periodes. Transient data bestaat tijdelijk tijdens de
executie van een programma. De meeste databases zijn opgeslagen als persistent data op magnetische schijven omdat databases te groot zijn voor main memory en omdat het goedkoop is.
Volatile storage is een categorie van opslag waaronder main memory valt, er is veel kans op
gegevensverlies (bv. door een stroompanne of een crash van het programma). Daarom worden
databases opgeslagen op nonvolatile storage waaronder secundaire en tertiaire opslag vallen.
Online storage kan op elk moment geraadpleegd worden. Offline storage kan niet op elk moment
geraadpleegd worden omdat het eerst geladen moet worden in het systeem. Dit gebeurt ofwel
automatisch (jukebox ) of handmatig. Offline storage wordt vaak gebruikt bij archivering van data
omdat tape heel goedkoop is en omdat de gegevens niet direct beschikbaar moeten zijn.
76
Bij het physical database design wordt bepaald hoe de organisatie van data wordt georganiseerd.
De data voor een database is opgeslagen als files of records. Als bepaalde data nodig is, wordt
deze van de disk naar main memory gekopieerd om te gebruiken.
Primary file organization bepaalt hoe records fysisch worden opgeslagen en dus hoe ze kunnen
worden aangesproken. Hier zijn meerdere keuzes zoals een heap file (ongesorteerd), een sorted file
(sequentieel), een hashed file of B-trees. Bij sorted files en bij hashed files wordt er gesorteerd of
gehasht op een bepaald veld: de sort key of de hash key.
Secondary organization of auxiliary access structure bepaalt hoe records via andere velden kunnen worden aangesproken, vaak gebeurt dit via indexen.
16.2
Secondary Storage Devices
De inhoud van deze sectie (pagina 569-575) is uitgebreid gezien in de cursussen Besturingssystemen
en SOCS. Het belangrijkste uit deze sectie is dat disks random access storage devices zijn en
dat het dus tijd kost om de juiste block te zoeken. Jaarlijks worden processoren 60% sneller maar
de toegangstijden van geheugen daalt maar met 7% per jaar. Het grote knelpunt bij databasetoepassingen is dus de tijd die nodig is om gegevens op schijven te lokaliseren en te schrijven.
Tapes zijn sequential access storage devices en hebben dus ook trage toegangstijden.
16.3
Buffering of Blocks
Het bufferen van (fysische) blokken van records is slechts effici¨ent indien er meerdere processen
verschillende delen van de database nodig hebben. Terwijl een proces wordt uitgevoerd kan de
buffer voor het andere proces gevuld worden en vice versa. Op deze manier heeft elk proces altijd
data klaar om te verwerken.
16.4
Placing File Records on Disk
16.4.1
Records and Record Types
In een database worden gegevens meestal opgeslagen in records. Elk record is een samenhorende
verzameling van data values of data items die elk tot een bepaald field behoren. Elk field heeft
een data type dat bepaalt welke mogelijke waarden er in dat field kunnen staan en hoe deze moeten
worden gelezen. Een verzameling van field names en de overeenkomstige data types specifi¨eren de
definitie van een record type of record format.
Om grote data-items in een record op te slaan (bv. video), gebruikt men pointers. Deze pointers
verwijzen naar BLOBs (Binary Large OBject) die meestal elders worden opgeslagen.
16.4.2
Files, Fixed-length Records, and Variable-Length Records
Een file in een databasecontext is meestal een opeenvolging van records. Er wordt onderscheid
gemaakt tussen 2 groepen records in files. Fixed-length records hebben allemaal dezelfde lengte
(hetzelfde aantal bytes). Variable-length records hebben verschillende lengtes. De records kunnen om volgende redenen van lengte verschillen:
• De records zijn allemaal van hetzelfde type maar ´e´en of meer velden hebben een variabele
lengte (variable-length fields).
In dit geval is er een separator nodig om de velden binnen een record te onderscheiden.
77
• De records zijn van hetzelfde type maar enkele velden zijn optioneel, niet alle records bevatten
deze optional fields dus.
In dit geval is er field type code nodig die aanduidt of een field in een record voorkomt.
• Repeating field: velden kunnen meerdere waarden hebben.
In dit geval is er een separator nodig die de meerdere waarden onderscheidt en een separator
die het einde van het veld aanduidt.
• Bij een mixed file zijn er verschillende recordtypes.
In dit geval is er een record type code nodig die bepaalt welk type record er behandeld
wordt.
16.4.3
Record Blocking and Spanned versus Unspanned Records
Als B de blokgrootte is en R de grootte van fixed-length records en als B > R, dan vinden we dat
de blocking factor gelijk is aan bfr = bB/Rc (aantal records per blok). Deze blocking factor bfr
kan gebruikt worden om het aantal blokken b te berekenen die nodig zijn voor een file van r records:
b = dr / bfre.
Spanned records worden verspreid over meerdere blokken. Aan het einde van een vol blok staat
dan een pointer naar het blok met het vervolg van het record. Deze techniek wordt gebruikt bij
variable-length records of als R > B. bfr is hier het gemiddeld aantal records per blok.
Unspanned records worden niet verspreid over meerdere blokken, 1 record past altijd volledig
in 1 blok. Hierbij is er vaak overschot aan het einde van een blok als B geen veelvoud van R is:
B − (bfr · R) vrije bytes. Deze techniek wordt gebruikt bij korte, fixed-length records. Elk record
begint dan op een vaste positie in het blok.
16.4.4
Allocating File Blocks on Disk
• Contiguous allocation: opeenvolgende bestandsblokken worden toegewezen aan aaneensluitende fysische blokken. Met 2 buffers kan het bestand snel overlopen worden, het invoegen
van blokken is echter moeilijk.
• Linked allocation: elk bestandsblok bevat een pointer naar het volgende blok. Het volledige
bestand overlopen gaat traag maar het bestand uitbreiden is heel simpel.
• Clustered allocation: clusters van aaneensluitende blokken worden geketend met pointers.
Het bestand kan snel overlopen en simpel uitgebreid worden.
• Indexed allocation: 1 of meer indexblokken bevatten pointers naar de bestandsblokken.
16.4.5
File Headers
De file header van een bestand bevat informatie voor het systeem waarop het bestand staat. Hierin
staat hoe een record eruit ziet, in welke blokken het bestand zich bevindt en de ordening van het
bestand.
Om een record te zoeken, worden meerdere blokken naar buffers geplaatst zodat het main
memory kan zoeken of het record in die blokken zit. Als het adres van een record niet gekend is,
moeten alle blokken van een bestand doorzocht worden om het record te vinden (linear search).
Om deze tijdverspilling tegen te gaan, is het belangrijk om informatie over de positie van records
bij te houden.
78
16.5
Operations on Files
Er zijn 2 soorten operaties op bestanden: retrieval operations (records lokaliseren en inlezen) en
update operations (records aanpassen, invoegen of verwijderen).
Met behulp van een simple selection condition kunnen records gezocht worden, deze worden
aangeboden door het besturingssysteem en zijn heel eenvoudig. Een DBMS moet een ingewikkelde
query omzetten in deze eenvoudige selectiecriteria.
• Open: het bestand wordt voorbereid op lezen en schrijven, 2 buffers worden aangesteld en
de file header wordt opgehaald. De pointer wijst naar het begin van het bestand.
• Close: de buffers worden opgeruimd.
Record-at-a-time operations behandelen 1 record per operatie.
• Reset: zet de file pointer terug naar het begin van het bestand.
• Find (locate): zoek het eerste record dat aan het criterium voldoet, kopieer het blok van
het record naar de buffer, zet de pointer naar dat record (het huidige record).
• Read (get): het huidige record wordt toegekend aan een programmavariabele, soms wordt
de pointer verplaatst (en moet misschien een nieuw blok ingelezen worden).
• FindNext: zoek het volgende record in de file dat aan de conditie voldoet. Laad het blok
van het record naar de buffer, zet de pointer naar dat record (het huidige record).
• Delete: verwijder het huidige record.
• Modify: verander het huidige record (eerst in de buffer, daarna wordt het record naar het
bestand geschreven).
• Insert: laad het juiste blok in de buffer, voeg het record toe aan dat blok en schrijf het blok
weg in het bestand.
Er bestaan ook operaties die andere operaties combineren.
• Scan: Find of FindNext en dan Read.
Set-at-a-time operations behandelt een set van records behandelen per operatie.
• FindAll: lokaliseert alle records die aan de conditie voldoen.
• Find n: lokaliseer n records die aan de conditie voldoen.
• FindOrdered: zoek alle records in een bepaalde volgorde.
• Reorganize: herorganiseer het bestand (bv. sortering).
Bij bestandsverwerking bij databases zijn er enkele belangrijke parameters waarmee rekening moet
worden gehouden. De file activity slaat op het aantal gebruikte records t.o.v. het totaal aantal
records in het bestand. De file volatility slaat op het aantal records dat in een periode veranderd
wordt t.o.v. het totaal aantal records in het bestand. De file turnover slaat op het aantal records
dat in een periode vervangen wordt t.o.v. het totaal aantal records in het bestand. De file growth
slaat op de toename van het aantal records in een bepaalde periode.
79
16.6
Files of Unordered Records (Heap Files)
Records worden in het bestand geplaatst in de orde waarin ze zijn toegevoegd. Een record toevoegen
kan zeer effici¨ent (achteraan toevoegen).
Zoeken in het bestand is ineffici¨ent (lineair). Het verwijderen van een record is ook ineffici¨ent
omdat het record eerst gezocht wordt, het blok naar het geheugen wordt verplaatst, het record
verwijderd wordt en uiteindelijk het blok teruggeschreven wordt.
Bovendien moet er af en toe een reorganization gebeuren om gaten in het bestand op te vullen.
16.7
Files of Ordered Records (Sorted Files)
Records worden fysisch geordend in een file volgens het ordering field. Als men de sleutel van het
record gebruikt om te sorteren noemt dat veld de ordering key voor het bestand.
Zoeken op ordering field is zeer effici¨ent met binary search (log2 b). Zoeken op nonordering
field blijft ineffici¨ent door linear search (b/2). Het invoegen, aanpassen (van het ordering field) en
verwijderen van records levert problemen op. Hieronder worden enkele oplossingen uitgelegd.
• Overflow file (transaction file): er wordt een ongeordend bestand gemaakt waar heel gemakkelijk records aan toegevoegd worden. Er is een periodieke reorganisatie nodig die de overflow
file met het echte bestand samenvoegt.
• Extra ruimte voorzien voor het toevoegen van records verspilt veel ruimte. Na een tijd is
er opnieuw meer ruimte nodig.
• Na elke operatie reorganiseren is ineffici¨ent aangezien dit veel tijd vraagt.
Sorted files worden niet vaak gebruikt in databases. Meestal gebruikt men een indexed-sequential
file met een primary index. Als er gesorteerd wordt op een veld dat geen sleutel is, dan wordt zo’n
bestand een clustered file genoemd.
16.8
Hashing Techniques
Hash files worden gebruikt om zeer snel de locatie van een record te bepalen. De zoekconditie
moet gebaseerd zijn op het hash field van het record. Als dit hash field de sleutel is van het record,
is het de hash key.
Een hash function h beeldt de waarde van het hash field af op het adres van de fysische blok
waarop het record zich bevindt. Een veelgebruikte hashfunctie is h(a) = a mod b, deze wordt vaak
in combinatie met andere berekeningen gebruikt.
16.8.1
Internal Hashing
De gegevens en de hashfunctie worden in het main memory voorgesteld (soms als een hash table).
Een collision komt voor als de hashwaarde van een in te voegen record al bestaat, er moet dan
een nieuwe positie gevonden worden (collision resolution). Dit kan op meerdere manieren.
• Open addressing probeert steeds volgende posities tot een lege positie is gevonden. Dit kan
echter zeer traag worden door het lineair zoeken naar een lege positie.
• Chaining voegt het nieuwe record toe in een overflow location. Op de plaats van de waarde
van de hashfunctie wordt dan een pointer bijgevoegd naar die overflow location.
• Multiple hashing: meerdere hashfuncties worden berekend tot men een lege positie vindt.
80
16.8.2
External Hashing for Disk Files
De gegevens (eventueel ook de hashfunctie) worden opgeslagen in het bestand zelf. Buckets bevatten pointers naar (groepen van opeenvolgende) fysische blokken. Verschillende records hebben
dezelfde hashwaarde als die in hetzelfde fysieke blok zitten. Als buckets volgeraken, worden er
gemeenschappelijke overflow buckets gebruikt.
Bij static hashing wordt er een vaste ruimte gereserveerd voor het bestand. Als het bestand
te groot is, is er verlies van ruimte. Als het bestand te klein is, zal er veel overloop en dus tijdverlies
optreden. Na een tijdje is er ook reorganisatie nodig.
Door het gebruiken van chaining is het moeilijk om een een record te zoeken via een veld dat
niet het sleutelveld is. Het doorlopen van het bestand in sleutelvolgorde is ook eerder traag.
16.8.3
Hashing Techniques That Allow Dynamic File Expansion
Extendible Hashing. Hier wordt gebruik gemaakt van een directory. Dit is een tabel waarin
de bucket van een record wordt bepaald met de eerste d bits (global depth) van de hashwaarde.
Deze bits zijn niet noodzakelijk uniek zodat er eenvoudig uitbreiding mogelijk is.
Voor elke bucket wordt ook de local depth d0 bijgehouden die bepaalt via welk aantal bits de
inhoud van de bucket is samengesteld. Er geldt altijd dat d0 6 d.
Bijvoorbeeld: in een directory (met d = 4) verwijzen de hashwaarden die beginnen met 1000 of
1001 naar dezelfde groep van buckets die beginnen met 100. Deze groep van buckets heeft dan een
lokale diepte d0 = 3. Na doorverwezen te worden naar deze groep buckets, wordt gekeken naar de
andere bits van de hashwaarde om te bepalen in welke bucket de hashwaarde behoort.
Bij overloop van een bucket moet maar 1 bucket in twee buckets gesplitst worden (met telkens
lokale diepte d0 + 1). Als er al geldt dat d0 = d, dan zal de waarde van d met 1 verhoogd worden,
hierdoor wordt de grootte van de directory verdubbeld.
Figuur 16.11 op pagina 595 maakt veel duidelijk.
Dynamic Hashing. Dit lijkt sterk op extendible hashing maar in plaats van een tabel (directory),
wordt een boomstructuur gebruikt. Afhangend van de nde bit van de hashwaarde, wordt op diepte
n bepaald welke wijzer naar de volgende knoop of bucket gekozen moet worden.
Ook hier moeten niet alle niveaus altijd bestaan en worden deze enkel gecre¨eerd indien nodig,
dus bij een volle bucket.
Zie figuur 16.12 op pagina 597.
Linear Hashing. Deze techniek probeert de veranderende grootte op te vangen zonder een extra
structuur. Om dit te bereiken houdt men een reeks hashfuncties en 1 extra variabele n bij.
Initieel is n = 0 en zijn er M buckets (0, 1, . . . , M − 1) met bijhorende initi¨ele hashfunctie
hi (K) = K mod M . Bij de eerste overloop wordt het record in zijn bucket gestopt met chaining.
De records in bucket 0 worden dan herverdeeld over bucket 0 en de nieuwe bucket M volgens
hi+1 (K) = K mod 2M . De waarde n wordt met 1 verhoogd.
Bij de volgende overlopen zullen buckets 1, 2, . . . gesplitst worden. De waarde van n wordt
gebruikt om te bepalen welke buckets al gesplitst zijn. Als hi (K) < N , is de bucket die hoort bij
hi (K) al gesplitst. Je moet dan voor dit record de functie hi+1 (K) gebruiken.
Uiteindelijk zal n = M , dit betekent dat de originele buckets 0, 1, . . . , M − 1 gesplitst zijn. Er
zijn dan 2M buckets, allen met de hashfunctie hi+1 . Op dit moment wordt n op 0 gezet en elke
nieuwe overloop zal leiden tot het gebruik van de hashfunctie hi+2 (K) = K mod 4M .
De file load factor l = r/(d · N ) kan het splitsen van buckets inperken, als l klein wordt, kan
je buckets weer samenvoegen. Hierbij is r het aantal aanwezige records, d de diepte van de buckets
en N het aantal buckets.
81
16.9
Other Primary File Organizations
16.9.1
Files of Mixed Records
In de eerdere secties gingen we telkens uit van hetzelfde type records binnen een file. In een
re¨eel systeem is dit echter zelden het geval aangezien er relaties tussen verschillende types moeten
weergegeven worden. Er zijn verschillende methodes om dit te implementeren.
Logical field references zijn verwijzingen naar een ander record, deze verwijzingen worden
geschreven in het veld dat verwijst naar andere records.
Een andere techniek die gebruikt wordt voor vaak opgevraagde relaties heet physically clustering on disk. Hierbij gaan we binnen een bestand de records clusteren per type.
16.10
Parallelizing Disk Access Using RAID Technology
Dit is gezien in het vak Besturingssystemen. Als je wil, kan je pagina 599-603 lezen.
16.11
New Storage Systems
16.11.1
Storage Area Networks
SANs lossen enkele problemen van de toenemende vraag naar opslagcapaciteit op.
• Flexibel toevoegen van zowel servers als opslagapparaten in een many-to-many model.
• Er zijn grote afstanden overbrugbaar: tot 10 km met fiber optic cables.
• Minder onderbrekingen of storingen bij het toevoegen van nieuwe randapparaten of servers.
Dit kan gerealiseerd worden door een combinatie van extreem snelle verbindingen, hubs en een
ingewikkeld organisatiesysteem binnen een lokaal netwerk van servers en opslagapparaten.
16.11.2
Network-Attached Storage
NAS-systemen bestaan uit NAS heads en standaard opslagmedia. De NAS head werkt als een
interface en kan via standaard data protocols benaderd worden (hoewel het eigenlijk een server is)
over een LAN. Hierdoor kan zeer eenvoudig extra media worden toegevoegd zonder dat de servers
die gebruikmaken van de NAS hier weet van hebben. Ook kan dit NAS-systeem verschillende
RAID-niveaus implementeren.
16.11.3
iSCSI Storage Systems
Internet SCSI (Small Computer System Interface) is een derde methode om opslag van veel
data eenvoudiger te maken. Concreet gebruikt iSCSI het standaard SCSI-protocol om data aan te
spreken, dit protocol wordt ingekapseld in een ander protocol.
Er zijn tegenwoordig 3 veelgebruikte methodes: IP, Fiber Channel over IP (FCIP) en Fiber
Channel over Ethernet (FCoE). De data kan zich zo over het internet (IP), fiber interface (FCIP) of
ethernet (FCoE) verplaatsen. Opnieuw kan zo de storage door een ander systeem beheerd worden en
uitgebreid worden indien nodig. Dit is goedkoper en er kunnen lange afstanden overbrugd worden.
82
Hoofdstuk 17
Database File Indexing Techniques,
B-Trees, and B+-Trees
We gaan ervan uit dat er al een primary access structure bestaat zoals beschreven in het vorig
hoofdstuk. In dit hoofdstuk hebben we het dan over indexes die secondary access paths voorzien
om het zoeken op verschillende criteria te vergemakkelijken. In tegenstelling tot de primary access
structure veranderen deze indices de fysische plaatsing van records of files niet. De indices maken
het zoeken op indexing fields van records gemakkelijker.
17.1
Types of Single-Level Ordered Indexes
Een index op een bestand is een gegevensstructuur die de toegang op dat bestand via een bepaald
veld (het indexing field) effici¨enter maakt. Het laat dus toe effici¨ent te zoeken naar een bepaalde
waarde van dat veld. De index is gesorteerd op dat veld waardoor binary search mogelijk wordt.
Een index kan opgeslagen zijn in het centraal geheugen of in een bestand in het externe geheugen.
17.1.1
Primary Indexes
Een primary index op een bestand is een gegevensstructuur met fixed-length records, fysisch
geordend volgens het eerste veld. Er is 1 index entry voor elk fysisch blok in het bestand:
<K(i), P (i)>. Het eerste veld bevat de ordering key van het eerste record uit dat blok (het anchor
record). Het tweede veld bevat een pointer naar dat blok.
Een primary index is een sparse index: het heeft entries voor sommige zoekwaarden. Een
dense index daarentegen heeft een entry voor elke zoekwaarde.
Het opbouwen van een primary index heeft grote voordelen in het aantal block accesses dat
moet gebeuren voor een zoekopdracht. Als dr / bfre = b (met r het aantal records en b het aantal
blokken), dan zijn er voor een primary index slechts log2 dri / bfri e = log2 (bi ) accesses nodig (met ri
het aantal entries, bfri de blocking factor van de index en bi het aantal blokken van de index).
Een primary index bevat kleinere en minder records dan het gegevensbestand. Het doorlopen van de
index gaat dus sneller dan het doorlopen van het gegevensbestand en er is dus minder schijftoegang
nodig.
Het toevoegen of weglaten van gegevens is echter veel ingewikkelder: we moeten het gegevensbestand en de index aanpassen (de ankerrecords). Overflow blocks zijn een oplossing voor het
toevoegen. Voor het weglaten van gegevens kan men de weggelaten records gewoon markeren. Na
een tijdje is er toch sowieso een reorganisatie nodig.
83
17.1.2
Clustering Indexes
Als een bestand geordend is op een non-key field (dat niet voor elk record uniek is), wordt dat
veld het clustering field genoemd en het gegevensbestand een clustered file. Voor zo’n bestand
kunnen we een clustering index opstellen.
Per unieke waarde van het clustering field is er 1 wijzer naar het blok waarin het eerste record
met die waarde voorkomt. Deze index is ook sparse.
Bij het toevoegen van een record, kan het gebeuren dat records fysisch 1 plaats opschuiven in de
blokken, hierdoor moeten soms ook blokadressen in de index veranderd worden. Dit kan opgelost
worden door aparte fysische blokken te gebruiken voor aparte waarden van het clustering field.
17.1.3
Secondary Indexes
Een secondary index is niet gebaseerd op het veld dat de ordening van het bestand bepaalt maar
wel op een ander veld. De index zelf is wel geordend op dat andere veld. Voor 1 gegevensbestand
kunnen er meerdere secondary indexes bestaan, telkens voor een ander veld.
Er zijn meerdere technieken mogelijk, afhankelijk van de situatie.
• Voor een veld met unieke waardes (secondary key), de index is gesorteerd op dat veld. De
index is tevens dense.
– Index met wijzers naar records: onmiddellijk vindbaar.
– Index met wijzers naar blokken: lineair zoeken binnen het blok.
• Voor een veld met niet-unieke waardes (deze mogen onsorteerbaar zijn).
– Dense index: elk record staat in de index, dubbele waardes zijn toegestaan in de index.
– Index met variable-length records: per unieke waarde een lijst wijzers naar de blokken
waarin de waarde voorkomt.
– Index met per unieke waarde een wijzer naar een blok met daarin wijzers naar de records.
17.2
Multilevel Indexes
Om nog minder block accesses bij elke zoekopdracht te behalen, kunnen we gebruik maken van
multilevel indexes. Dit betekent dat we de index zelf gaan indexeren. Een index kan immers
gezien worden als een geordend bestand waarop een index kan gebouwd worden. Dit kunnen we
blijven herhalen tot de top level index nog maar 1 blok groot is.
De first level index is de index van het geordend gegevensbestand. Dit kan elk type index zijn
zolang de index enkel unieke waardes heeft.
Een indexed sequential file heeft een multilevel primary index op de ordering key.
De blocking factor bfri van de index is even groot voor alle indices en wordt ook wel de fan-out
(fo) van de multilevel index genoemd. Om te berekenen hoeveel levels ernodig zijn als we weten
dat er r1 entries zijn in het eerste level, bestaat de volgende formule: t = logfo (r1 ) .
Bij het doorzoeken van een multilevel index gebeuren er ongeveer logfo (bi ) block accesses als bi
het aantal blocks van de first level index is. Dit is meestal beter dan de log2 (bi ) block accesses die
nodig zijn bij het binair zoeken in de index.
Het verwijderen van records gebeurt door ze te markeren, het toevoegen gebeurt met overloopgebieden. Zo’n overloop werkt vertragend en verkwist ruimte, er is ook af en toe een reorganisatie
nodig. Bij een reorganisatie wordt het hele bestand sequentieel doorlopen en herschreven naar een
nieuw bestand, daarna wordt een nieuwe index gebouwd op dat nieuwe bestand.
84
17.3
Dynamic Multilevel Indexes Using B-trees & B+-Trees
Het maken van indices met een statische structuur geeft vaak problemen bij het toevoegen of
weglaten van records. Elk niveau van de indexboom is fysisch geordend, daarom moet de hele
boom van indices aangepast worden als een record toegevoegd of verwijderd moet worden. Daarom
bekijken we nu indices die met dynamische structuren opgebouwd worden.
17.3.1
Search Trees and B-trees
Een search tree van orde p is een zoekboom met de volgende karakteristieken. Elke node in
de zoekboom bevat maximaal p − 1 zoekwaarden en p pointers naar child nodes. Elke node kan
voorgesteld worden als <P1 , K1 , P2 , K2 , . . . , Pq−1 , Kq−1 , Pq > met q 6 p. Hier is Pi een pointer naar
een child node en Ki een zoekwaarde.
Op de zoekboom moeten de volgende 2 voorwaarden te allen tijde gelden.
1. Binnen elke node geldt: K1 < K2 < · · · < Kq−1

 Ki−1 < X < Ki
X < Ki
2. Voor elke waarde X waarnaar Pi verwijst, geldt:

Ki−1 < X
als 1 < i < q
als i = 1
als i = q
Om nu een bepaalde waarde X te zoeken, volgen we recursief een reeks pointers Pi volgens de
tweede voorwaarde hierboven. Als Kr−1 < X < Kr , moeten we dus verder zoeken via pointer Pr .
Een zoekboom heeft echter enkele problemen als ze niet gebalanceerd is, in dat geval is het
zoeken vaak ineffici¨ent. Door het invoegen of verwijderen van nodes kan er ook veel plaats verspild
worden en zal de zoekboom nog meer ongebalanceerd worden.
Zie figuren 17.8 en 17.9 op pagina 630 voor voorbeelden.
Een oplossing voor deze problemen zijn B-trees. Zo’n zoekboom legt extra vereisten op aan zijn
nodes zodat de B-tree veel beter gebalanceerd is.
Een B-tree van orde p moet voldoen aan de volgende vereisten.
1. Interne nodes hebben < P1 , <K1 , P r1 >, P2 , <K2 , P r2 >, . . . , Pq−1 , <Kq−1 , P rq−1 >, Pq >
als vorm met q 6 p. Een Pi is een tree pointer en een P ri is een data pointer.
2. Binnen elke node geldt K1 < K2 < · · · < Kq−1 .

 Ki−1 < X < Ki
X < Ki
3. Voor elke waarde X waarnaar Pi verwijst, geldt:

Ki−1 < X
4. Elke node heeft hoogstens p tree pointers.
als 1 < i < q
als i = 1
als i = q
5. Elke node (behalve de wortel en de bladeren) heeft minstens dp/2e tree pointers. De wortel
heeft minstens 2 tree pointers (tenzij het de enige node is).
6. Een node met q tree pointers (met q ≤ p) heeft q − 1 zoekwaarden (Ki ).
7. Alle bladeren (leaf nodes) staan op hetzelfde niveau.
Bij het toevoegen van een waarde in een volle node (dus q = p), moet deze node in 2 gesplitst
worden. Bij het verwijderen van een waarde uit een node die half vol zit (dus dp/2e), moet deze
node samengevoegd worden met naburige nodes.
Deze twee operaties moeten af en toe gebeuren om ervoor te zorgen dat de B-tree aan de
vereisten voldoet. Ze kunnen meerdere malen na elkaar worden toegepast ze elders een nieuw
probleem veroorzaken. Als een probleem zich blijft voordoen in de wortel, kan er een nieuw niveau
toegevoegd of verwijderd worden.
85
Bij een willekeurig aantal invoegingen en verwijderingen, zit een B-tree gemiddeld 69% vol. Dit
is een beperkte verspilling van geheugen, een B-tree is ook redelijk gebalanceerd. B-trees worden
gebruikt als primaire bestandsorganisatie, dus van het bestand zelf en niet voor een index. Ze zijn
enkel goed bruikbaar als het bestand weinig records bevat en als deze records klein zijn.
Als er ge¨ındexeerd wordt op een niet-sleutelveld, wijst de data pointer naar een blok met adressen
zoals bij de secondary indexes. Dit zorgt dus voor een extra indirectie.
Een B-tree bevat op niveau i minstens 2 di−1 knopen, dit zijn dus 2 (d − 1) di−1 zoekwaarden
.
(met d = dp/2e). Dit betekent dat de hoogte h van een B-tree bepaald wordt door h 6 logd n+1
2
17.3.2
B+ -Trees
B+ -trees zijn een variatie van B-trees. Bij het doorlopen van een B-tree worden interne knopen
vaak opnieuw gelezen, terwijl ze in het centraal geheugen staan. Bij B+ -trees wordt dit opgelost
door de interne knopen enkel sleutels te laten bijhouden, geen wijzers naar records.
De adressen van records staan dus enkel in de bladeren (leaf nodes). De orde pi van de interne
knopen is hierdoor groter, dit zorgt voor betere prestaties. De orde van de bladeren kan hoger zijn
dan die van de interne knopen.
Voor de interne knopen gelden bijna dezelfde vereisten als bij de B-tree, enkel vereisten 1 en 3
zijn lichtjes anders. Vereiste 7 geldt hier uiteraard niet.
1. Elke interne knoop is van de vorm <P1 , K1 , P2 , K2 , . . . , Pq−1 , Kq−1 , Pq >

 Ki−1 < X 6 Ki
X 6 Ki
3. Voor elke waarde X waarnaar Pi verwijst, geldt:

Ki−1 < X
met q 6 p.
als 1 < i < q
als i = 1
als i = q
Voor de bladeren stellen we de volgende vereisten.
1. Elk blad is van de vorm < <K1 , P r1 >, <K2 , P r2 >, . . . , <Kq−1 , P rq−1 >, Pnext > met q 6 p.
Pnext verwijst naar het volgende blad in de B+ -tree. Hierdoor kan je de bladeren makkelijk in
volgorde doorlopen als een linked list.
2. Binnen elke node geldt K1 6 K2 6 · · · 6 Kq−1 .
3. Elke data pointer P ri wijst naar een record (wiens zoekwaarde gelijk is aan Ki ) of naar een
blok met daarin het record. Als het zoekveld geen sleutelveld is, kan P ri ook wijzen naar een
blok met adressen zoals bij de secondary indexes.
4. Elk blad heeft minstens dp/2e waarden.
5. Alle bladeren staan op hetzelfde niveau.
Om een record met sleutel K toe te voegen aan een B+ -tree, voeg je de sleutel toe aan het blad
waarbij de sleutel hoort. Als het blad al vol is, splits je het blad in 2 kinderen en verdeel je de
elementen over deze kinderen. Je voegt de sleutel toe aan het juiste blad en past de Pnext aan.
Daarna voeg je de laatste waarde (sleutel) van blad 1 toe aan de ouderknoop. Als deze ouderknoop vol is, herhaal je dit proces (maar dan met interne knopen).
Om een record met sleutel K te verwijderen, zoek je het blad met de sleutel en verwijder je de
sleutel daaruit. Als de sleutel in de interne knopen voorkomt, vervang je hem door de waarde er
net links van.
Als er onderloop (te weinig waarden) in een blad is, steel je enkele waarden van een naburig blad
(en pas je de ouderknoop aan). Eventueel kan je ook 2 bladeren samenvoegen. Als er onderloop in
een interne knoop is, kan je de waarden herverdelen of interne knopen samenvoegen.
86
Er bestaan ook B∗ -trees, het enige verschil met een B+ -tree is dat een knoop niet minstens halfvol
moet zijn maar minstens 32 vol. Er wordt dan pas gesplitst als 2 naburige knopen vol zijn.
Bij andere systemen wordt met een fill factor gewerkt die tussen 0.5 en 1.0 ligt. Nog andere
systemen laten toe dat een interne knoop leeg kan worden of hebben een andere beperking voor
interne knopen en bladknopen.
17.4
Indexes on Multiple Keys
We proberen nu op 2 velden (v1 en v2 ) tegelijk te selecteren met condities c1 en c2 . Eerst geven we
2 na¨ıeve oplossingen waarna we betere oplossingen gaan overlopen.
• Als er een index op v1 bestaat, selecteer daaruit de elementen die voldoen aan c1 . Uit die set
van kandidaten neem je dan enkel de records die voldoen aan c2 . Dit werkt uiteraard ook in
de andere richting (als er een index op v2 bestaat).
• Als er indices bestaan voor v1 en voor v2 , maak dan 2 sets die voldoen aan de condities c1 en
c2 . De oplossing wordt dan bepaald door de gemeenschappelijke records uit die 2 sets.
17.4.1
Ordered Index on Multiple Attributes
Als we vaak zoeken naar een combinatie van v1 en v2 , kan men een index maken die als key een
tupel <v1 , v2 > heeft. Hierbij wordt dan eerst op v1 en dan op v2 gesorteerd (in de tupel).
17.4.2
Partitioned Hashing
Als er geen range queries nodig zijn (als we dus enkel op gelijkheid checken), is partitioned
hashing een goede kandidaat. Hierbij wordt elk attribuut apart gehasht waarna de resultaten
van de hashfuncties samengevoegd worden: h(c1 )h(c2 ). De samengevoegde hash wijst dan naar de
bucket met records die aan beide voorwaarden voldoen.
Deze techniek kan ook met meerdere attributen toegepast worden.
Een extra voordeel is dat het ook redelijk gemakkelijk is om op 1 attribuut te selecteren (in dit
voorbeeld het eerste attribuut). Je moet dan namelijk alle buckets afgaan die beginnen met de hash
van de eerste conditie: h(c1 )h(∗).
17.4.3
Grid Files
Grid files zetten de twee attributen uit in een matrix. Per rij wordt er een specifiek interval van
v1 bepaald en per kolom ook een specifiek interval van v2 . Daarna zetten we wijzers naar buckets
op de juiste plaatsen in de matrix. Een wijzer wijst naar een bucket waarin alle records zitten die
behoren tot het interval van die rij (voor v1 ) en behoren tot het interval in die kolom (voor v2 ).
17.5
Other Types of Indexes
17.5.1
Hash Indexes
Zoals besproken in het vorige hoofdstuk, kunnen we ook hash indexes gebruiken als secundary
access structure. Dit werkt analoog aan de besprekingen hierboven, met als enige uitzondering dat
er een ander veld gekozen wordt als indexveld.
87
17.5.2
Bitmap Indexes
Een bitmap index maken gaat als volgt. Per mogelijke waarde van het attribuut maken we een
entry in de bitmap index en overlopen dan alle records in volgorde. Als bij een record de waarde
voor het attribuut gelijk is aan de waarde bij de entry, schrijven we een 1 bij die entry, in het
andere geval een 0. Zo krijgt men per mogelijke waarde (entry) een opeenvolging van bits die voor
elk record zeggen of dat record die waarde bevat.
Deze techniek is enkel effici¨ent als er v´e´el meer records dan mogelijke waarden bestaan. Het
verwijderen van een record zorgt voor overhead maar die kan beperkt worden door een existence
bitmap te maken die bijhoud of een record nog bestaat.
Op dezelfde manier kan voor de bladeren van een B+ -tree ook een bitmap worden gemaakt. Als
bepaalde zoekwaarden heel vaak voorkomen is de lijst met records bij die waarde zeer lang. Daarom
kan het dan dus handig zijn om bij zo’n zoekwaarde een bitmap op te slaan die weergeeft of records
bij die waarde horen.
17.5.3
Function-Based Indexing
In plaats van een index te maken van waarden van een attributen, passen we een functie toe op die
attributen en maken een index op basis van die functiewaarden.
17.6
Some General Issues Concerning Indexing
17.6.1
Logical versus Physical Indexes
Een physical index bevat bij elke verwijzing naar een record het fysische adres van dat record op
de schijf. Dit heeft als nadeel dat als het record wordt verplaatst, men de index moet aanpassen.
Om dit op te lossen wordt er vaak gebruik gemaakt van een logical ndex. Voor elke fysische
plaats van een record, is er in deze index een entry die een zekere code als index key heeft. In de
rest van het systeem wordt dan met de key van de logical index verwezen naar de records.
17.6.2
Discussion
Vaak worden indices dynamisch aangemaakt (dus als het nodig is), daarom wordt een index vaak
een access structure genoemd.
Met indices kan men ook key constraints op een attribuut controleren. Als er een nieuw record
wordt toegevoegd, dan wordt er meteen ook gecheckt of deze constraint geldt en kan het invoegen
worden verworpen.
Duplicaten kunnen voor problemen zorgen in een DBMS daarom wordt er soms aan de primaire sleutel ook het rijnummer van het record toegevoegd. Op die manier is elk record uniek te
identificeren en kunnen duplicaten bovendien makkelijk worden afgehandeld.
Een fully inverted file is een bestand dat op elk attribuut van de records is ge¨ındexeerd.
Virtual Storage Access Method (VSAM) is nog een systeem van IBM dat tegenwoordig
in veel commerci¨ele systemen terug te vinden is.
17.6.3
Column-Based Storage of Relations
Een ander systeem voor een DBMS is column-based storage. Voor sommige toepassingen is dit
veel effici¨enter dan row-based, meestal gebruiken deze toepassingen vooral read-only operaties. Men
kan dan beter indexeren op enkel de nodige informatie (dus met column-based storage).
88
Hoofdstuk 18
Introduction to Query Processing and
Query Optimization Techniques
In dit hoofdstuk worden de technieken uitgelegd die een DBMS gebruikt om een hoogniveau query
te verwerken, optimaliseren en uit te voeren. Een DBMS heeft heel wat onderdelen die met queries
te maken hebben.
De scanner identificeert de query tokens, in SQL zijn dit de keywords, attribuut- en relatienamen. De parser controleert of de query aan de regels van de query syntax voldoet. De validator
controleert of alle attribuut- en relatienamen geldig zijn. Een query tree of query graph is de
inwendige structuur waarin de query wordt bijgehouden.
De execution strategy (of query plan) wordt door het DBMS gebruikt om de resultaten van
de query uit de database te halen. Er zijn meestal meerdere strategie¨en, het proces om een geschikte
uitvoeringsstrategie te zoeken wordt query optimization genoemd. De query optimizer moet
een goede uitvoeringsstrategie kiezen.
De code generator genereert de code om de uitvoeringsstrategie uit te voeren. De runtime
database processor moet de de query code uitvoeren en hiermee de resultaten opvragen.
Op figuur 18.1 op pagina 660 staan de stappen van het verwerken van een query.
18.1
Translating SQL Queries into Relational Algebra
Een SQL query wordt eerst omgezet naar een equivalente extended relational algebra expression en
wordt dan geoptimaliseerd (omdat in SQL de volgorde van bewerkingen minder vastligt).
Meestal wordt een SQL query eerst onderverdeeld in query blocks. Een query block bestaat
uit een enkele select–from–where-uitdrukking. Group by en having zijn ook onderdeel van
de query block als deze voorkomen in de uitdrukking. Geneste SQL queries worden beschouwd als
aparte query blocks.
18.2
Algorithms for External Sorting
Sorteeralgoritmen worden vaak gebruikt bij het verwerken van queries. Ze moeten bijvoorbeeld
gebruikt worden bij een order by-clausule van een SQL query. Andere situaties waarbij sorteeralgoritmen gebruikt worden zijn join, union, intersection en project (om duplicaten te
verwijderen als distinct geslecteerd wordt).
External sorting: sorteeralgoritmes die gebruikt worden bij het sorteren van grote bestanden die
bestaan uit records (op een harde schijf). Voor deze algoritmes wordt de sort-merge strategy
gebruikt: eerst worden kleine subfiles gesorteerd, later worden deze samengevoegd (merge).
89
Er is een buffer space nodig om het sorteren en het mergen uit te voeren. De buffer space in het
main memory is onderdeel van de DBMS-cache. De buffer space is onderverdeeld in individuele
buffers die elk even groot zijn en elk juist 1 disk block kunnen bevatten.
In de sorteerfase worden runs (kleine delen van het bestand die in de buffer space passen) in
de buffer geladen, gesorteerd met een intern sorteeralgoritme en dan weer weggeschreven naar de
schijf als tijdelijk bestand. Dit wordt herhaald tot het volledige bestand is overlopen.
In de mergefase worden de runs samengevoegd in 1 of meer merge passes tot er maar 1
gesorteerd bestand overblijft. Elke merge pass kan bestaan uit verschillende merge steps. De
degree of merging wordt bepaald door het aantal runs dat samengevoegd wordt bij elke merge
step. Tijdens elke merge step is er een buffer nodig voor elke run (deze bevat dan een disk block
van de run). Er is ook nog een extra buffer nodig met het resultaat van de merge step.
Zij b het aantal blokken en nB het aantal vrije buffers, dan heeft het sort-merge algoritme exact
nR = db / nB e runs nodig.
In de mergefase is de degree of merging dM gelijk aan het aantal deelbestanden (runs) die ineens
samengevoegd kunnen worden, dus dM = nB − 1. Het aantal passes is gelijk aan dlogdM nR e. De
mergefase heeft dus een complexiteit van 2 · b · logdM (nR ).
In de sorteerfase wordt elk blok 1 keer ingelezen en 1 keer weggeschreven: 2 · b.
Dit geeft een totale complexiteit van 2 · b + 2 · b · logdM (nR ).
In figuur 18.2 op pagina 664 staat de pseudocode voor het sort-merge algoritme.
18.3
Algorithms for SELECT and JOIN Operations
18.3.1
Implementing the SELECT Operation
Search methods for simple selection
Deze zoekmethodes scannen alle records om records te vinden die aan het selectiecriterium voldoen.
S1 Lineair search (brute force). Doorloop elke record in de file op zoek naar matches.
S2 Binary search. Enkel mogelijk als de conditie een equality comparison (“=”) gebruikt op
een sleutelattribuut waarop het bestand geordend is.
S3 Using a primary index or a hash key. Enkel mogelijk als de conditie een equality
comparison gebruikt op een sleutelattribuut dat een primary index of een hashfunctie heeft.
Dit zoekalgoritme is effectief voor point queries. Er wordt altijd maar 1 record opgehaald.
S4 Using a primary index to retrieve multiple records. Dit wordt gebruikt als de conditie
een ongelijkheid uit {<, 6, >, >} gebruikt en als er gezocht wordt op een sleutelattribuut met
een primary index.
S5 Using a clustering index to retrieve multiple records. Enkel mogelijk als de conditie
een equality comparison gebruikt op een niet-sleutelattribuut dat de ordening bepaalt.
S6 Using a secondary (B+ -tree) index on an equality comparison. Dit geeft 1 record
terug als het indexing field een sleutelattribuut is (met “=”), bij niet-sleutelattributen geeft
het meerdere records terug. De conditie kan bestaan uit {=, <, 6, >, >}.
Index searches: methodes die een index gebruiken, dus S3, S4, S5 en S6.
Range queries: queries waarbij de conditie een vergelijking uit {<, 6, >, >} gebruikt.
90
Search methods for complex selection
Deze zoekalgoritmen zijn bedoeld voor queries met een conjunctieve conditie. Een conjunctieve
conditie bestaat uit simpele deelcondities die zijn samengevoegd met AND.
S7 Conjunctive selection using an individual index. Indien er voor 1 van de simpele deelcondities een van de methodes S2 – S6 bruikbaar is, selecteer dan eerst volgens die deelconditie.
Test hierna voor elk gevonden record de andere deelconditie(s).
S8 Conjunctive selection using a composite index. Dit is enkel mogelijk als er voor 2 of
meer attributen een “=”-deelconditie gebruikt wordt en als er een samengestelde index op die
attributen bestaat.
S9 Conjunctive selection by intersection of record pointers. Mogelijk met secundaire
indexen die recordpointers bevatten (geen blokpointers). Voor elke “=”-conditie op een secundair ge¨ındexeerd attribuut wordt de verzameling van recordpointers opgehaald. Uit de
doorsnede van al die verzamelingen worden enkele records opgehaald. De andere condities
worden dan getest op deze records om zo de records weg te filteren die niet aan de query
voldoen.
Deze methode werkt enkel voor attributen die geen sleutelattribuut zijn. Het grote voordeel
is dat een groot deel van het selectiewerk enkel op indices moet gebeuren.
Selectivy sl of a condition: de verhouding van het aantal records dat aan de conditie voldoen
tegenover het totaal aantal records in het bestand. Schattingen van deze waarden worden soms
bijgehouden in de DBMS en gebruikt door de optimizer.
Als er bij een selectie met een conjunctieve conditie (S7, S8 of S9) meerdere toegangspaden
beschikbaar zijn, moet de conditie met de laagste selectiviteit sl als eerste gekozen worden. Men
kan ook schattingen van sl uit de catalogus gebruiken.
Een selectie met een disjunctieve conditie is moeilijker te optimaliseren, elke deelconditie moet
volledig getest worden. Als een deelconditie geen toegangspad heeft, moet er lineair gezocht worden.
Het gebruiken van indexen voor de andere indexen is dan niet meer zinvol.
18.3.2
Implementing the JOIN Operation
De dure join-operatie kan op verschillende manieren ge¨ımplementeerd worden. De methodes hieronder zijn bedoeld voor een 2-way join (2 bestanden joinen) van de vorm R ./A=B S.
J1 Nested-loop join (or nested-block join). Dit is de brute force manier om een joinoperatie uit te voeren. Voor elk record t in R en voor elk record s in S wordt er gecontroleerd
of er voldaan is aan de join-conditie t[A] = s[B].
Als bestand in de buitenste lus kiest men best het bestand met het kleinste aantal fysische
blokken.
J2 Single-loop join (using an access structure to retrieve the matching records). Voor
1 van de 2 attributen bestaat er een index of hash key, stel attribuut B van S. Ga dan alle
records t in R af en gebruik de index of hash key van s (dus s[B]) als zoekwaarde om snel te
controleren of er voldaan is aan t[A] = s[B].
Als bestand in de buitenste lus kies men best het bestand met een hoge join-selectiefactor zodat
weinig onnodige records opgezocht worden. De join-selectiefactor van R m.b.t. R[A] = S[B]
is het aantal records van S dat gemiddeld overeenkomt met een record van R.
91
J3 Sort-merge join. Als R gesorteerd is volgens A en als S gesorteerd is volgens B, dan is een
join mogelijk door 1 keer A en B lineair te doorlopen. Dit is uiteraard zeer effici¨ent. Als de
bestanden niet geordend zijn, kan men ze best sorteren, dit is nog steeds effici¨ent.
Deze methode is ook mogelijk met secundaire indexen: A en B kunnen in volgorde doorlopen
worden dankzij de index. Het probleem is dat de records zelf verspreid zijn in het bestand, er
moeten dus voortdurend andere blokken ingelezen worden. Dit kan soms ineffici¨ent zijn.
J4 Partition-hash join. A en B worden gehasht volgens dezelfde hashfunctie. Stel R heeft het
kleinste aantal records. Er wordt een nieuw hashbestand aangemaakt en alle records van R
worden gehasht en in buckets geplaatst. Daarna wordt elk record van S overlopen en wordt
er gecontroleerd in welke bucket het record zou komen. In die bucket wordt dan naar de
overeenkomstige records van R gezocht.
In een uitgebreidere versie kan men eerst de bestanden partitioneren met de hashfunctie
zodat men bestanden krijgt die volledig in het intern geheugen passen. Die bestanden worden
dan per 2 aan elkaar gejoind met eender welke join-methode tot alle gejoinde bestanden aan
elkaar hangen. Als men voor het joinen de methode J4 wil gebruiken, moet men een andere
hashfunctie gebruiken.
De hybrid hash-join is een variant van de partition-hash join waarbij een deel van de join-fase
al tijdens de partitiefase gebeurt. E´en van de tijdelijke hashbestanden blijft permanent in het
geheugen, zo worden 2 tijdelijke bestanden uitgespaard.
18.4
Algorithms for PROJECT and Set Operations
Project – Als de attributenlijst van de projectie π<attributenlijst> (R) een sleutel van R bevat, bevat
het resultaat evenveel tupels als R. In het andere geval moeten eventuele dubbels verwijderd worden
door sortering (dubbels komen dan achter elkaar voor) of hashing. In het laatste geval voeg je een
tupel toe aan het resultaat als diens hashwaarde niet voorkomt in de hashtabel
Cartesian product – De operatie om het Carthesisch product te berekenen is zeer duur. Voor
elke combinatie van 2 records moet er namelijk een nieuw record worden aangemaakt. Deze operatie
wordt best vermeden, ze kan het best vervangen worden door equivalente operaties tijdens de
optimalisatie.
Union, intersection en set difference – Deze operaties zijn enkel van toepassing op type
compatible relaties, deze relaties hebben hetzelfde aantal attributen met bovendien dezelfde domeinen voor elk attribuut. Deze operaties worden ge¨ımplementeerd door een aangepaste versie van
het sort-merge algoritme. De 2 relaties worden eerst gesorteerd volgens dezelfde attributen. Hierna
kan elke relatie 1 keer lineair doorlopen worden om het gewenste resultaat te bepalen.
Er kan ook hashing gebruikt worden voor deze operaties. De eerste relatie wordt gehasht naar een
in-memory hashtable van buckets. De records van de andere relatie worden dan 1 voor 1 doorlopen,
de hashwaarde van zo’n record bepaalt dan in welke bucket je moet zoeken naar overeenkomstige
records uit de eerste relatie.
In SQL worden er varianten van de hierboven beschreven methoden gebruikt voor de operaties
op verzamelingen: union all, intersection all en except all.
92
18.5
Implementing Aggregate Operations and
OUTER JOINs
18.5.1
Implementing Aggregate Operations
De aggregatie-operaties min en max kunnen simpel berekend worden als er een dense index
bestaat voor het te controleren attribuut. Het resultaat kan dan uit de index berekend worden. Bij
min wordt telkens de meest linkse pointer in de B + -boom gevolgd, bij max steeds de meest rechtse.
Voor de operaties average, sum en count moet de index wel een dense index zijn, de
bladeren van de boom worden dan doorlopen en het resultaat wordt berekend.
De count(*)-operatie kan ook uit de catalogus gehaald worden, de catalogus houdt namelijk
bij hoeveel records een relatie heeft.
Voor een group by-operatie moeten de aggregatie-operaties apart worden toegepast voor elke
groep. Het partitioneren van het bestand in de juiste groepen kan gedaan worden door de records
eerst te sorteren of te hashen en daarna voor elke groep apart de operatie berekenen. Als er
een clustering index bestaat voor de attributen waarop gegroepeerd moet worden, moet er niet
gesorteerd of gehasht worden.
18.5.2
Implementing OUTER JOINs
Outer joins kunnen berekend worden door 1 van de join-algoritmen aan te passen. Als er
bijvoorbeeld een left outer join berekend moet worden, dan worden niet enkel de records
bijgehouden die een match vormen, maar ook de records van de linkse relatie. De records die niet
matchen worden dan aangevuld met NULL-waarden.
Men kan ook eerst een inner join berekenen en het resultaat aanvullen met de tupels die niet
in de inner join voorkomen (aangevuld met NULL-waarden).
18.6
Combining Operations Using Pipelining
Omdat een query meestal uit meerdere relationele operaties bestaat, zullen er veel tijdelijke bestanden aangemaakt worden voor elke opeenvolgende relationele operatie.
Bij pipelining of stream-based processing worden meerdere operaties in 1 algoritme gecombineerd. Zo wordt het resultaat van operatie 1 niet naar een tijdelijk bestand geschreven maar
wordt het resultaat direct doorgegeven als invoer aan operatie 2. Zo ontstaat er een stroom van
gegevens tussen de operaties (algoritmen): een pijplijn.
18.7
Using Heuristics in Query Optimization
Om de prestaties van het uitvoeren van queries te verbeteren, worden er heuristieken toegepast om
de interne weergave van de query (de query tree) aan te passen. De initial query representation
wordt aangepast met heuristieken tot de optimized query representation, deze komt overeen
met de query excecution strategy. Hiermee wordt een query excecution plan opgesteld die groepen
operaties uitvoert, gebaseerd op de beschikbare toegangspaden.
Een belangrijke heuristieke regel stelt dat select- en project-operaties uitgevoerd moeten
worden voordat de binaire operaties uitgevoerd worden. Dit komt omdat select en project de
grootte van het te controleren bestand sterk verminderen.
93
18.7.1
Notation for Query Trees and Query Graphs
In een query tree worden relaties uit de query voorgesteld als bladeren en operaties als interne
knopen. Bij het uitvoeren van een query wordt een interne knoop uitgevoerd van zodra diens
operanden beschikbaar zijn. De interne knoop wordt dan vervangen door de uitvoer van de operatie.
De uitvoer begint bij de bladeren en eindigt bij de wortel.
Een query graph is een neutralere voorstelling van een query omdat er geen specifieke volgorde
is waarin de operaties moeten worden uitgevoerd. In een query graph worden relaties voorgesteld
als relation nodes (enkele rand). Constante waarden (meestal van de selectiecondities) worden
voorgesteld door constant nodes (dubbele rand). Selectie- en join-condities worden voorgesteld als
edges. Attributen die moeten worden opgevraagd, zijn weergegeven tussen vierkante haakjes.
Uit studies is gebleken dat query trees een betere voorstelling zijn dan query graphs omdat de query
optimizer de volgorde van de operaties moet kunnen weergeven.
Figuur 18.4 op pagina 682 geeft voorbeelden van query trees en een query graph.
18.7.2
Heuristic Optimization of Query Trees
Een query kan door verschillende query trees voorgesteld worden. Al deze query trees worden
equivalent genoemd. De query parser maakt meestal de initial query tree die zelden direct
uitgevoerd wordt. Eerst zal de heuristic query optimizer de tree optimaliseren naar een final
query tree die veel effici¨enter is om uit te voeren.
General transformation rules for relational algebra operations
Hieronder staan enkele algemene regels om transformaties op queries uit te voeren die gebruikt
worden bij het optimaliseren van de query tree.
1. Cascade of σ. Een conjunctieve selectieconditie kan omgezet worden in een cascade (opeenvolging) van individuele σ-operaties.
σc1 ∧ c2 ∧ ... ∧ cn (R) ≡ σc1 (σc2 ( . . . ( σcn (R) ) . . . ) )
2. Commutativity of σ.
σc1 ( σc2 (R) ) ≡ σc2 ( σc1 (R) )
3. Cascade of π. In opeenvolgende projecties moet enkel de laatste projectie behouden worden.
πlist1 (πlist2 ( . . . ( πlistn (R) ) . . . ) ) ≡ πlist1 (R)
4. Commuting σ with π. Dit geldt enkel als het selectiecriterium c enkel slaat op attributen
A1 , A2 , . . . , An uit de projectielijst.
πA1 , A2 , ..., An ( σc (R) ) ≡ σc ( πA1 , A2 , ..., An (R) )
5. Commutativity of ./ (and ×).
R ./c S ≡ S ./c R
R×S ≡S×R
6. Commuting σ with ./ (or ×). Deze regels gelden ook voor ×.
Als c enkel slaat op attributen van R, dan geldt er dat:
σc (R ./ S) = σc (R) ./ S
Als c = c1 ∧ c2 en als c1 en c2 condities zijn die enkel slaan op attributen van R en S, dan
geldt er dat:
σc (R ./ S) = σc1 (R) ./ σc2 (S)
94
7. Commuting π with ./ (or ×). Als alle join-attributen voorkomen in de projectielijst
L = {A1 , . . . , An , B1 , . . . , Bm }, kan de projectie naar binnen geschoven worden.
πL (R ./c S) = ( πA1 , ..., An (R) ) ./c ( πB1 , ..., Bm (S) )
In het andere geval moeten R en S geprojecteerd worden op de join-attributen en de attributen
in de projectielijst. Op het einde moet er dan nogmaals geprojecteerd worden op de gevraagde
attributen. Bijvoorbeeld:
πA (R ./B=C S) ≡ πA ( πA,B (R) ./B=C πA,C (S) )
8. Commutativity of set operations. ∪ en ∩ zijn commutatief, − niet.
9. Associativity of ∪, ∩, ×, and ./. Deze 4 operaties zijn individueel associatief.
10. Commuting σ with set operations. Als θ een operatie uit {∪, ∩, −} voorstelt, geldt er:
σc (R θ S) ≡ σc (R) θ σc (S)
11. The π operation commutes with ∪.
πL (R ∪ S) ≡ πL (R) ∪ πL (S)
12. Converting a (σ, ×) sequence into ./. Dit geldt enkel als de selectieconditie c overeenkomt
met een join-conditie.
σc (R × S) ≡ (R ./c S)
Andere transformaties (zoals de wetten van de Morgan) zijn te vinden in hoofdstukken 4, 5 en 6.
In het algemeen proberen we dus de bladeren en knopen van de query tree te herschikken zodat
de query effici¨enter wordt. We proberen eerst de bewerkingen uit te voeren die de grootte van de
tijdelijke relaties verminderen. Een voorbeeld van een optimalisatie-algoritme met heuristieken zou
er dus als volgt uitzien.
1. Splits complexe selectie-operaties in simpele selecties (meer flexibiliteit bij het herschikken).
2. Schuif selectie-operaties zo ver mogelijk naar beneden (minder relaties).
3. Schuif bladeren waarop een strenge selectie gebeurt, meer naar links (kleinere relaties).
4. Combineer meermaals een Carthesisch product met een selectie-operatie tot een join-operatie.
5. Schuif projecties zo ver mogelijk naar beneden (geen onnodige attributen).
6. Identificeer deelbomen die door 1 algoritme kunnen uitgevoerd worden.
18.7.3
Converting Query Trees into Query Execution Plans
Het uitvoeringsplan wordt voorgesteld als een query tree. Dit plan bevat informatie over de verschillende access methods voor elke relatie en welke algoritmen er gebruikt worden bij het berekenen
van de verschillende operaties.
Bij een materialized evaluation wordt het resultaat van een operatie bewaard als een tijdelijke
relatie, het resultaat wordt dus fysisch gematerialiseerd. Dit is dus het tegenovergestelde van een
pipelined evaluation.
95
18.8
Using Selectivity and Cost Estimates in Query Optimization
Bij compiled queries wordt de optimalisatie gedaan bij het compileren van de query. De strategy
code kan dan direct worden uitgevoerd als het opgeroepen wordt (at runtime).
Als de optimalisatie pas at runtime gebeurt, worden de queries interpreted queries genoemd.
De query optimizer gebruikt niet enkel heuristieken. Het schat ook de kost in voor verschillende
uitvoeringsstrategie¨en. De optimizer moet er wel op toezien dat er niet te veel tijd verloren gaat
bij het inschatten en vergelijken van deze uitvoeringsstrategie¨en.
Cost-based optimalization: er wordt met de traditionele optimalisatietechnieken een oplossing gezocht voor een probleem waarbij de kost om tot die oplossing te komen, is verkleind.
18.8.1
Cost components for Query Execution
1. Het inlezen en wegschrijven van blokken naar het secundair geheugen.
2. Het tijdelijk opslaan van tussenresultaten op het secundair geheugen.
3. Het berekenen van de query in de CPU.
4. Het aantal buffers in het main memory die nodig zijn.
5. De communicatiekosten van het versturen van data tussen de cli¨ent en de server.
Bij grote systemen wordt de nadruk gelegd op het minimaliseren van kosten voor toegang tot het
hulpgeheugen. Bij kleine systemen ligt de nadruk eerder op het verminderen van het rekenwerk.
Bij zeer grote systemen moet er ook rekening gehouden worden met de communicatiekosten.
18.8.2
Catalog Information Used in Cost Functions
Om de kost van een uitvoeringsstrategie te bepalen, moet er bepaalde informatie bijgehouden worden
in de catalog. De volgende eigenschappen worden bijgehouden voor elk bestand: het aantal records
r, de gemiddelde recordlengte R, het aantal bestandsblokken b en de blocking factor bfr.
Er wordt ook bijgehouden op welke manier de bestanden zijn opgesteld (bv. geordend, met een
primary index, . . . ). Als er multilevel indexen gebruikt worden, worden het aantal levels van elk
multilevel index (primary, secondary of clustering) bijgehouden.
Het aantal (d) verschillende waarden dat een attribuut kan hebben en de attribute selectivity
sl (zie 18.3.1) worden ook bijgehouden. Met sl kan een schatting gemaakt worden voor de selection
cardinality s = sl · r van een attribuut. Dit is het gemiddeld aantal records dat voldoet aan een
“=”-selectieconditie op dat attribuut.
De optimizer houdt ook een histogram bij voor attributen waarvan de waarden niet evenwichtig
verdeeld zijn over de records.
18.8.3
Examples of Cost Functions for SELECT
Hieronder staan de functies opgesomd om de kost te bepalen voor de algoritmen uit 18.3.1. De kost
wordt uitgedrukt in het aantal block transfers.
S1 Linear search (brute force) approach. Alle file blocks moeten doorlopen worden, het
aantal block transfers is dan gemiddeld CS1a = b. Als er een “=”-conditie gebruikt wordt op
een sleutelattribuut, is dit gemiddeld CS1b = b/2.
96
S2 Binary search. Er worden ongeveer CS2 = log2 (b) + ds/bfre − 1 file block transfers gedaan.
S3 Using a primary index or hash key to retrieve a single record.
Bij het gebruik van een primary key, haalt het algoritme 1 bestandsblok op per index level
plus nog 1 bestandsblok. Dit geeft dus CS3a = x + 1 blocks met x het aantal index levels.
Bij het gebruik van een hash key, wordt er meestal maar 1 blok opgehaald (voor static en linear
hashing), dus CS3b = 1. Bij extendible hashing (zie 17.8) worden er 2 blokken opgehaald.
S4 Using an ordering index to retrieve multiple records. Als gemiddeld de helft van de
records voldoet aan de conditie, dan is de kost ongeveer CS4 = x + (b/2). Deze schatting kan
sterk verschillen naargelang de verdeling van de waarden voor een bepaald attribuut.
S5 Using an clustering index to retrieve multiple records. Als s de selection cardinality
van het ge¨ındexeerde attribuut is, zullen er ds/bfr e bestandsblokken opgeroepen worden.
Bovendien wordt er ook 1 blok opgehaald voor elk index level. Het totaal aantal opgehaalde
blokken is dan CS5 = x + ds/bfr e.
S6 Using a secondary (B+ -tree) index. Als er een secondary index gebruikt wordt op een
sleutelattribuut, zijn er CS6a = x + 1 bloktoegangen nodig.
Als dit niet voor een sleutelattribuut gebeurt, is het aantal block transfers CS6b = x + 1 + s,
dit is in het slechtste geval waarbij elke record in een aparte blok zit.
Als de operaties {<, 6, >, >} gebruikt worden in de conditie, zal ongeveer de helft van de
first-level index blokken ingelezen worden. Ook de helft van de file records zullen via de index
ingelezen worden. Dit komt dan neer op CS6c = x + (bI1 /2) + (r/2)
S7 Conjunctive selection. De methoden S1 tot en met S6 kunnen hiervoor gebruikt worden.
S8 Conjunctive selection using a composite index. Hiervoor kunnen we de methoden S3a,
S5 of S6b gebruiken, afhankelijk van het type index.
18.8.4
Examples of Cost Functions for JOIN
Om een idee te krijgen van de kost van een join-operatie, wordt er meestal geschat hoeveel records er
zullen zijn na een join-operatie. Deze waarde wordt meestal als de join selectivity js bijgehouden.
Dit is de verhouding van het aantal tupels na een join-operatie tegenover het aantal tupels na een
berekening van het Carthesisch product, kortom:
sl =
|R ./c S|
|R ./c S|
=
|R × S|
|R| · |S|
Als er geen join-conditie c is, geldt er dat sl = 1. In dit geval is de join hetzelfde als het berekenen
van het Carthesisch product.
18.8.5
Multiple Relation Queries and JOIN Ordening
Een left-deep tree is een binaire boom waarin het rechtse kind van elke inwendige knoop altijd
een base relation is. Deze bomen worden gebruikt voor queries met veel join-operaties.
De optimizer kan niet van alle mogelijke query trees voor queries met veel join-operaties, de
kosten inschatten. Dit zou namelijk te veel tijd in beslag nemen. De structuur van de query tree
wordt dan beperkt tot dat van een left-deep tree. Het aantal mogelijke query trees is dan veel
kleiner. De optimizer neemt de left-deep tree met de laagste kost.
Een voorbeeld van een left-deep tree vind je op figuur 18.7 op pagina 698.
97
18.8.6
Example to Illustrate Cost-Based Query Optimization
Op pagina 699-701 wordt er een voorbeeld gegeven om de theorie te illustreren.
18.9
Overview of Query Optimization in Oracle
De Oracle DBMS kent 2 verschillende query optimalisatietechnieken:
• De rule-based optimalisatietechniek kiest een uitvoeringsplan gebaseerd op operaties die
geordend zijn op heuristiek.
• Bij de cost-based optimalisatietechniek kiest de optimizer het toegangspad met de laagste
kost.
De Oracle query optimizer kan ook hints van de gebruiker gebruiken bij de optimalisatie van queries.
18.10
Semantic Query Optimization
Bij deze techniek worden de constraints gebruikt die toegepast worden op het databaseschema.
Indien er bijvoorbeeld gezocht wordt naar werknemers die meer verdienen dan hun baas, kan de
optimizer zien dat er een constraint is die dit voorkomt. Het zou dus niet zinvol zijn om deze query
uit te voeren omdat er toch geen oplossingen zijn. Een nadeel bij deze methode is dat het doorlopen
van alle constraints veel tijd in beslag kan nemen.
98
Hoofdstuk 20
Foundations of Database Transaction
Processing
Een transactie is de uitvoering van een programma dat de database raadpleegt of wijzigt.
Transaction processing systems zijn systemen van grote databases met honderden gebruikers
die gelijktijdig transacties uitvoeren. Zo’n database moet altijd beschikbaar zijn en moet een snelle
responstijd hebben voor alle gebruikers.
20.1
Introduction to Transaction Processing
20.1.1
Single-User versus Multiuser Systems
Een DBMS is single-user als slechts 1 gebruiker per keer het systeem kan gebruiken, meestal op
persoonlijke computers.
Een DBMS is multiuser als meerdere gebruikers het systeem gelijktijdig kunnen gebruiken, dit
is mogelijk dankzij multiprogramming (het OS voert meerdere processen tegelijk uit).
Bij interleaved processing behandelt 1 processor afwisselend verschillende transacties, dit
model gebruiken wij. Bij parallel processing werken meerdere processoren in parallel.
20.1.2
Transactions, Database Items, Read and Write Operations,
and DBMS Buffers
Een transactie is een uitvoerend programma dat een logische eenheid vormt. Het bevat 1 of meerdere
database operaties: insertion, deletion, modification of retrieval.
Een read-only transaction is een transactie die de database niet verandert. In het andere
geval praat men over een read-write transaction (of update transaction).
We bespreken het database model bij transaction processing. De database wordt voorgesteld
als een verzameling van named data items. Een data item kan een record, een disk block of de
waarde van een attribuut van een record zijn. De granularity stelt de grootte van een data item
voor. Elk data item heeft een unieke naam om de data items van elkaar te onderscheiden.
Een transactie kan bestaan uit de volgende basic database operaties.
• read item(X) leest een data item X in en stopt deze in een variabele (meestal ook X).
1. Vind het adres van het fysisch blok dat item X bevat.
2. Kopieer dat blok naar een buffer in main memory (als het er nog niet in zit).
3. Kopieer item X van de buffer naar een programma variabele.
99
• write item(X) schrijft de waarde van een variabele X weg naar een database item X.
1. Vind het adres van het fysisch blok dat item X bevat.
2. Kopieer dat blok naar een buffer in main memory (als het er nog niet in zit).
3. Kopieer de programma variabele X naar de juiste plaats in de buffer.
4. Schrijf het aangepaste blok terug op de schijf (onmiddellijk of later).
Het DBMS houdt een buffer cache bij waarin enkele data buffers zitten. De data buffers zitten in
het main memory en houden elk een database disk block bij. Hierin zitten een aantal database items
die verwerkt worden. Buffers worden vervangen volgens een bepaalde buffer replacement policy.
De read-set van een transactie is de verzameling van alle items die gelezen worden. Items die
weggeschreven worden behoren tot de write-set van een operatie.
20.1.3
Why Concurrency Control Is Needed
Er kunnen verschillende problemen optreden bij het gelijktijdig uitvoeren van transacties.
• The Lost Update Problem. Een database item wordt door meerdere transacties tegelijkertijd gelezen en aangepast waardoor de waarde van het data item niet meer klopt.
• The Temporary Update (or Dirty Read) Problem. Transactie T1 verandert een data
item maar de schrijfoperatie faalt, de waarde van dit data item is nu niet meer correct. Voordat
dit hersteld kan worden, leest transactie T2 de foute waarde in.
• The Incorrect Summary Problem. In transactie T1 wordt een aggregatiefunctie berekend
van een aantal items. Als deze items worden aangepast door een transactie T2 tijdens de
berekening van de aggregatiefunctie, dan zal de uitkomst fout zijn.
• The Unrepeatable Read Problem. De waarde van een data item wordt twee keer kort na
elkaar ingelezen. Tussen deze 2 read-operaties wordt de waarde van het data item aangepast
door een andere transactie. De 2 read-operaties lezen dus verschillende waarden.
Zie figuur 20.3 op pagina 727 voor schematische voorstellingen van deze problemen.
20.1.4
Why Recovery Is Needed
Het DBMS moet ervoor zorgen dat een transactie ofwel volledig wordt uitgevoerd (commited),
ofwel helemaal niet wordt uitgevoerd (aborted). Als een transactie faalt, mag de transactie geen
veranderingen aanbrengen in de database of een effect hebben op andere transacties.
• A computer failure (system crash). Een hardware, software of netwerk fout tijdens de
uitvoering van de transactie.
• A transaction or system error. De transactie faalt door een verkeerde parameter, een
integer overflow, een logische programmeerfout of dergelijke in een operatie.
• Local errors or exception conditions detected by the transaction. Een bepaalde
toestand zorgt ervoor dat de transactie moet worden tegengehouden.
• Concurrency control enforcement. De currency control method stopt een transactie vanwege schending van serializability of om een deadlock op te lossen.
• Disk failure. Een disk block verliest data vanwege een fout bij het lezen of schrijven. Een
head crash of een beschadigd spoor is ook mogelijk.
• Physical problems and catastrophes. Stroom- of koelingsproblemen, brand, diefstal, . . .
100
20.2
Transaction and System concepts
20.2.1
Transaction States and Additional Operations
De recovery manager van het DBMS houdt de toestand van de transacties bij. Op die manier kan
de database hersteld worden als een transactie faalt. De volgende operaties worden bijgehouden.
• begin transaction: het begin van de transactie.
• read of write: alle lees- en schrijfoperaties van een transactie.
• end transaction: de uitvoering van de transactie is gedaan. Er moet nog gecontroleerd
worden dat de wijzigingen ook definitief kunnen worden toegepast op de database (committed )
of dat de transactie gestopt moet worden vanwege concurrency control.
• commit transaction: de transactie is succesvol be¨eindigd, de wijzigingen kunnen worden
toegepast op de database (commit) en kunnen niet ongedaan gemaakt worden.
• rollback (of abort): de transactie is gefaald, alle wijzigingen worden ongedaan gemaakt.
Een transactie kan zich in verschillende toestanden bevinden: active (bij het begin van de transactie), partially committed (na het uitvoeren van de lees- en schrijfoperaties), committed (als
de transactie gelukt is), failed of terminated.
Figuur 20.4 op pagina 730 geeft deze verschillende staten schematisch weer.
20.2.2
The System Log
Het systeem houdt een logbestand bij met daarin alle transacties die invloed hebben op items in
de database. Dit bestand is een sequentieel append-only file zodat het geen last kan hebben van
een of andere failure. Het laatste deel van het bestand wordt in de log buffer in het main memory
gehouden voordat het weggeschreven wordt naar het logbestand op de schijf.
De log records zijn de entries van het logbestand, hierbij is T een transaction-id om elke
transactie een unieke naam te geven, X duidt een database item aan.
• [start transaction, T ]
• [write item, T , X, old value, new value]
• [read item, T , X]
• [commit, T ]
• [abort, T ]
Ofwel wordt de transactie dan volledig ongedaan gemaakt: het logbestand wordt achterwaarts
doorlopen en alle write-operaties worden ongedaan gemaakt (undo).
Ofwel wordt de transactie volledig afgewerkt en proberen we de write-operaties te herstellen: het
logbestand wordt voorwaarts doorlopen en alle write-operaties worden opnieuw uitgevoerd (redo).
20.2.3
Commit Point of a Transaction
Een transactie bereikt een commit point als alle operaties succesvol zijn uitgevoerd en als alle bewerking naar het logbestand zijn geschreven. Na het commit point is het resultaat van de transactie
definitief, ze kan niet meer worden ongedaan gemaakt.
Eerst wordt de commit op het logbestand in de log buffer genoteerd. Daarna wordt het deel in
de log buffer definitief op de schijf geschreven, dit proces heet force-writing. Hierna bereikt de
transactie het commit point.
101
20.3
Desirable Properties of Transactions
Transacties moeten een aantal eigenschappen bevatten, de ACID properties.
• Atomicity. Transacties moeten ofwel volledig worden uitgevoerd, ofwel helemaal niet.
• Consistency preservation. Een enkele transactie moet de database van de ene naar de
andere consistente toestand brengen, zonder interferentie van andere transacties.
• Isolation. Het moet lijken alsof het de enige transactie is die wordt uitgevoerd (terwijl er
eigenlijk toch meerdere transacties tegelijk worden uitgevoerd).
• Durability or permanency. De veranderingen door een transactie moeten persistent zijn.
20.4
Characterizing Schedules Based on Recoverability
In een schedule (of transactierooster) worden de operaties van meerdere transacties in chronologische volgorde opgeschreven.
20.4.1
Schedules (Histories) of Transactions
Een schedule S bestaande uit de transacties T1 , T2 , . . . , Tn is een ordening van de volgorde waarin
de operaties van de transacties worden uitgevoerd. De operaties van de verschillende transacties
kunnen door elkaar voorkomen. De volgorde waarin operaties voorkomen in een transactie, moet
wel behouden worden. De volgorde van de operaties in S wordt de total ordening genoemd.
Twee operaties zijn met elkaar in conflict als ze aan de volgende 3 voorwaarden voldoen.
1. Ze behoren tot verschillende transacties.
2. Ze behandelen hetzelfde data item X.
3. Minstens 1 van de operaties is een operatie van de vorm write item(X). Er bestaan readwrite conflicten en write-write conflicten.
Een complete schedule is een schedule S = T1 , T2 , . . . , Tn die aan de volgende condities voldoet.
• De operaties in S zijn exact die in T1 , T2 , . . . , Tn met telkens ofwel een commit-operatie, ofwel
een abort-operatie aan het einde van elke transactie Ti .
• Elke 2 operaties van dezelfde transactie Ti komen (ten opzichte van elkaar) in S in dezelfde
volgorde voor als in de volgorde waarin die 2 operaties in Ti voorkomen.
• Voor elke 2 conflicterende operaties, geldt dat hun volgorde eenduidig vastligt.
De committed projection C(S) van een schedule S bevat enkel de operaties in S die behoren tot
committed transacties, dit zijn transacties Ti wiens commit-operatie ci tot S behoort.
20.4.2
Characterizing Schedules Based on Recoverability
Een schedule S is een recoverable schedule a.s.a. een transactie die gecommit is nooit meer ongedaan gemaakt moet worden. Dus als geen enkele transactie T in S commit voordat alle transacties
T 0 , die een item X hebben beschreven dat door T wordt gelezen, zijn gecommit.
Als dit niet geldt, is S een nonrecoverable schedule.
102
Een recoverable schedule is niet altijd simpel herstelbaar. Soms moet er een cascading rollback
gebeuren, dit kan tijdrovend zijn. In een recoverable schedule S gebeurt een cascading rollback als
een uncommitted transaction een rollback moet ondergaan omdat het een item las van een gefaalde
transactie. Hierdoor kan dan weer een andere uncommitted transaction last hebben.
Een schedule S is een cascadeless schedule als elke transactie in S enkel items leest committed
transactions. Een cascadeless schedule is automatisch ook recoverable.
Een schedule S is een strict schedule als elke transactie T een item X enkel leest of schrijft
als de laatste transactie die X heeft beschreven, gecommit is. Deze schedules zijn gemakkelijk te
herstellen aangezien men gewoon het oorspronkelijke item dat de gefaalde transactie schreef, moet
terugzetten. Een strict schedule is automatisch ook cascadeless.
20.5
Characterizing Schedules Based on Serializability
Een serializable schedule is altijd correct als de transacties concurrent uitgevoerd worden.
20.5.1
Serial, Nonserial, and Conflict-Serializable Schedules
Een schedule wordt serial genoemd als de transacties na elkaar worden uitgevoerd, dus zonder interferentie. Bij een nonserial schedule zijn er meerdere transacties tegelijk actief. Als de transacties
onderling onafhankelijk zijn, dan is een serial schedule altijd correct.
Bij serial schedules moeten transacties soms lang wachten als een voorgaande transactie wacht
op I/O of als die voorgaande transactie te lang duurt. Dit grote nadeel weegt niet op tegen het
voordeel van de correctheid, serial schedules worden dus niet gebruikt.
Een nonserial schedule S met n transacties is serializable a.s.a. het equivalent is met een serial
schedule met dezelfde n transacties. Zo’n nonserial schedule is dus ook altijd correct.
Twee schedules zijn result equivalent als ze dezelfde finale toestand van de database veroorzaken. Deze equivalentie is echter te zwak.
Twee schedules zijn conflict equivalent als ze de conflicterende operaties in dezelfde volgorde
uitvoeren. Een schedule is conflict serializable als het conflict equivalent is met een serial schedule.
20.5.2
Testing for Conflict Serializability of a Schedule
Het volgende algoritme test of een schedule serializable is m.b.v. een precedence graph.
1. Maak een knoop voor elke transactie Ti in S en label die knoop Ti .
2. Maak een boog van Ti naar Tj voor elke situatie in S waarbij:
• Tj een leesoperatie uitvoert nadat Ti een schrijfoperatie uitvoert.
• Tj een schrijfoperatie uitvoert nadat Ti een leesoperatie uitvoert.
• Tj een schrijfoperatie uitvoert nadat Ti een schrijfoperatie uitvoert.
3. Het schedule S is serializable als er geen lussen voorkomen in de graaf.
20.5.3
How Serializability Is Used for Concurrency Control
Er kunnen protocols ontworpen worden om ervoor te zorgen dat alle schedules serializable zijn. In
deze protocols worden regels vastgelegd die elke transactie moet volgen. Ze kunnen ook opgelegd
worden door het DBMS currency control subsysteem. Dit wordt besproken in hoofdstuk 22.
103
20.5.4
View Equivalence and View Serializability
Twee schedules S en S 0 zijn view equivalent als er voldaan wordt aan de volgende voorwaarden.
• Dezelfde verzameling transacties zit in S en in S 0 en de schedule S en S 0 bevatten dezelfde
operaties als die transacties.
• Voor elke leesoperatie ri (X) van Ti in S geldt: als de waarde van X (gelezen door ri ) weggeschreven is door een schrijfoperatie wj (X) van Tj (of als het de originele waarde van X is),
dan moet dezelfde conditie gelden voor de waarde van X, gelezen door ri (X) van Ti in S 0 .
• Als de schrijfoperatie wk (Y ) van Tk de laatste operatie is die het item Y wegschrijft in S, dan
moet wk (Y ) van Tk ook de laatste operatie zijn die Y wegschrijft in S 0 .
Een schedule S is view serializable als het view equivalent is met een serial schedule.
De definities van conflict serializability en view serializability zijn hetzelfde als de voorwaarde
constrained write assumption (of no blind writes) geldt voor alle transacties in het schedule.
Deze voorwaarde stelt dat elke schrijfoperatie wi (X) in Ti voorgegaan moet worden door een leesoperatie ri (X) in Ti en dat de waarde weggeschreven door wi (X) in Ti enkel afhangt van de waarde
X, ingelezen door ri (X).
Een blind write is een schrijfoperatie in een transactie T op een item X dat niet afhangt van
de waarde van X en dus niet voorafgegaan wordt door een leesoperatie van X in T .
De definitie van view serializability is minder strikt dan die van conflict serializability onder voorwaarde van de conditie unconstrained write assumption. Hierbij zijn blind writes wel toegestaan. Testen voor view serializability is NP-hard, er bestaat dus geen effici¨ent algoritme voor.
20.5.5
Other Types of Equivalence of Schedules
Debit-credit transactions zijn transacties die voldoen aan minder strenge voorwaarden dan serializability omdat dit in sommige situaties niet nodig is. Zo zijn bijvoorbeeld de bewerkingen open aftrekken van geld bij een balans commutatief en dus maakt de volgorde van de operaties niet
uit. Deze extra informatie over de transacties wordt de semantics genoemd.
20.6
Transaction Support in SQL
Een SQL instructie wordt als altijd atomisch beschouwd en wordt dus volledig uitgevoerd als er
geen fout voorkomt. Als er wel een fout optreedt, dan blijft de gegevensbank ongewijzigd.
In SQL is er geen Begin Transaction-statement, alle instructies moeten echter wel een end statement hebben: commit of rollback. Het is mogelijk enkele eigenschappen toe te kennen aan
een transactie die met het commando set transaction kunnen gespecificeerd worden.
De optie access mode kan read only (default) of read write zijn.
De optie diagnostic area size specificeert hoeveel condities er tegelijk worden bijgehouden in
de diagnostic area. Deze condities geven informatie over de n meest recente SQL instructies.
De optie isolation level kan gezet worden op read uncommitted, read committed, repeatable read of serializable (default).
Als een transactie uitgevoerd wordt op een lager niveau dan serializable, kunnen er zich verschillende
failures voordoen. Een dirty read bijvoorbeeld maakt gebruik van een tijdelijke aanpassing, deze
aanpassing werd eerder uitgevoerd door een nog niet gecommitte transactie.
Een nonrepeatable read gebeurt als transactie T1 een bepaald item leest, een andere transactie
T2 dit item aanpast, als T1 dan opnieuw dat item leest, zal die een andere waarde hebben.
Een phantom is een record dat zichtbaar wordt de tweede keer dat de tabel gelezen wordt.
104
Hoofdstuk 21
Introduction to Protocols for
Concurrency Control in Databases
21.1
Two-Phase Locking Techniques for Concurrency Control
Een lock is een variabele geassocieerd met een data-item dat de status weergeeft wat betreft de
mogelijke operaties die erop kunnen worden uitgevoerd.
´ en lock per data-item in de database
• E´
• Gebruikt voor synchronisatie bij gelijktijdige toegang
21.1.1
Types of Locks and System Lock Tables
Hieronder worden enkele soorten locks besproken.
Binary Locks
Status Variabele heeft slechts twee toestanden voor data-item X:
• Locked (1): variabele heeft waarde 1 en X is niet toegankelijk
• Unlocked (0): variabele heeft waarde 0 en X is toegankelijk. Indien het item wordt gebruik
wordt de waarde op 1 (Locked) gezet.
We refereren vanaf nu naar de status van lock geassocieerd met X als de booleaanse waarde lock(X)
Operaties Er zijn twee operaties gedefinieerd:
• lock item(X)
Idien een transactie X wil benaderen wordt deze operatie uitgevoerd. Er zijn twee mogelijkheden:
– lock(x) = 1: De transactie moet wachten.
– lock(x) = 0: De waarde van lock(x) wordt op 1 gezet en de transactie kan worden
uitgevoerd.
• unlock item(X)
Wanneer de transactie voltooid is wordt X terug vrijgegeven. De waarde van lock(x) wordt
terug op 0 gezet.
(Exact algoritme zie pagina 757)
105
Critische secties Bovenstaande operaties moeten ondeelbaar of atomair worden uitgevoerd. Dergelijke stukken code worden critische secties genoemd.
Gegevensstructuur Voor de implementatie van een binary lock volstaan twee gegevensstructuren:
• Een queue waarin transacties worden geplaatst die wachten om de lock te bemachtigen.
• Een gegevensstructuur met 3 velden: Data item name, LOCK, Locking transaction >.
Dit zou bijvoorbeeld ook een hash-tabel kunnen zijn waarbij er wordt vanuit gegaan dat items
die niet in de tabel zitten niet gelock zijt.
Regels bij Binary Lock
1. Een transactie moet een operatie lock item(X) uitvoeren alvorens een operatie read item(X)
of write item(X) uit te voeren.
2. Een transactie moet een operatie unlock item(x) uitvoeren nadat alle read item(X) of write item(X)
operaties zijn afgerond.
3. Een transactie mag geen operatie lock item(X) uitvoeren wanneer hij de lock reeds bezit.
4. Een transactie mag geen operatie unlock item(X) uitvoeren wanneer hij de lock niet bezit.
Conclusie
• Zeer eenvoudig
• Slechts 1 transactie kan een lock vasthouden
Shared/Exclusive (or Read/Write) Locks
Bepaalde operaties kunnen gelijktijdig worden uitgevoerd op X. Daarvoor zijn er nu 3 operaties
met bijhorende status:
• read lock(X) → read-locked
Deze lock kan door meerdere transacties tegelijk worden verkregen.
• write lock(X) → write-locked
Deze lock kan exclusief aan ´e´en transactie worden toegewezen.
• unlock(X) → unlocked
Geef X terug vrij.
Deze locks worden ook multiple-mode locks genoemd.
Gegevensstructuur We moeten nu bijhouden hoeveel transacties in het bezit zijn van een read
lock.
< Data item name, LOCK, N o of reads, Locking transaction(s) >
Afhankelijk van het type bevat de lijst met transacties slechts ´e´en element bij een write lock of
meerdere bij een read lock.
106
Regels Read/Write Locks
1. Een transactie moet een operatie read lock(X) of write lock(X) uitvoeren alvorens een operatie
read item(X) uit te voeren.
2. Een transactie moet een operatie write lock(X) uitvoeren alvorens een operatie write item(X)
uit te voeren.
3. Een transactie moet een operatie unlock item(x) uitvoeren nadat alle read item(X) of write item(X)
operaties zijn afgerond.
4. Een transactie mag geen operatie write lock(X) uitvoeren wanneer deze al een read lock of
write lock bezit. (Dit kan worden versoepeld)
5. Een transactie mag geen operatie unlock item(X) uitvoeren wanneer hij de lock niet bezit.
Conversion of Locks
We kunnen regel 4 en 5 versoepelen om lock conversion toe te laten. Hierdoor kan de transactie
zijn lock
• Upgraden: Wanneer deze een read lock bezit kan hij deze upgraden tot een write lock.
• Downgraden: Wanneer deze een write lock bezit kan hij deze downgraden tot een read lock.
Serializability
1. Werkwijze garandeert geen serializability
2. Protocol nodig dat bepaalt wanneer we locken en unlocken
(zie voorbeeld pagina 761)
21.1.2
Guaranteeing Serializability by Two-Phase Locking
Om te voldoen aan het two-phase locking protocol moeten alle locks voorafgaan aan de eerste
unlock-operatie. Hiermee kan een transactie worden opgedeeld in twee fases:
1. Expanding / Growing Phase
Locks kunnen worden bemachtigd maar niet worden vrijgegeven. Bij lock conversion mag
worden geupgrade.
2. Shrinking Phase
Locks kunnen worden vrijgegeven maar niet worden bemachtigd. Bij lock conversion mag
worden gedowngrade.
Indien elke transactie het two-phase locking protocol volgt is de planning
gegarandeerd serializable.
Eigenschappen
• Limiteert de hoeveelheid parallelisme
• Garandeert serializability
• Mogelijk zijn er andere schema’s die ook voldoen, maar niet worden toegelaten met dit principe
107
Basic, Conservative, Strict, and Rigorous Two-Phase Locking
Verschillende varianten op Two-Phase Locking
• Basic
Beschreven in vorige paragraaf
• Conservative of static
–
–
–
–
Vereist dat alles gelockt is alvorent de transactie van start gaat
Predeclareren van een write-set en read-set
Geeft nooit aanleiding tot deadlock
Soms onmogelijk
• Strict
– Meest populair
– Garandeert stricte schema’s
– Vrijgeven van exclusieve locks gebeurt pas helemaal op het einde
• Regorous
–
–
–
–
Nog stricter
Garandeert eveneens stricte schema’s
Vrijgeven van elke lock gebeurt pas helemaal op het einde
Eenvoudiger te implementeren dan strict
Concurrency Control Subsystem
• Verantwoordelijk voor toekennen locks
• Houdt gegevensstructuren bij
21.1.3
Dealing with Deadlock and Starvation
Twee mogelijke problemen die voorkomen bij het gebruik van locks.
Deadlock
Treedt op wanneer elke transactie T in een set van minstens twee transacties wacht op een item dat
locked is door een andere transactie T 0
• Elke transactie in de wachtrij
• Lock kan nooit worden vrijgegeven
Deadlock Prevention Protocols
Protocols voor het verhinderen van deadlocks.
• Lock in advance
Zoals gebruikt bij conservative locking
• Ordering
Bepaal een soort van ordening zodat transacties die meerdere items nodig hebben ze in de
juiste volgorde locken.
108
Timestamp Methodes Alternatieve methodes maken gebruik van een Transaction Timestamp,
genoteerd als T S(T ).
• Kent uniek ID toe aan elke transactie
• Gebaseerd op orde van transactie
• T S(T1 ) < T S(T2 ) ⇒ T1 startte voor T2
Hiermee kunnen volgende regels worden ingesteld ter preventie van deadlocks.
• Wait-die
Als T S(Ti ) < T S(Tj ) dan mag Ti wachten. Indien T S(Ti ) > T S(Tj ) wordt Ti onderbroken
en later herstart met zelfde timestamp.
• Wound-wait
Als T S(Ti ) < T S(Tj ) dan wordt Tj onderbroken en later herstart met zelfde timestamp.
Indien T S(Ti ) > T S(Tj ) mag Ti wachten.
Met deze protocols worden geen circulaire wachtrijen gevormd en zijn deadlocks niet mogelijk.
Wait Methods
• No Waiting
– Transactie wordt onmiddellijk onderbroken als geen lock kan worden bemachtigd
– Geen controle op daadwerkelijke deadlock
– Herstart na zekere periode
• Cautious Waiting
– Ti wilt lock voor X maar deze is in het bezit van Tj
– Als Tj op dat moment zelf ook wacht wordt Ti onderbroken
Beide methodes garanderen dat er geen deadlocks optreden.
Deadlock Detection
Protocols voor het opmerken van deadlocks.
• Interessant indien kans op deadlocks klein is
• Minder interessant indien hoge intensiteit transacties
Wait-for graph
• Knoop voor elke transactie die aan het uitvoeren is
• Gerichte boog van wachtende transactie naar transactie die lock momenteel heeft
• Boog wordt verwijderd indien lock wordt vrijgegeven door eindpunt
In geval van deadlock → vinctim selection
109
Timeouts
• Transactie gelimiteerd in tijd
• Eenvoudig te implementeren
• Weinig overhead
Starvation
• Transactie moet wachten voor onbepaalde duur terwijl andere wel kunnen uitvoeren
• Treedt op bij prioriteiten (bv ter preventie van deadlocks)
• Treedt op wanneer steeds hetzelfde victim wordt gekozen.
Hoe oplossen?
• Eerlijk wachtschema (→ Firs-come-first-served)
• Prioriteit verhogen met wachtduur
Wait-Die en Wound-Wait kunnen geen aanleiding geven tot starvation gezien de transactie herstart
wordt met de originele timestamp.
21.2
Concurrency Control Based on Timestamp Ordering
Alternatief dat eveneens serializability garandeert.
21.2.1
Timestamps
• Unieke identifier, toegekend bij begin van transactie
• Kan gezien worden als de starttijd van de transactie
• Ordening op basis van timestamps voorkomt deadlocks
Implementatie van een timestamp
• Teller die wordt verhoogd bij aanmaak nieuwe timestamp
(Waarde kan niet oneindig toenemen!)
• Huidige tijd waarbij slechts 1 timestamp gegenereeerd kan worden tijdens 1 klik van de klok
21.2.2
The Timestamp Ordering Algorithm
Centraal idee: Sorteren transacties op hun timestamp Verschil met 2PL
• Schema is equivalent met een schema dat voldoet aan 2PL protocol
• Schema is equivalent met schema met dezelfde volgorde van transacties
Het algoritme garandeert dat voor elk item dat wordt benaderd door conflicterende operaties de
volgorde van benadering gelijk is als die van de timestamps. Met elk item worden twee Timestampwaarden geassocieerd:
110
• Read Timestamp: read TS(X)
read TS(X) ← TS(T) waarbij T de jongste transactie is die X heeft gelezen.
• Write Timestamp: write TS(X)
write TS(X) ← TS(T) waarbij T de jongste transactie is die X heeft weggeschreven.
Basic Timestamp Ordering (TO)
• Transactie T probeert een operatie write item(X) uit te voeren. Algoritme controleert of
de timestamp van T kleiner is dan die van X: Boolean b ← write TS(X) > TS(T) ∨
read TS(X) > TS(X)
– If(b=TRUE): Jongere operatie (met grote TS(T’)>TS(T)) heeft waarde reeds veranderd → stop de transactie, herstel eventueel gewijzigde items (roll back) en weiger de
operatie.
– If(b=FALSE): Geen probleem → voer de operatie uit en zet write TS(X) op TS(T)
• Transactie T probeert een operatie read item(X) uit te voeren. Algoritme controleert of de
timestamp van T kleiner is dan die van X: Boolean b ← write TS(X) > TS(T)
– If(b=TRUE): Jongere operatie (met grote TS(T’)>TS(T)) heeft waarde reeds veranderd → stop de transactie, herstel eventueel gewijzigde items (roll back) en weiger de
operatie.
– If(b=FALSE): Geen probleem → voer de operatie uit en zet read TS(X) op max(T S(T ), read T
Samengevat: Wanneer twee conflicterende operaties in verkeerde volgorde worden uitgevoerd,
wordt de laatste van de twee geweigerd door het be¨eindigen van bijhorende transactie .
Strict Timestamp Method
Variant op Basic TO Algoritme die ganradeert dat de schema’s ook strict en conflict serializable
zijn.
Idee: Transactie T die operatie uitvoert zodat TS(T) > write TS(X) moet wachten todat transactie T’ dat de huidige waarde van X schreef (write TS(X) = TS(T’)) voltooid en be¨eindigd is.
→ Geen aanleiding tot deadlock: kan niet circulair worden gewacht door ordering in timestamp.
Thomas’s Write Rule
Variant op Basic TO Algoritme die geen conflic serializabilty garandeert maar minder schrijfoperaties weigert.
• If(read TS(X) > TS(T)): Stop en herstel (roll back)
• Else If(write TS(X) > TS(T)): Voer schrijfoperatie niet uit maar blijf uitvoeren. De
huidige schrijfoperatie van T is reeds verouderd.
• Else: voer de schrijfoperatie uit en zet write TS(X) op TS(T).
111
21.3
Multiversion Concurrency Control Techniques
Hierbij worden oudere versies van de data bijgehouden wanneer de waarde van een item wordt
gewijzigd.
• Leesoperaties die anders geweigerd zouden worden toch nog een oudere versie lezen.
• Door het kiezen van de juiste versie blijft serializabilty gegarandeerd
• Vraagt meer ruimte (maar kan soms sowieso het geval zijn voor herstel)
21.3.1
Multiversion Technique Based on Timestamp Ordering
Opnieuw twee timestmaps
• read TS(Xi ): grootste timestamp (= jongste) van alle transacties die Xi hebben gelezen.
• write TS(Xi ): grootste timestamp (= jongste) van alle transacties die Xi hebben weggeschreven.
Dit leidt tot
• T mag item X schrijven → Versie Xk+1 van X wordt aangemaakt en read TS(Xk+1 ) en write
TS(Xk+1 ) worden op TS(T) gezet.
• T mag item Xi lezen → read TS(Xi ) en write TS(Xi ) worden op TS(T) gezet.
Regels Regels om serializability te garanderen:
1. Als transactie T een write (X) operatie wil uitvoeren en versie i van X heeft de hoogste
write TS(Xi ) waarde van alle versies van X die kleiner of gelijk is aan TS(T) en read TS(Xi )
> TS(T)
→ Be¨eindig en herstel transactie T
(Deze situatie komt voor als T een versie van X probeert te schrijven die gelezen zou moeten
zijn door een transactie T’ met timestamp read TS(T’))
Anders: Vorm een nieuwe versie Xj van X met read TS(Xj ) = write TS(Xj ) = TS(T)
2. Als transactie T een read (X) operatie wil uitvoeren, vind versie i van X met de hoogste
write TS(Xi ) van alle X die kleiner zijn van TS(X)
→ Geef de waarde van Xi terug aan transactie T en zet de waarde van read TS(Xi op
max(T S(T ), readT S(Xi ))
→ Lezen is altijd succesvol.
→ Herstellen kan aanleiding geven tot cascading rollback
21.3.2
Multiversion Two-Phase Locking Using Certify Locks
Drie soorten locking
• Read: Onveranderd
• Write: Twee versies → een transactie T’ mag X lezen terwijl T hierop een writ lock bezit.
´ en versie weggeschreven door voltooide transactie
– E´
– Andere versie aangemaakt bij verkrijgen write lock voor T
• Certify : Exclusief en nodig voor het voltooien van transactie → nodig voor elk object waarop
write lock is verkregen
112
Eigenschappen
• Lezen kan gelijktijdig met enkelvoudig write lock
• Voltooien transactie kan uitgesteld worden door wachten op certify lock
• Deadlocks kunnen voorkomen bij het upgraden van read naar write lock
21.4
Validation (Optimistic) Concurrency Control Techniques
Voorgaande technieken checken voor de uitvoer van de operaties → overhead en vertraging.
Validation of Certification doet geen controle tijdens de uitvoer van de transactie.
Protocolfasen
1. Read Phase: Een transactie kan waarden lezen van gecommiteeerde items in de database.
Updates worden enkel toegewezen aan lokale kopie¨en.
2. Validation Phase: Controle wordt uitgevoerd om te verzekeren dat geen updates de serializability schenden.
3. Write Phase: Als de validatie succesvol was worden de updates weggeschreven naar de
database.
Centraal idee
• Controle in ´e´en keer op het einde
• Uitvoer met een minimum aan overhead tot de validatie wordt bereikt
Optimistisch
• Als er veel interferentie is zullen vele transacties moeten herstarten na validatiefase
• Optimischtisch veronderstelt weinig interferentie
Protocol
Maakt gebruik van transaction timestamps en moet daarnaast bijhouden:
• write sets en read sets (= alle items die respectievelijk geschreven en gelezen worden)
• Begin- en eindtijden van fases
→ Bij de validatiefase voor Ti wordt nagegaan of deze niet interfereert met gecommiteerde transacties of transacties momenteel ook in de validatiefase zitten.W
113
Protocol regels Tijdens de validatie wordt gecontroleerd of, voor elke transactie Tj dat deze
ofwel gecommitteerd is ofwel in zijn validatiefase is geldt:
1. Transactie Tj voltooid zijn schrijffase voordat Ti zijn leesfase begint.
2. Ti start zijn leesfase na de schrijffase van Tj en de read set van Ti heeft geen elementen
gemeenschappelijk met de write set van Tj
3. Zowel de read set als de write set van Ti hebben geen elementen gemeenschappelijk met de
write set van Tj en Tj voltooit zijn leesfase Ti zijn leesfase voltooit.
21.5
Granularity of Data Items and Multiple Granularity
Locking
We gingen er steeds van uit dat de database gevormd werd door een aantal data-items, bijvoorbeeld:
• Een record
• Een veld van een record
• Een disk block
• Volledig bestand
• De volledig database
De granularity of granulariteit bepaalt de performatie van bovenvermelde technieken.
21.5.1
Granularity Level Considerations for Locking
Data item granularity
• Fijne granulariteit: kleine items
• Grove granulariteit: grote items
Voor- en nadelen
• Grove granulariteit
– Minder parallellisme
– Lange wachttijden
• Fijne granulariteit
– Groter aantal items in de database
– Meer overhead
→ Beste grootte hangt af van situatie
114
21.5.2
Multiple Granularity Level Locking
Ondersteunen van locks voor verschillende groottes van items → multiple granularity level 2PL
(Probleem: voorbeeld probleem zie pagina 775)
Nieuw type lock nodig: intention lock → toont pad vanaf root tot gewenste knoop in granulariteitshierarchie.
1. Itention-shared (IS): ´e´en of meer gedeelde locks op onderliggende kno(o)p(en).
2. Intention-exclusive (IX) ´e´en of meer exclusieve locks op onderliggende kno(o)p(en).
3. Shared-intention-exclusive (SIX) Op huidige knoop rust een gedeeld lock maar ´e´en of
meer exclusieve locks zullen worden aangevraagd op onderliggende knopen.
Protocol regels Multiple Granularity Locking (MLG)
1. Compatibiliteit locks moet aangehouden worden. (zie pagina 776)
2. De root moet altijd als eerste worden gelockt.
3. Een knoop N kan gelockt zijn door transactie T in S of in IS mode als en slechts als de vader
van de knoop N reeds gelockt is door transactie T in IS ofwel IX.
4. Een knoop N kan gelockt zijn door transactie T in X, IX of in SIX mode als en slechts als
de vader van de knoop N reeds gelockt is door transactie T in IX ofwel SIX.
5. Een transactie T kan een knoop enkel een lock aanvragen als het geen knopen heeft geunlockt.
6. Een transactie T kan een knoop N enkel vrijgegven als geen van de kinderen van N momenteel
gelockt zijn door T.
Regel 1 → geen conflicten toelaten
Regel 5,6 → forceren 2PL protocol
Toepassing Vooral geschikt voor een mix tussen
• Korte transacties die slechts een beperk aantal items vereisen
• Grote transacties die volledige bestanden vereisen
21.6
Using Locks for Concurrency Control in Indexes
Locking gebruiken voor indexen (cfr. hoofdstuk 17)
Probleem: Index begint steeds in root → grote hoeveelheid blocking
• Root zou gelockt worden in exclusive mode
• Alle conflicterende transacties moeten wachten
Oplossing: Uitbuiten boomstructuur → zoeken via index betekent boom doorlopen
• Bovenliggende knoop niet meer nodig eens gepasseerd
• Lock op parent mag opgeheven worden eens lock op kind is toegewezen
115
Conservatieve benadering invoegen
1. Lock root in exclusive mode
2. Bereik kindknoop
3. Als het kind niet vol is → geef root vrij
→ Kan toegepast worden op elk niveau van de boom
→ Exlusieve lock worden snel vrijgegeven
Optimistische benadering
• Shared lock voor de knopen leidend naar doelknoop
• Exclusive lock op bladknoop
• Indien invoeging leidt tot splitsing → propageer opwaarts → upgrade locks naar exclusive
locks
Benadering met variant B + -tree: B-link tree Hierbij zijn alle broderknopen op hetzelfde
niveau gelinkt.
• Zoeken
– Shared lock bij opvragen pagina
– Lock moet vrijgegeven worden alsvorens kind te benaderen
• Invoegen
– Upgrade shared lock tot exclusive lock
– Bij splitsing moet vaderknoop opnieuw gelockt worden in exclusive mode
• Complicatie
– Veronderstel invoegoperatie volgt zelfde pad als zoekoperatie
– Wordt nieuw item ingevoegd in bladknoop die zorgt voor een splitsing
– Wanneer zoektoch daarna wordt voorgezet wordt een foute bladknoop gevonden
– Kan toch gevonden worden door link te volgen naar broederknoop
21.7
Other Concurrency Control Issues
21.7.1
Insertion, Deletion, and Phantom Records
Insertion
Nieuwe record dat wordt ingevoerd → kan uiteraard niet benderd worden tot het bestaat
• Locking environment: Write lock (exlusief)
• Timestmap environment: Timestamp = die van transactie die aanmaakt
116
Deletion
• Locking environment: Write lock (exlusief)
• Timestmap environment: Latere transacties mogen item niet schrijven of lezen alvorens
het verwijderd is
Phantom Records
Veronderstel volgende situatie
• Transactie T: voegt record toe met Dno=5
• Transactie T’: selecteert alle records met Dno=5
Mogelijke volgorde van uitvoer:
• T’ na T: Moet nieuwe record omvatten
• T na T’: Mag nieuwe record niet omvatten
Als T’ alle records met Dno=5 al heeft gelockt zijn er geen gemeenschappelijke records tussen beide
transacties → nieuwe record is phantom record
Index Locking Oplossing voor phantom records
• Locken van index alvorens invoegen record
• Conflict index lock → phantom record wordt opgemerkt
21.7.2
Interactive Transactions
Lezen van invoer en schrijven van uitvoer naar een interactief apparaat alvorens gegevens gecommit zijn.
• Eventuele afhankelijkheid tussen transacties is niet gekend door systeem
• Afhankelijkheid kan niet worden afgedwongen door concurrency control
→ Uitstellen van weergeven tot alles is gecommit.
21.7.3
Latches
Locks die slechts voor korte duur bestaan.
• Volgens niet standaard protocol
• Bijvoorbeeld bij wegschrijven pagina naar schijf
117
Hoofdstuk 22
Introduction to Database Recovery
Protocols
22.1
Recovery Concepts
22.1.1
Recovery Outline and Categorization of Recovery Algorithms
Recovery from transaction
• Restore to the most recent consistent state
• Information is kept by system log
Typical Strategy for Recovery
1. Extensive damage due to catastrophic failure
• Recover form last archived backup
• Reconstruct current state by redoing operations of commited transaction
• Commited transactions are kept by backed up log
2. No physical damage is done
• Identify changes causing inconsistencies
• Undo transactions that weren’t committed
• Redo transactions that were committed but not properly finished
(e.g. not yet written to disk)
Deffered Update
No physical update on disk until after a transaction is complete.
• Updates are recorded by database until committed
• Either in main memory or transaction workspace
• Written to disk once committed
Failures before commit do no harm
• no UNDO necessary
118
• REDO might be necessary: writing may not have finished after commit
→ NO-UNDO/REDO Algorithm
Immediate Update
Operation may update the database on disk before a transaction is complete.
• Operations have to write log on disk before executing
• In case of failure before committed: UNDO from log on disk (Rollback)
• Both UNDO and REDO
→ UNDO/REDO Algorithm
UNDO/REDO Operations
• Required to be idempotent
• Executing an operations multiple times has to be equivalent to executing it once
• Whole recovery process should be idempotent
→ The result of recovery from a system crash during recovery should be the same as the result of
recovering when there is no crash during recovery!
22.1.2
Caching (Buffering) of Disk Blocks
Buffering
• Disk pages are kept in main memory
• Updates are written to copies in memory instead onto disk
• Usually handled by OS, but database do it themselves
Directory
• In-memory buffers controlled by DBMS
• Directoy is used to keep track of what’s in those buffers
• If requested file is not in the cache, fetch in from disk and copy it cache
• If cache is full
– Replace a page
– Flush a cache buffer
• Page replacement strategy used
– Least recently used (LRU)
– First-in-first-out (FIFO)
– Least-likely-to use
119
Additional information in directory
• Dirty bit
– Indicates whether of not buffer has been modified
– Possibly additional information (such as modifying transaction)
– Only pages with dirty bit = 0 have to be written do disk when flushed
• Pin-unpin bit
– Pinned page cannot be written back to disk
– May be necessary for implementing recovery protocol
Strategies for Flushing
• In-place updating
– Writes buffer to same original location on disk
– Overwrites the old value of changed data
• Shadowing
– Different disk location
– Multiple versions of same data exists
– Not typically used in practice
We have to types of values
• Before image (BFIM): value before updating
• After image (AFMI): value after updating
22.1.3
Write-Ahead Logging, Steal/No-Steal, and Force/No-Foce
Write-Ahead Logging
• Use of a log is necessary for in-place updating
• BFIM must be recorded in log entry and flushed to disk
• BFIM is flushed before AFIM is written to disk
= Write-Ahead Logging
Log entries Distinguish between two types of log entry information
• REDO-type log
– Includes the new value (AFIM)
– Needed to redo the operation
• UNDO-type log
– Includes the old value (BFIM)
– Needed to undo the operation
→ Combined for UNDO/REDO-Algorithm
120
Log Buffering
• Log is stored in log buffer in main memory
• Log consists of append-only file
• Last n block of that file are in cache
→ Must first be written to disk before the data block itself can be written back!
Steal/No-steal
• No-steal approach
– Cache buffer page update cannot be written to disk before transaction commits
– Indicated by pin-bit
• Steal approach
– Allows writing an updated buffer before the transaction commits
– Used when buffer manager needs a buffer frame and replaces an existing page that had
been updated but whose transaction had not committed.
Force/No-force
• Force approach
– Updated pages are written to disk before transaction commits
– REDO will never be needed
• No-force approach
– The opposite, obviously
Typically a steal/no-force approach is used.
• Advantage is a page of a committed transaction may still be in the buffer
• Eliminates expensive IO
Recovery Lists
To facilitate recovery: the DBMS may need to maintain a number of lists
• Active transactions: have started but not committed
• Committed transactions
• Aborted transactions: since last checkpoint
→ Maintaining those lists makes recovery more efficient!
121
22.1.4
Checkpoints in the System Log and Fuzzy Checkpoints
Checkpoints
A checkpoint is a list of active transactions that is periodically written into the log when all
changed buffers are written to disk.
• All transactions have their commit-entries in the log before a checkpoint
• Do not have to have their write operation redone after checkpoint
• List of active transactions is included in checkpoint → easily redone
DBMS decides on what intervals to take a checkpoint. This consists of:
1. Suspending execution of transactions temporarily
2. Force-writing all changed main memory buffers to disk
3. Writing checkpoint-record to log and force-writing it to disk
4. Resuming execution
→ Additional info may be included, facilitating undoing in case of a rollback.
Fuzzy Checkpoints
Transactions may be delayed due to checkpoint taking → fuzzy checkpointing reduces this.
• Transactions resumes after writing of begin-checkpoint
• After step 2 → write end-checkpoint to disk
• Previous checkpoint should remain valid
• Pointer on disk points to previous checkpoint until end-checkpoint is reached
22.1.5
Transaction Rollback and Cascading Roll back
A rollback is needed when a transaction fails before committing. Changed data must be changed
back to its original state.
Cascading Rollback
1. Transaction T fails and rolls back
2. Transaction S had read data changed by T
→ S has to be rolled back also.
This can process can continue for a long time and is called cascading roll back. This can be
complex and time consuming → systems are designed so that this is never needed.
For an example: check page 792 in Database Systems (Sixth Edition)
122
22.1.6
Transactions Actions That Do Not Affect the Database
In general, there are actions that do not affect the database
• Should not execute multiple times in case of recovery
• Execute after transaction committed
• Create a batch job which is executed afterwards
22.2
NO-UNDO/REDO Recovery Base on Deffered Update
→ Postpone updates until the transaction completes and reaches its commit point.
• Updates are recorded to a log
• Log is force-written to disk when committing
• Only REDO-entries needed
• Only applicable if transactions change few items
→ Buffers will run out of space!
Protocol
1. A transaction cannot change the database on disk until it reaches its commit point.
2. A transaction does not reach its commit point untill all its REDO-type log entries are recorded
in the log and the log buffer is written to disk.
Same properties as listed above.
Multiuser Systems
Concurrency control and recovery are interrelated. Consider a system with concurrency control
using 2PL. We call a possible algorithm RDU M or Recovery used Deferred Update in a Multiuser
environment.
Procedure RDU M (NO-UNDO/REDO with checkpoints)
• Two lists of transactions
– Committed transaction T since last checkpoint: commit list
– Active transactions T’: active list
• REDO all write operations of the committed transaction list from the log, in the order they
were written to the log
• Active transactions did not commit hence no action is required
Procedure REDO (WRITE OP)
• Examin the log entry
• Set item to the AFIM
For an example: check page 794 in Database Systems (Sixth Edition)
123
Efficiency improvements
If a data item X has been updated more than once by committed transactions since the last
checkpoint, it is only necessary to REDO the last update of X from the log during recovery!
→ Start from the end of the log
Aborted Transactions
If a transaction is aborted it is simply resubmitted since it has not changed the database. This has
drawbacks:
• Limits concurrent execution
• All write-locked items remain locked until commit-point is reached
• Requires excessive buffer space to hold items
The main benefit is that a transaction operation never has to be undone for two reasons:
1. A transaction does not record any changes until commit-point → never rolled back
2. A transaction will never read the value of an item that is written by an uncommitted transaction
22.3
Recovery Rechniques Based on Immediate Update
→ Updates are immediately written to disk. Though this is not a requirement!
Handling Failed Transactions
• Undoing the effect of updates
• Rolling back transactions
• UNDO-type log entries are used which contain the old value (BFIM)
• Require steal strategy
We can distinguish two main types of algorithms:
• Updates recorded on disk before transaction commits
– Never need to REDO
– Called UNDO/NO-Redo recovery algorithm
– Used Force-Strategy for deciding when buffers are written to disk
• Transaction is allowed to commit before updates are written to disk
– UNDO/REDO recovery algorithm
– Steal/No-force strategy
124
Concurrent execution
Recovery process depends on concurrency control protocol
• RIU M: Recovery using Immediate Updates for a Multiuser environment
• We assume checkpoints and a strict schedules
• Deadlocks may occur thus requires abort and UNDO-operations
Procedure RIU M (UNDO/REDO with checkpoints)
1. Use two lists maintained by the system
• Committed transactions
• Active transactions
2. Undo all write item operations of active, uncommitted transactions using UNDO (in reverse order of log)
3. Redo all write item operations of committed transactions from the log in regular order
Whenever an operation is redone, it’s added to a list so it is not redone again.
Procedure REDO (Write OP)
1. Examine log entry and set value of X back to old value (BFIM)
2. Undo write item in reverse order
Only one UNDO operation is needed → scan list in forward direction and apply earliest UNDO.
22.4
Shadow Paging
• Does not require use of a log in single-user environment
• Log may be used in multiuser environment
22.4.1
Before Transaction
• Database consists of fixed size pages
• Directory with n entries with ith entry the ith page on disk
• Directory is kept in main memory
• When transaction begins executing the current directory is copied into a shadow directory
• Shadow directory is saved on disk while active is used
125
22.4.2
During Transaction
• Shadow directory is not touched during transaction
• In case of write item, new page is created
• Old page is not overwritten
• Current directory points to new page, whereas the old one points to the previous
•
→ For every updates page, there are two version. One referenced to by the shadow directory, and
one by the active directory.
22.4.3
Recovery Process
• Free the modified database page → discard current directory
• Previous state is available trough the shadow directory
• Committing corresponds to discarding shadow directory
→ No UNDO/REDO necessary!
22.4.4
Disadvantages
• Logs and checkpoints need to be incorporated into page for multiuser envornment
• Changing location on disk → less efficient
• Large directories may exist
• Overhead of writing shadow directories to disk
• Old page must be released → Garbage collection
• Migration between directories has to be atomic!
22.5
The Aries Recovery Algorithm
• Used in database related IBM products
• Uses a steal/no-force approach
Based on 3 concepts:
1. Write-ahead logging
2. Repeating history during REDO
• Retrace all actions prior to the crash
• Uncommitted transactions at the time of the crash are omitted
3. Logging changes during UNDO
• Prevents from repeating the completed UNDO operations
• In case of restart during recovery
126
22.5.1
Analysis Phase
• Identifies dirty buffer pages in buffer
• Appropriate location from where REDO should start is determined
22.5.2
REDO Phase
• Reads start point for REDO
• From there REDO operations are applied until end of log is reached
• Only necessary REDO operations are applied
22.5.3
UNDO Phase
• Log is scanned backwards
• Operations are undone in reverse order
22.5.4
Structures
• Log
• Transaction Table
• Dirty Page Table
• Checkpoints
22.5.5
Log Sequence Number (LSN)
• Monotonically increasing
• Indicates the address of the log record on disk
• Corresponds to specific change of some transaction
• Each page will store LSN of the last record corresponding to a change for that page
• Log is written when
–
–
–
–
–
Updating a page (write)
Committing a transaction (commit)
Aborting a transaction (abort)
Undoing an update (undo) → compensation log record
Ending a transaction (end)→ end log record
Fields in log
• Previous LSN: Links the log records in reverse order for each transaction
• For write record
– Page ID
– Length of the updated item
– Offset from the beginning of the page
127
22.5.6
Tables
• Transaction Table
– Entry for each active transaction
– Information such as ID, status and the LSN of the most recent log record
• Dirty Page Table
– Entry for each dirty page in buffer
– Includes page ID, LSN of the earliest update to that page
→ Mainly used by transaction manager
22.5.7
Checkpoints
• Writing a begin checkpoint record
• Writing an end checkpoint record
– Content of both the transaction table and Dirty Page Table are appended tot the log
– Fuzzy checkpointing is used
• Writing LSN of the begin checkpoint to a special file
– Accessed during recovery
– Used to locate last checkpoint information
22.5.8
Recovery from crash
• Information from the last checkpoint is first accessed trough the special file
•
For the detailed exaplanation of the ARIES Algorithm, refer to page 799 in Database
Concepts (6th edition)
22.6
Recovery in Multidatabse Systems
• Single transaction may need acces to multiple databases
• May even be different types of databases
• Recovery techniques may differ between databases
→ Global Recovery Manager of Coordinator is needed.
→ Follows two-phase commit protocol
• Phase 1
– All participation database signal coordinator that their part has concluded
– Coordinator sends message prepare for commit
128
– Every receiving database will force-write all log records etc to disk
– Answer coordinator with ready to commit
– If write fails send cordinator cannot commit
– Assumes a not OK reply if no response after a time interval
• Phase 2
– All participants reply OK
– Coordinators vote is also OK
– Transaction is successful
– Coordinator sends a commit signal
– In case of failure: roll back message
→ Either all databases commit or all database roll back.
22.7
Database Backup and Recovery from Catastrophic
Failures
• Techniques so far focussed on non-catastrophic failures
• Entries from log or shadow directories are used
22.7.1
Handling more Catastrophic Failures
• Databse Backup
• Whole database and log are periodically copied to cheap storage medium
• The latest backup can be reloaded
• Such backups may be locked in a vault for critical information
– Stock markets
– Banking and insurance
22.7.2
Increase frequency
• Create customary backups
• Start where last complete backup ended
• Smaller thus possible to create more frequently
• After full recovery, redo operations noted in this backup
129