Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ΣΔΒΔ - P20009, P20007, P20004 #226

Open
wants to merge 104 commits into
base: master
Choose a base branch
from

Conversation

dimitrisstyl7
Copy link

@dimitrisstyl7 dimitrisstyl7 commented Feb 20, 2023

ΣΥΣΤΗΜΑΤΑ ΔΙΑΧΕΙΡΙΣΗΣ ΒΑΣΕΩΝ ΔΕΔΟΜΕΝΩΝ | 2022-23

Ομάδα: Παναγιώτα Νικολάου Π20009, Κωνσταντίνος Λοϊζίδης Π20007, Δημήτρης Στυλιανού Π20004

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

Αρχείο mdb.py

Συνάρτηση create_query_plan:

  • Στο 'action==select' (γραμμή 79) προσθέσαμε την κλήση της συνάρτησης 'evaluate_where_clause', η οποία υπολογίζει το 'where' clause το οποίο δεν ήταν υλοποιημένο. Η συγκεκριμένη συνάρτηση θα επεξηγηθεί παρακάτω.

Παράδειγμα εκτέλεσης:

Εγγραφές πίνακα:

image

Πλάνο εκτέλεσης:

image

Εκτέλεση ερωτήματος:

image

  • Στο 'action==create table' (γραμμή 100) προσθέσαμε στην υπάρχων υλοποίηση την υποστήριξη ένα πεδίο να είναι 'unique'.

Παράδειγμα εκτέλεσης:

Πλάνο εκτέλεσης:

image

Εκτέλεση ερωτήματος:

image

  • Προσθέσαμε το 'action==delete from' (γραμμή 138) ώστε να υποστηρίζεται και η διαγραφή εγγραφής/ών. Όπως και στο select, καλούμε την συνάρτηση 'evaluate_where_clause'.

Παράδειγμα εκτέλεσης:

Εγγραφές πίνακα:

image

Πλάνο εκτέλεσης:

image

Εκτέλεση ερωτήματος:

image

  • Προσθέσαμε το 'action==update' (γραμμή 144) ώστε να υποστηρίζεται η ενημέρωση εγγραφής/ων. Επίσης, καλείται η συνάρτηση 'evaluate_where_clause'.

Παράδειγμα εκτέλεσης:

Εγγραφές πίνακα:

image

Πλάνο εκτέλεσης:

image

Εκτέλεση ερωτήματος:

image

  • Τροποποιήσαμε το 'action==create index' (γραμμή 150) ώστε να υπάρχει η δυνατότητα επιλογής του πεδίου που θέλουμε να υποστηρίζεται από ευρετήριο (btree ή hash).

Παράδειγμα εκτέλεσης:

Πλάνο εκτέλεσης:

image

Εκτέλεση ερωτήματος:

image

Συνάρτηση evaluate_from_clause:

Στις γραμμές 185-189 επεκτείναμε το 'on' clause διότι το χρειαστήκαμε για να φτιάξουμε τα ισοδύναμα πλάνα εκτέλεσης (issue_3a).

Συνάρτηση evaluate_where_clause:

Την χρησιμοποιούν όλα τα queries που υποστηρίζουν το 'where' clause (select, delete και update). Μέσα σε αυτή, δημιουργήσαμε 3 ιδιωτικές βοηθητικές συναρτήσεις:
  1. convert_list_to_dict: Μετατρέπει μια λίστα με λεξικά σε ένα λεξικό, το οποίο μπορεί να περιέχει εμφωλευμένα λεξικά ανάλογα πόσο σύνθετο είναι το query μας.
  2. build_list: Φτιάχνει μια λίστα από λεξικά, όπου κάθε λεξικό περιέχει την αριστερή και δεξιά συνθήκη ενός operator ('and' / 'or').
  3. put_paren_in_oprt_and: Βοηθάει στη σωστή δημιουργία του πλάνου εκτέλεσης. Όταν υπάρχει 'and' operator που δεν είναι σε παρενθέσεις και ακολουθείται ή προηγείται από έναν 'or' operator, βάζουμε τις κατάλληλες παρενθέσεις ώστε να εξασφαλίσουμε την προτεραιότητα μεταξύ των operators 'and' και 'or'.

    Γενικά, η συνάρτηση evaluate_where_clause χρησιμοποιείται για την δημιουργία ενός σωστόυ πλάνου εκτέλεσης, υποστηρίζοντας σύνθετα 'where' clause για όλους τους operators (and, or, not και between).

Κύρια συνάρτηση (main):


