Οι σχέσεις IS-A στις Σχεσιακές Βάσεις Δεδομένων

Στο σχεδιασμό Βάσεων Δεδομένων, οι σχέσεις IS-A είναι ίσως η τεχνική που έχει αγνοηθεί περισσότερο από όλες. Ακόμα και όταν η κατηγοριοποίηση των οντοτήτων είναι προφανής, πολλοί επιλέγουν τη δημιουργία ενός πίνακα με πολλά πεδία, που καλύπτουν όλες τις περιπτώσεις, ο οποίος τελικά καταλήγει να είναι “αραιός”. Άλλοι πάλι, προτιμούν να υλοποιήσουν τόσους πίνακες, όσες και οι τελικές κατηγορίες οντοτήτων. Αλλά οι πίνακες αυτοί είναι εντελώς ανεξάρτητοι μεταξύ τους, και τελικά το πρόβλημα της εννοιολογικής συσχέτισης τους μεταφέρεται σε ψηλότερα επίπεδα στο μοντέλο της εφαρμογής.

Ακόμα χειρότερα, η συζήτηση για τη βέλτιστη υλοποίηση συχνά καταλήγει στο δίλημμα: “αραιός πίνακας ή πολλοί ανεξάρτητοι πίνακες;” αφήνοντας εντελώς απέξω την προοπτική της σχέσης IS-A. Ειδικά όταν το έργο είναι “μικρό”, και οι επιπτώσεις στην απόδοση αλλά και τη συντήρηση δεν είναι μεγάλες, οι δύο αυτές επιλογές φαντάζουν αυτόματες, σε αντίθεση με την “πολυπλοκότητα” της υλοποίησης ενός πιο δομημένου σχήματος.

Για να μπορέσουμε να κατανοήσουμε καλύτερα την υλοποίηση των σχέσεων IS-A, και να τις συγκρίνουμε με άλλες τεχνικές, ας φανταστούμε τη ΒΔ ενός ηλεκτρονικού καταστήματος. Μεταξύ άλλων, διατηρεί πληροφορίες για διάφορους τύπους ατόμων: υπαλλήλους, πελάτες, προμηθευτές και άλλες επαφές. Είναι προφανές ότι όλα αυτά τα άτομα έχουν ένα ονοματεπώνυμο (fullname) και πιθανότατα ένα τηλέφωνο (phone). Οι υπάλληλοι έχουν μισθό (salary) και ανήκουν σε τμήμα (department), οι προμηθευτές σχετίζονται με κάποια επιχείρηση (company) και οι πελάτες έχουν ένα ποσό πίστωσης (credit). Επιπλέον, οι υπάλληλοι καθώς και οι πελάτες έχουν στοιχεία αυθεντικοποίησης (username και password). Φυσικά, σε πραγματικές συνθήκες, θα είχαν οριστεί πολύ περισσότερα πεδία για καθεμιά από αυτές τις οντότητες, αλλά ας το κρατήσουμε όσο πιο απλό γίνεται.

Αυτό που δεν είναι τόσο προφανές, αλλά σίγουρα υπονοείται, είναι το γεγονός ότι τα παραπάνω σύνολα συχνά επικαλύπτονται. Για παράδειγμα, δεν υπάρχει λόγος να θεωρήσουμε ότι ένας υπάλληλος ή ένας προμηθευτής δεν μπορεί να είναι συγχρόνως και πελάτης. Επιπλέον, κάποια άτομα δεν ανήκουν σε κανένα από αυτά τα σύνολα — είναι απλά “άλλες επαφές”.

Ας συγκρίνουμε τώρα, χρησιμοποιώντας ένα δείγμα δεδομένων, τις τρεις μεθόδους που αναφέρθηκαν παραπάνω: τον αραιό πίνακα, τους πολλούς ανεξάρτητους πίνακες και την προσέγγιση IS-A.

1. Μεγάλος, αραιός πίνακας

Θα ξεκινήσω από τον αραιό πίνακα, όχι μόνο διότι δίνει μία καλή οπτική αναπαράσταση του παραδείγματος, αλλά επίσης διότι μπορεί να αποτελέσει ένα καλό σημείο εκκίνησης για μία διαδικασία κανονικοποίησης. Έχουμε λοιπόν:

people
id fullname phone salary department company credit username password
3465 John Doe 555-12345 1345.67 R&D jdoe **************
9674 Jane Doess 980.55 Sales 630.43 jane **************
5789 Michael Smith 555-98736 Widgets Co. 176.00 msmith **************
1287 Samantha Blue 555-03456 354.99 sammyblue **************
9824 Alice Red
7289 Ben Purple 555-98765 Acme Ltd.
1485 Vincent Maroon 555-37108

Ο λόγος για τον οποίο τον χαρακτηρίσαμε “αραιό πίνακα” είναι τώρα ξεκάθαρος. Όσο θα μεγαλώνει ο πίνακας, τόσο περισσότερος χώρος θα ξοδεύεται άσκοπα. Στην πραγματικότητα όμως, αυτό δεν είναι το μεγαλύτερο πρόβλημα.

Επειδή όλα τα δεδομένα βρίσκονται στο ίδιο αντικείμενο της ΒΔ (έναν πίνακα) είναι σχεδόν αδύνατο να επιβάλουμε τους απαραίτητους περιορισμούς στο επίπεδο της ΒΔ. Για παράδειγμα, αφού η στήλη department δεν μπορεί να οριστεί ως “NOT NULL”, τι γίνεται αν ένα άτομο έχει μισθό αλλά το αντίστοιχο κελί τμήματος είναι κενό; Ή, πως μπορούμε να επιβάλουμε μοναδικότητα στη στήλη username τη στιγμή που δέχεται κενά;

2. Πολλοί ανεξάρτητοι πίνακες

Για καθεμία από τις οντότητες υπάλληλος, πελάτης, προμηθευτήςάλλη επαφή υλοποιούμε κι από έναν πίνακα. Κάθε πίνακας περιέχει τόσες στήλες όσα και τα κατηγορήματα της κάθε οντότητας ξεχωριστά, συν ένα που χρησιμοποιείται σαν κύριο κλειδί. Φυσικά, σε κάποιες από αυτές υπάρχουν ήδη πεδία που χαρακτηρίζουν την πλειάδα και είναι υποψήφια κύρια κλειδιά, αλλά ας το κάνουμε έτσι χάριν ομοιομορφίας με τις υπόλοιπες μεθόδους.

employee
id fullname phone salary department username password
4589 John Doe 555-12345 1345.67 R&D jdoe **************
7856 Jane Doess 980.55 Sales jane **************
customer
id fullname phone credit username password
1085 Jane Doess 630.43 doess **************
3718 Michael Smith 555-98736 176.00 msmith **************
3376 Samantha Blue 555-03456 354.99 sammyblue **************
supplier
id fullname phone company
9836 Michael Smith 555-98736 Widgets Co.
3376 Ben Purple 555-98765 Acme Ltd.
other_contact
id fullname phone
1234 Alice Red
4589 Vincent Maroon 555-37108

Η αδυναμία να εφαρμόσουμε περιορισμούς έχει πλέον μερικώς εξαλειφθεί. Τα usernames μπορούν πλέον να είναι μοναδικά, αλλά μόνο μέσα στα όρια του ίδιου πίνακα, και όχι σε όλο το σύστημα. Επίσης, μπορούμε να εξασφαλίσουμε ότι ο μισθός αλλά και το τμήμα θα είναι πάντα συμπληρωμένα.

Έχουμε πάντως κι εδώ πρόβλημα σπατάλης χώρου, λόγω της επικάλυψης των οντοτήτων. Η Jane και ο Michael εμφανίζονται σε δυο πίνακες ο καθένας, κουβαλώντας μαζί τους τα ονόματα και τηλέφωνα τους. Επιπλέον, επειδή η Jane είναι συγχρόνως υπάλληλος και πελάτης, τα στοιχεία αυθεντικοποίησης της εμφανίζονται και στους δυο πίνακες αντίστοιχα. Αυτό εισάγει την ανάγκη για συγχρονισμό δεδομένων που πρέπει να βρίσκονται σε πολλά μέρη συγχρόνως, που μπορεί να αποδειχτεί δύσκολη δουλειά. Ή, για τα στοιχεία αυθεντικοποίησης, το συμβιβασμό ότι η Jane θα έχει διαφορετικό username/password στα δύο υποσυστήματα (πράγμα που συμβαίνει και στο παράδειγμα).

Τέλος, αν θέλουμε να παράγουμε μία ενιαία λίστα με οποιαδήποτε από τα κοινά δεδομένα, θα πρέπει να το κάνουμε χρησιμοποιώντας ερωτήματα UNION. Για παράδειγμα, προκειμένου να ανακτήσουμε μία γενική λίστα με ονοματεπώνυμα και τηλέφωνα, πρέπει να κάνουμε συνένωση και των τεσσάρων πινάκων.

3. Η προσέγγιση IS-A

Για να υλοποιηθεί μία σχέση IS-A, θα πρέπει πρώτα να οριστούν όλες οι κλάσεις, από τη γενική υπερκλάση και όλες οι ενδιάμεσες μέχρι τις τελικές. Είναι προφανές ότι η γενική υπερκλάση είναι το άτομο (person) και περιέχει τα κατηγορήματα fullname και phone. Τα άτομα που έχουν στοιχεία αυθεντικοποίησης θα τα λέμε χρήστες (users) με κατηγορήματα username και password, που με τη σειρά τους χωρίζονται σε υπαλλήλους (employees: salary, department) και πελάτες (customers: credit). Εκτός από τους χρήστες υπάρχουν οι προμηθευτές (suppliers: company) και οι άλλες επαφές χωρίς επιπλέον κατηγορήματα. Συνοπτικά:

Έστω person(fullname,phone). Ένας user(username,password) είναι (is a) person. Ένας customer(credit) είναι user. Ένας employee(salary) είναι user. Ένας supplier(company) είναι person.

Κάθε πίνακας από τους παρακάτω περιέχει μόνο τα πεδία τα ειδικά για τη συγκεκριμένη (υπο)κλάση. Το πεδίο id είναι συγχρόνως κύριο κλειδί και ξένο κλειδί στην άμεση υπερκλάση της (με εξαίρεση το person που προφανώς δεν έχει δική του υπερκλάση). Για παράδειγμα, το user.id είναι κύριο κλειδί του πίνακα user και ξένο κλειδί στο person.id. Έτσι εξασφαλίζεται αφ’ ενός η σύνδεση της κάθε κλάσης με την υπερκλάση της και αφ’ ετέρου η μοναδικότητα του κάθε στιγμιότυπου μέσα στην κλάση του.

person
id fullname phone
3465 John Doe 555-12345
9674 Jane Doess
5789 Michael Smith 555-98736
1287 Samantha Blue 555-03456
9824 Alice Red
7289 Ben Purple 555-98765
1485 Vincent Maroon 555-37108
user
id username password
3465 jdoe **************
9674 jane **************
5789 msmith **************
1287 sammyblue **************
customer
id credit
9674 630.43
5789 176.00
1287 354.99
employee
id salary department
3465 1345.67 R&D
9674 980.55 Sales
supplier
id company
5789 Widgets Co.
7289 Acme Ltd.

Παρατηρούμε ότι δεν χρειάζεται να υλοποιήσουμε πίνακα για τις “άλλες επαφές”, αφού δεν έχουν επιπλέον κατηγορήματα.

Η σπατάλη χώρου είναι τώρα μηδενική. Μπορούμε να εφαρμόσουμε οτιδήποτε περιορισμούς χρειαζόμαστε. Κάθε στιγμιότυπο μπορεί να ανήκει σε οποιαδήποτε κλάση, αλλά μόνο μία φορά στην καθεμία, αρκεί πρώτα να εμφανίζεται στην άμεση υπερκλάση της. Μπορούν πολύ ευκολότερα να εξαχθούν συγκεντρωτικά αποτελέσματα, για οποιοδήποτε επίπεδο της ιεράρχησης. Κανένας συγχρονισμός δεν χρειάζεται, και ο κάθε χρήστης έχει ένα μοναδικό λογαριασμό στο σύστημα.

Συμπεράσματα

Οι σχέσεις IS-A είναι εναρμονισμένες με τη φιλοσοφία της αυτονομίας μίας ΒΔ, ανεξάρτητα από τις εφαρμογές που τη χρησιμοποιούν. Βοηθούν στη διάκριση των υποσυστημάτων και στην επεκτασιμότητα του συστήματος, καθώς αν χρειαστεί περαιτέρω ανάπτυξη της ιεραρχίας, κανένα από τα ανώτερα επίπεδα δεν χρειάζεται να αλλάξει, συνεπώς ούτε και οι σχετικές εφαρμογές. Επιπλέον, αν χρειαστούν αλλαγές σε κάποια κλάση, επηρεάζεται μόνο ο αντίστοιχος πίνακας. Κι όλα αυτά, χρησιμοποιώντας τις ήδη υπαρχουσες λειτουργίες ενός συστήματος διαχείρισης σχεσιακών βάσεων δεδομένων.

