Όταν εργαζόμαστε με το πλαίσιο Ruby on Rails, συνήθως ασχολούμαστε με σχεσιακές βάσεις δεδομένων όπως η MySQL ή η PostgreSQL. Κατά τον ορισμό των μεταναστεύσεων με τη χρήση των Active Record Migrations, συναντάμε τα λεγόμενα ευρετήρια, αλλά οι αρχάριοι συχνά δεν κατανοούν αρκετά τα ευρετήρια και τα οφέλη που προσφέρουν.
Όταν εργαζόμαστε με το πλαίσιο Ruby on Rails, συνήθως ασχολούμαστε με σχεσιακές βάσεις δεδομένων όπως η MySQL ή η PostgreSQL. Κατά τον ορισμό των μεταναστεύσεων με τη χρήση των Active Record Migrations, συναντάμε τα λεγόμενα ευρετήρια, αλλά οι αρχάριοι συχνά δεν κατανοούν αρκετά τα ευρετήρια και τα οφέλη που προσφέρουν.
Σε αυτή τη δημοσίευση, θα ήθελα να εξηγήσω τι είναι τα ευρετήρια, για ποιο λόγο χρησιμοποιούνται και να παρουσιάσω ορισμένες καλές πρακτικές για το πώς να τα χρησιμοποιείτε.
Βάση δεδομένων
Υπάρχουν πολλές μηχανές βάσεων δεδομένων και μία από τις πιο δημοφιλείς είναι οι προαναφερθείσες MySQL, PostgreSQL, Oracle ή Microsoft SQL Server. Όλες είναι σχεσιακές βάσεις δεδομένων, πράγμα που σημαίνει ότι όλα τα δεδομένα σχετίζονται μεταξύ τους και αποθηκεύονται σε πίνακες. Κάθε γραμμή του πίνακα ονομάζεται εγγραφή (record) και κάθε μία έχει το δικό της μοναδικό αναγνωριστικό (id). Μπορείτε να ελέγξετε την κατάταξη των πιο δημοφιλών μηχανών βάσεων δεδομένων στη διεύθυνση https://db-engines.com/en/ranking. Εκεί θα βρείτε και ορισμένες μη σχεσιακές βάσεις δεδομένων, όπως η MongoDB.
Δημιουργία ευρετηρίου
Οι πίνακες στις βάσεις δεδομένων μας μπορεί να έχουν από λίγες έως αρκετές δεκάδες - σε ακραίες περιπτώσεις, έως και αρκετές εκατοντάδες - στήλες. Λάβετε υπόψη ότι κάθε πίνακας μπορεί να έχει απεριόριστο αριθμό γραμμών. Ο αριθμός αυτός δεν προκύπτει άμεσα από τη δομή της βάσης δεδομένων και θα πρέπει πάντα να υποθέτουμε ότι ο αριθμός των εγγραφών θα αυξάνεται διαδοχικά και, κατά συνέπεια, η βάση δεδομένων μας θα μεγαλώνει. Οι αρχικές παραδοχές και τα ερωτήματα που γράφονται σε υπάρχουσες εφαρμογές μπορεί να είναι πολύ καλά για ένα μικρό ή μεσαίο αριθμό εγγραφών, αλλά με την πάροδο του χρόνου, όταν φτάνουν περισσότερα δεδομένα, η επικοινωνία της εφαρμογής με τη βάση δεδομένων παύει να είναι αποδοτική.
Ο ρόλος του προγραμματιστή είναι να γράφει ερωτήματα για την ανάκτηση κάποιων δεδομένων από τον πίνακα ή τους πίνακες, αλλά ο βέλτιστος τρόπος επεξεργασίας του ερωτήματος εξαρτάται από τη μηχανή της βάσης δεδομένων. Θυμηθείτε ότι οι μηχανές βάσεων δεδομένων φορτώνουν δεδομένα από το δίσκο στη μνήμη και στη συνέχεια τα σαρώνουν. Αυτό σημαίνει ότι αν πολλοί χρήστες εκτελούν σύνθετες λειτουργίες ταυτόχρονα, αρκετοί από αυτούς θα πρέπει να περιμένουν τη σειρά τους λόγω της έλλειψης πόρων για την υλοποίηση των αναζητήσεών τους. Αυτός είναι ο λόγος για τον οποίο τα σχετικά ευρετήρια είναι τόσο σημαντικά.
Wiki: Ευρετήριο - μια δομή δεδομένων που αυξάνει την ταχύτητα εκτέλεσης πράξεων αναζήτησης σε έναν πίνακα.
Για κάθε ευρετήριο, πρέπει να ορίσουμε τα κλειδιά (για μία ή πολλές στήλες) που θα χρησιμοποιούνται για την αναζήτηση εγγραφών στον πίνακα. Τα δεδομένα στο ευρετήριο θα ταξινομούνται με το κλειδί που έχει οριστεί προηγουμένως, γεγονός που θα επιταχύνει σημαντικά την αναζήτηση δεδομένων στον πίνακα. Το απλούστερο παράδειγμα από την καθημερινή ζωή είναι ένας τηλεφωνικός κατάλογος στον οποίο οι άνθρωποι ταξινομούνται με βάση το όνομα και το επώνυμο. Μπορούμε να πούμε ότι το ευρετήριό μας σε αυτή την περίπτωση θα είναι το όνομα και το επώνυμο.
Πώς επιλέγετε το καλύτερο κλειδί ευρετηρίου; Δεν είναι δύσκολο - απλά θυμηθείτε μερικούς κανόνες. Δημιουργήστε ένα ευρετήριο με βάση στήλες που:
- θα χρησιμοποιείται συχνά στις έρευνές μας (WHERE),
- σε συνδυασμό μεταξύ τους δίνουν μια μοναδική τιμή (δηλαδή μια τιμή που θα υποδεικνύει ακριβώς μια σειρά),
- θα χρησιμοποιηθούν ως λεγόμενες συνδετικές στήλες (JOIN),
- δίνουν τα πιο επιλεκτικά κλειδιά, δηλαδή εκείνα που επιστρέφουν τον μικρότερο αριθμό γραμμών κατά τη σύνταξη ενός ερωτήματος.
Εάν γνωρίζουμε ήδη ποια κλειδιά θα είναι τα βέλτιστα για τον πίνακα μας, μπορούμε επίσης να αναρωτηθούμε πόσα ευρετήρια χρειαζόμαστε. Σε αυτή την περίπτωση, είναι καλύτερο να γνωρίζουμε τα ερωτήματα που θα αναφέρονται στον πίνακα μας ήδη από το στάδιο του σχεδιασμού.
Ας δημιουργήσουμε ευρετήρια για συγκεκριμένα ερωτήματα που θα εμφανιστούν, αλλά μην τα γράψετε για κάθε στήλη. Τα ευρετήρια, όπως και οι πίνακες, πρέπει να αποθηκεύονται κάπου, οπότε όταν δημιουργούμε πίνακες με ευρετήριο για κάθε στήλη, πρέπει να λάβουμε υπόψη ότι ο χώρος που χρησιμοποιείται μπορεί να αυξηθεί σημαντικά.
Δημιουργία μοναδικού ευρετηρίου
Ένα άλλο θέμα που πρέπει να σκεφτούμε είναι η μοναδικότητα. Αξίζει να αφιερώσουμε πέντε επιπλέον λεπτά για να σκεφτούμε αν το ευρετήριό μας είναι πραγματικά μοναδικό. Με αυτόν τον τρόπο, λέμε στον βελτιστοποιητή ερωτημάτων ότι δεν χρειάζεται να περιμένει διπλότυπα στο ερώτημα. Για παράδειγμα, διευθύνσεις ηλεκτρονικού ταχυδρομείου:
frozenstringliteral: true
class CreateUsers < ActiveRecord::Migration[6.0]
def change
createtable :users do |t|
t.string :email, null: false
end
addindex :users, :email, unique: true
end
end
Στο παράδειγμα της μηχανής PostgreSQL, θα δείξω τη διαφορά στην ταχύτητα του ερωτήματος για τη στήλη email με μοναδικό ευρετήριο και χωρίς ευρετήριο.
1. Μπορείτε να χρησιμοποιήσετε δείγμα κωδικός αποσπάσματα στη δική σας βάση δεδομένων για να μπορέσετε να δοκιμάσετε το παρακάτω παράδειγμα. Αρχικά, ας δημιουργήσουμε έναν κενό πίνακα με μία στήλη:
ΔΗΜΙΟΥΡΓΙΑ ΠΙΝΑΚΑ users (
email varchar
);
2. Ας δημιουργήσουμε 10.000 εγγραφές για τη δοκιμή:
DO $
BEGIN FOR i IN 1..10000 LOOP
INSERT INTO users values((select 'user' || i || '@example.com')),
END LOOP; END,
$,
Θα χρησιμοποιήσουμε το EXPLAIN ANALYZE για να ελέγξουμε πόσο γρήγορα θα επεξεργαστεί το ερώτημά μας όταν θέλουμε να βρούμε έναν συγκεκριμένο χρήστη στη βάση δεδομένων.
EXPLAIN ANALYZE SELECT email FROM users WHERE email = 'user890example.com',
Το ερώτημά μας ανάγκασε την επανάληψη σε ολόκληρο τον πίνακα σε αναζήτηση της εγγραφής που μας ενδιαφέρει.
Η διαδικασία αυτή ονομάζεται διαδοχική σάρωση. Στην περίπτωση αυτή, η ανάγνωση ολόκληρου του πίνακα και το φιλτράρισμα συγκεκριμένων γραμμών είναι ο καλύτερος τρόπος για να γίνει η εργασία.
Η PostgreSQL θα φιλτράρει τις περιττές γραμμές και θα επιστρέψει απλώς αυτές που μας ενδιαφέρουν. Αυτό είναι πραγματικά το καλύτερο πράγμα που μπορούμε να κάνουμε σε αυτή την περίπτωση. Η διαδοχική σάρωση δεν είναι πάντα κακή, υπάρχουν περιπτώσεις όπου η διαδοχική σάρωση είναι ιδανική.
4. Τώρα είναι η ώρα να ελέγξετε το ερώτημα που έχει ήδη γίνει στον πίνακα που έχει INDEX UNIQUE. Ας ορίσουμε τον δείκτη και ας εκτελέσουμε το ερώτημα.
EATE UNIQUE INDEX index_email on users(email),
EXPLAIN ANALYZE SELECT email FROM users WHERE email = 'user890example.com',
Αυτή τη φορά η PostgreSQL εκμεταλλεύτηκε τη σάρωση ευρετηρίου, επειδή όλες οι στήλες που απαιτούνται βρίσκονται ήδη στο ευρετήριο.
Η επιλογή λίγων μόνο γραμμών θα είναι πολύ αποτελεσματική όταν χρησιμοποιείτε το ευρετήριο. Ωστόσο, εάν επιλεγούν περισσότερα δεδομένα, η σάρωση του ευρετηρίου και του πίνακα θα είναι πολύ χρονοβόρα.
Περίληψη
Όπως μπορείτε να δείτε, ο χρόνος εκτέλεσης ενός ερωτήματος σε μια στήλη με ευρετήριο είναι πολύ μικρότερος (στο παράδειγμα που παρουσιάζεται είναι μια μείωση από 1,267 ms σε 0,111 ms, δηλαδή τόσο πολύ όσο 91,24%!). Η πιο σημαντική διαφορά είναι ο τρόπος με τον οποίο η PostgreSQL αναζητά την εγγραφή που μας ενδιαφέρει. Στην πρώτη περίπτωση, η μηχανή βάσης δεδομένων έπρεπε να ψάξει σε ολόκληρο τον πίνακα για την εγγραφή που χρειαζόμασταν. Στη δεύτερη, όμως, η δομή του ευρετηρίου είναι ταξινομημένη και μοναδική, επομένως η μηχανή ήξερε πού βρισκόταν η εγγραφή, γεγονός που επιτάχυνε σημαντικά το χρόνο επεξεργασίας του ερωτήματος.
Στην περίπτωση μεγάλων βάσεων δεδομένων και πολύ σύνθετων ερωτημάτων, τα σωστά ρυθμισμένα ευρετήρια μπορούν να επιταχύνουν σημαντικά την εργασία της εφαρμογής σας, χωρίς να χρειάζεται να αυξήσετε την ταχύτητα του μηχανήματος στο οποίο κάνετε αναζήτηση στη βάση δεδομένων.
Αξίζει να θυμάστε ότι η δημιουργία δεικτών σε κάθε στήλη δεν είναι καλή πρακτική. Τα καθιερωμένα ευρετήρια θα επιταχύνουν το έργο του βελτιστοποιητή κατά την αναζήτηση των δεδομένων που σας ενδιαφέρουν, αλλά ταυτόχρονα θα επιβραδύνουν την εισαγωγή νέων και την ενημέρωση των υπαρχόντων.