Στην περίπτωση που δίνεται ένα κανονικό query χωρίς 'explain', οι γραμμές 482-485 υπολογίζουν τα διάφορα ισοδύναμα queries (εφόσον το δοθέν query υποστηρίζεται - από την υλοποίηση μας -) και επιστρέφουν αυτό με το μικρότερο κόστος (issue_3). Πιο συγκεκριμένα, η συνάρτηση 'multiple_query_plans' επιστρέφει μια λίστα με τα ισοδύναμα πλάνα εκτέλεσης ('queries') και μια λογική τιμή ('is_valid') και αν είναι True καλείται η συνάρτηση 'evaluate_query_plans' , η οποία επιστρέφει το query με το μικρότερο κόστος (εάν αυτό υποστηρίζεται).

Ισοδύναμα πλάνα εκτέλεσης:

image

Πλάνο εκτέλεσης με το ελάχιστο κόστος:

image

Αρχείο database.py

Συνάρτηση __init__:

Προσθέσαμε το λεξικό stats όπου θα περιέχει τα στατιστίκα του κάθε πίνακα, στην γραμμή 38-39 τα φορτώνουμε μέσω της συνάρτησης 'load_statistics' και έπειτα τα υπολογίζουμε μέσω της συνάρτησης 'calculate_tables_statistics'.
Στην γραμμή 53 δημιουργείται ο φάκελος όπου θα περιέχει το αρχείο (pkl) που αποθηκεύονται τα στατιστικά.
Επίσης, στην γραμμή 61 προσθέσαμε τις στήλες 'indexed_column' και 'index_type' όπου μας είναι απαραίτητες για την αποθήκευση του ονόματος στήλης όπου δημιουργείται το ευρετήριο και τον τύπο του ευρετηρίου (btree, hash).


Συνάρτηση create_table:

Στις γραμμές 121-127 στέλνουμε σαν όρισμα στον constructor του Table τα 'unique' πεδία (οι αλλαγές στην κλάση Table θα αναφερθούν παρακάτω). Επίσης, στην γραμμή 133 υπολογίζουμε τα σταστικά του κάθε πίνακα ώστε να έχουμε στην διάθεση μας και τα στατιστικά του νέου πίνακα.

Συνάρτηση drop_table:

Στην γραμμή 152 υπολογίζουμε τα στατιστίκα του κάθε πίνακα ώστε να αφαιρεθούν τα στατιστικά του πίνακα που διαγράφηκε και στην γραμμή 166 κάναμε την απαραίτητη αλλαγή ώστε να παίρνουμε τη σωστή στήλη (index_name).

Συνάρτηση insert_into:

Στις γραμμές 287-288 ξεκλειδώνουμε τον πίνακα δίοτι παρέμενε κλειδωμένος σε περίπτωση κάποιου exception.

Συνάρτηση select:

Στις γραμμές 365-398 γίνεται ο έλεγχος για την ύπαρξη ευρετηρίου για έναν συγκεκριμένο πίνακα. Εάν υπάρχει γίνονται κάποια ενδιάμεσα βήματα για να ξεχωρίσουμε αν είναι btree ή hash και έπειτα τα στέλνουμε σαν όρισμα στη συνάρτηση '_select_where' της κλάσης Table. Δεν χρησιμοποιούμε καθόλου την συνάρτηση '_select_where_with_btree' και όπως θα δείτε την έχουμε αφαιρέσει τελείως από την κλάση Table.

Συνάρτηση join:

Στις γραμμές 489-528 προστέθηκε ο κατάλληλος κώδικας για τον έλεγχο ύπαρξης ευρετηρίων και έαν ο πίνακας διαθέτει ευρετήριο να εφαρμόζεται επιτυχώς ο αλγόριθμος σύνδεσης Index Nested Loop Join (INLJ).

Συνάρτηση save_statistics:

Χρησιμοποιείται για την αποθήκευση των στατιστικών μας.

Συνάρτηση load_statistics:

Χρησιμοποιείται για την φόρτωση των στατιστικών μας.

Συνάρτηση calculate_tables_statistics:

Χρησιμοποιείται για τον υπολογισμό των στατιστικών μας.

Συνάρτηση print_statistics:

Χρησιμοποιείται για το τύπωμα των στατιστικών.

Συνάρτηση create_index:

Κάναμε τις απαραίτητες αλλαγές ώστε να υποστηρίζεται το ευρετήριο btree όσο και το hash. Γίνονται όλοι οι απαραίτητοι ελέγχοι ώστε να διασφαλίζεται η σωστή δημιουργία των ευρετηριών.
Παραδοχή: Δεν μπορεί ένα πεδίο να έχει 2 ευρετηρία.


Συνάρτηση _construct_index:

Κάναμε τις απαραίτητες αλλαγές ώστε να υποστηρίζεται και η δημιουργία του ευρετηρίου hash.

Συνάρτηση _has_index:

Προσθέσαμε την δυνατότητα να γίνεται έλεγχος αν ένας πίνακας περιέχει ευρετήριο πάνω σε συγκεκριμένη στήλη.

Αρχείο table.py

Σημείωση: Έχουμε διαγράψει την συνάρτηση 'select_where_with_btree' καθώς δεν μας ήταν χρήσιμη πλέον.

Συνάρτηση __init__:

Κάναμε τις απαραίτητες προσθήκες ώστε ένας πίνακας να έχει στα χαρακτηριστικά του και τα unique πεδία.

Συνάρτηση _insert:

Προσθέσαμε τους απαραίτητους ελέγχους ώστε να γίνεται σωστή εισαγωγή εγγραφών.

Συνάρτηση _update_rows:

Στην γραμμή 164 καλείται η συνάρτηση 'find_rows_by_condition', η οποία μας επιστρέφει την θέση κάθε εγγραφής (προς ενημέρωση) του πίνακα. Η συνάρτηση 'find_rows_by_condition' θα επεξηγηθεί παρακάτω.

Συνάρτηση _delete_where:

Στην γραμμή 186 καλείται η συνάρτηση 'find_rows_by_condition', η οποία μας επιστρέφει την θέση κάθε εγγραφής (προς διαγραφή) του πίνακα.

Συνάρτηση _select_where:

Η συνάρτηση _select_where παίρνει 2 νέα ορίσματα, το 'btree_dic' και 'hash_dic'. Στην περίπτωση που ο πίνακας υποστηρίζει αναζήτηση μέσω ευρετηρίου, τα λεξικά θα περιέχουν τα αντίστοιχα αντικείμενα (btree, hash). Όπως αναφέρθηκε παραπάνω, η συνάρτηση 'find_rows_by_condition' επιστρέφει την θέση κάθε εγγραφής που αναζητείται (αυτό μπορεί να γίνει είτε μέσω ευρετηρίου, είτε μέσω γραμμικής αναζήτησης και για αυτό στέλνουμε τα 2 λεξικά σαν όρισμα).

Συνάρτηση show:

Έχουμε προσθέσει την λέξη '#UNIQUE#' δίπλα από την ονομασία κάθε 'unique' πεδίου.

Συνάρτηση find_rows_by_condition:

Η κύρια λειτουργία της συνάρτησης είναι να διασχίζει το δοθέν λεξικό (πλάνο εκτέλεσης) σε βάθος. Αυτό επιτυγχάνεται καλώντας τον εαυτό της για κάθε left και right των operators and/or/between ή αν έχουμε operator not για την συνθήκη που ακολουθείται. Όταν φτάσει στο τέλος και εντοπίσει μια απλή συνθήκη, ψάχνει είτε μέσω ευρετηρίου, είτε μέσω γραμμικής αναζήτησης.

Αρχείο evaluate_query_plans.py

Παραδοχές:
  1. Έχουμε μόνο ερωτήσεις ταυτότητας για την κοστολόγηση.
  2. Τα 'select' προσμετρούνται πάντα στο κόστος, ασχέτως αν η επιλογή επιστρέφει όλες τις στήλες.
  3. Αν έχουμε query όπως (SELECT * FROM E1 JOIN E2 ON θ1 AND θ2) δεν υποστηρίζεται η κοστολόγηση του, όταν όμως δημιουργηθούν ισοδύναμα πλάνα εκτέλεσης όπως (SELECT * FROM E1 JOIN E2 ON θ2 WHERE θ1(παραδοχή ότι η σύνδεση γίνεται στο θ2 και όχι στο θ1)) τότε υποστηρίζεται η κοστολόγηση του.

Συνάρτηση evaluate_select_clause:

Είναι βοηθητική συνάρτηση για τον υπολογισμό του κόστους των ισοδύναμων πλάνων εκτέλεσης που δημιουργήσαμε.

Συνάρτηση evaluate_query_plans:

Υπολογίζει το κάθε κόστος των queries που βρίσκονται στη λίστα 'queries' και μας επιστρέφει το query με το ελάχιστο κόστος.

Αρχείο query_plans.py