2 Comments

  1. Καλησπέρα. Ωραίο το άρθρο και χρήσιμο με σωστή προσέγγιση.
    Μερικές μόνο παρατηρήσεις:
    α) Αραιός πίνακας δεν συνεπάγεται μη-κανονικοποιημένος.
    β) Μπορείς να βάλεις unique index σε nullable στήλη. Άλλωστε, ως γνωστόν δύο null values δεν θεωρούνται ως μεταξύ τους ίσες ώστε να παραβιάζεται το constraint. και
    γ) στην τρίτη περίπτωση υπάρχει σπατάλη χώρου γιατί ξαναποθηκεύεις το πρωτεύον κλειδί στα παιδιά και διατηρείς κ index φυσικά σε αυτό. Επίσης, το flag εάν ένα κελί είναι null να είσαι σίγουρος πως το έχουν βελτιστοποιήσει, άρα η πρώτη περίπτωση δεν συνεπάγεται τη σπατάλη χώρου που μοιάζει να έχει ένας πίνακας.

  2. Σ’ ευχαριστώ για το σχόλιο σου. Πάντα μου αρέσει να βλέπω σχόλια με κριτική σκέψη!
    Σχετικά με τις παρατηρήσεις σου:

    α) Δίκιο έχεις, αλλά ποτέ δεν ισχυρίστηκα κάτι τέτοιο. Αν αναφέρεσαι στο

    …διότι μπορεί να αποτελέσει ένα καλό σημείο εκκίνησης για μία διαδικασία κανονικοποίησης…

    αναφερόμουν στην ύπαρξη ενός και μόνο πίνακα κατά την έναρξη μίας οποιασδήποτε διαδικασίας κανονικοποίησης, πράγμα με το οποίο είναι, θεωρητικά, εξοικειωμένος κάποιος που θα διάβαζε το άρθρο, άρα και ένα καλό σημείο για να αρχίσω. Αλλά τώρα που το αναφέρεις, ίσως θα έπρεπε να το έχω εκφράσει καλύτερα.

    β) Κι εδώ δίκιο έχεις …εν μέρει! Δύο NULL τιμές δεν θεωρούνται ίσες, αλλά ούτε και διαφορετικές. Όπως για παράδειγμα στη Γεωμετρία δύο ασύμπτωτες ευθείες δεν μπορεί να θεωρηθούν ούτε παράλληλες ούτε τεμνόμενες: απλά δεν υφίσταται το δίλημμα.
    Άρα, αφού κι εδώ δεν υφίσταται σύγκριση, το κάθε RDBMS το αντιμετωπίζει διαφορετικά. Ενώ όλα (που ξέρω) θα σε αφήσουν να ορίσεις το index (και γιατί όχι) στην πράξη η MySQL θα σε αφήσει να βάζεις NULL τιμές ενώ ο MSSQL θα σε αφήσει να βάλεις μόνο μία (δηλαδή δύο NULL παύει να είναι unique!).
    Για να είμαι εντάξει, θα πρέπει να παραδεχθώ ότι τα ANSI Standards είναι “μαζί σου”, όμως οι απόψεις διίστανται για το αν αυτό είναι σωστό ή όχι.

    γ) Επανάληψη!=Σπατάλη
    Είναι δύο διαφορετικά προβλήματα. Όταν επαναλαμβάνεται κάτι άσκοπα, δημιουργεί προβλήματα συγχρονισμού, όπως γίνεται στη δεύτερη περίπτωση με τα ονοματεπώνυμα και ειδικά με τα στοιχεία πιστοποίησης. Και φυσικά όταν έχεις ένα FK δεν μπορείς να μην επαναλάβεις την τιμή του πεδίου στον detail πίνακα… Εδώ το πρόβλημα το λύνουν οι ON UPDATE/ON DELETE constraints, που αν δεν υπήρχαν, δεν θα είχαμε και αξιοπρεπή FKs 😉
    Για τη σπατάλη, εννοείται ότι γίνεται optimization σε επίπεδο αποθηκευτικού χώρου, αν εννοείς αυτό. Αλλά εγώ αναφέρομαι στη σπατάλη σε λογικό επίπεδο.

Αφήστε μια απάντηση

Η ηλ. διεύθυνση σας δεν δημοσιεύεται. Τα υποχρεωτικά πεδία σημειώνονται με *