Οι κανόνες ΣΑ που υποστηρίζονται για την παραγωγή των ισοδύναμων πλάνων εκτέλεσης είναι οι εξής:
  1. Conjunctive selection operations can be deconstructed into a sequence of individual selections; cascade of σ.
    RA:σθ1∧θ2(E)
    SQL:SELECT * FROM E WHERE θ1 AND θ2;
    =
    RA:σθ1(σθ2(E))
    SQL:SELECT * FROM (SELECT * FROM E WHERE θ2) WHERE θ1;

  2. Selection operations are commutative:
    RA:σθ1(σθ2(E))
    SQL:SELECT * FROM (SELECT * FROM E WHERE θ2) WHERE θ1;
    =
    RA:σθ2(σθ1(E))
    SQL:SELECT * FROM (SELECT * FROM E WHERE θ1) WHERE θ2;

  3. Only the final operations in a sequence of projection operations is needed, the others can be omitted; cascade of Π.

    RA:ΠL1(ΠL2(. . .(ΠLn(E)). . .))
    SQL:SELECT L1 FROM (SELECT L2 FROM (...SELECT Ln FROM E ...))
    =
    RA:ΠL1(E)
    SQL:SELECT L1 FROM E;

  4. Selections can be combined with Cartesian products and theta joins:

    RA:σθ1(E1 |><|θ2 E2)
    SQL:SELECT * FROM E1 JOIN E2 ON θ2 WHERE θ1;
    =
    RA:E1 |><|θ1∧θ2 E2
    SQL:SELECT * FROM E1 JOIN E2 ON θ1 AND θ2;

  5. Theta join operations are commutative:

    RA:E1 |><|θ E2
    SQL:SELECT * FROM E1 JOIN E2 ON θ;
    =
    RA:E2 |><|θ E1
    SQL:SELECT * FROM E2 JOIN E1 ON θ;

Συνάρτηση get_final_from:

Χρησιμοποιείται για τον τρίτο κανόνα της ΣΑ.

Συνάρτηση count_selects:

Χρησιμοποιείται για την εύρεση πλήθους των 'select' clause, που βρίσκονται μέσα στο πλάνο εκτέλεσης που μας επέστρεψε η συνάρτηση 'interpret' (του mdb.py).

Συνάρτηση check_query:

Η συνάρτηση 'check_query' εκτελείται ώστε να ελέγξει αν εφαρμόζονται οι κανόνες ΣΑ που υποστηρίζονται παραπάνω.

Συνάρτηση multiple_query_plans:

Εάν το query υποστηρίζει την παραγωγή ισοδύναμων πλάνων εκτέλεσης (βάσει των παραπάνω κανόνων ΣΑ), δημιουργεί ισοδύναμα πλάνα εκτέλεσης για το δοθέν query. Επιστρέφει μια λίστα με τα ισοδύναμα πλάνα εκτέλεσης και μια λογική τιμή όπου καθορίζει έαν πρέπει να εκτελεστεί η συνάρτηση 'evaluate_query_plans' (του evaluate_query_plans.py) μέσα στην κύρια συνάρτηση (του mdb.py). Αν δεν υποστηρίζεται από τους πιο πάνω κανόνες ΣΑ, επιστρέφει μια λίστα με το αρχικό query και μια λογική τιμή όπου δεν επιτρέπει στην συνάρτηση 'evaluate_query_plans' να εκτελεστεί.

Αρχείο extendible_hasing.py

Η κλάση ExtendibleHashing υλοποιεί τον επεκτάσιμο κατακερματισμό. Επιλέξαμε ο κατακερματισμός να γίνεται βάσει του LSB (Least Significant Bit).

Συνάρτηση __init__:

Παίρνει ως πρώτο όρισμα τον πλήθος bit που θα χρησιμοποιηθούν αρχικά για την κατανομή του κάθε κλειδιού στο αντίστοιχο bucket και αποθηκεύεται στο μεταβλητή bits. Σαν δεύτερο όρισμα παίρνει τον μέγιστο αριθμό εγγραφών που μπορεί να έχει ο κάθε bucket και τον αποθηκεύει μέσα στην μεταβλητή bucket_size. Επίσης, βάσει του πλήθος bit που θα δοθούν, δημιουργούνται και οι αντίστοιχοι bucket.

Συνάρτηση _hash:

Αντιστοιχεί στην συνάρτηση κατακερματισμού.

Συνάρτηση _add:

Προσθέτει στον κατάλληλο bucket τον συνδυασμό κλειδιού (key) και τιμής (value).

Συνάρτηση _remove:

Αφαιρεί απο συγκεκριμένο bucket τον συνδυασμό κλειδιού (key), τιμής (value) και επιστρέφει True αν ήταν επιτυχής, αλλιώς επιστρέφει False.

Συνάρτηση _get:

Επιστρέφει την τιμή (value) ενός συγκεκριμένου δοθέντος κλειδιού. Αν δεν βρεθεί επιστρέφει None.

Συνάρτηση _split:

Η συνάρτηση '_split' καλείται όταν ο bucket που θέλουμε να γίνει εισάγωγη ενός κλειδιού (key), τιμής (value) είναι γεμάτος και επομένως πρέπει να δημιουργηθούν νέοι bucket και να γίνει διαχωρισμός των εγγραφών του.

Συνάρτηση _print:

Η συνάρτηση '_print' καλείται για το τύπωμα του πίνακα κατακερματισμού.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants