go backsqlschool blogs list

Μια μικρή βουτία στα άδυτα της αρχιτεκτονικής μιας βάσης

by Antonios Chatzipavlis

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

Θα μιλήσουμε εδώ γιa την αρχιτεκτονική μιας database στον SQL Server, από τι αποτελείτε μια database, πιο είναι το ιδανικό αρχικό μέγεθος δημιουργίας της, τι πολιτική να ορίσω για το growth της.

Μια database στον SQL Server αποτελείτε από τουλάχιστον 2 αρχεία. Το ένα από αυτά είναι το data αρχείο και το άλλο είναι το log αρχείο. Εάν δεν ορίσω κάτι συγκεκριμένο κατά την δημιουργία της database, αυτή είναι ένα πιστό αντίγραφο της model database που έχει ο SQL Server. Δηλαδή έχει όλα τα περιεχόμενα και το μέγεθος της model database. Γενικότερα να γνωρίζεται ότι κάθε φορά που φτιάχνεται μια database αυτή είναι ένα αντίγραφο της model database τουλάχιστον ως προς τα περιεχόμενα της, μιας και κατά την δημιουργία έχουμε την δυνατότητα να αλλάξουμε το μέγεθος, το location που θα είναι τα αρχεία της database και ένα σωρό άλλα options και παραμέτρους.

Αν αναρωτιέστε ποια είναι τα περιεχόμενα της model database, αυτά είναι τα database system catalogs και τυχόν δικά μας objects όπως tables, views, stored procedures κλπ που έχουμε φτιάξει στην model με σκοπό να τα έχουμε διαθέσιμα στις νέες δικιές μας databases. (Παρατήρηση: Εάν έχω ήδη δικίες μου databases και φτιάξω στην model ένα νέο δικό μου object (πχ table) τότε αυτό δεν θα πάει και στις ήδη υπάρχουσες αλλά μόνο στις νέες).

Όπως είπα και πιο πάνω μια database έχει τουλάχιστον 2 αρχεία το data file και το log file. Μια database μπορεί να έχει μέχρι 32.767 αρχεία. Το μέγεθος της μπορεί να φτάσει στα 524.258 ΤΒ για τις εκδόσεις 2005 και 2008 και στα 1.048.512 ΤΒ για τις εκδόσεις 2000 και 7.0. Κάθε data file δεν μπορεί να είναι μεγαλύτερο από 16 ΤΒ για τις εκδόσεις 2005 και 2008 και 32 ΤΒ για 2000 και 7.0, ενώ το κάθε log file δεν μπορεί να είναι μεγαλύτερο των 2 ΤΒ για τις εκδόσεις 2005 και 2008, 32 ΤΒ στην έκδοση 2000 και 4 ΤΒ στην έκδοση 7.0.

Όταν δημιουργούμε μια database συνήθως ορίζουμε το αρχικό μέγεθος δημιουργίας της, τόσο για το data όσο και για το log file. O χώρος αυτός καταλαμβάνεται άμεσα από το δίσκο μας. Δηλαδή αν φτιάξω μια βάση με 10 ΜΒ data file και 3 ΜΒ log file τότε έχω μείον 13 ΜΒ από τα διαθέσιμα του δίσκου μου.

imageΚάθε data file χωρίζεται εσωτερικά σε σελίδες (pages) των 8ΚΒ (8.192 Β), στις οποίες αποθηκεύονται τα δεδομένα που έχω στην βάση (data, metadata, indexes). Κάθε 8 συνεχόμενες σελίδες μου κάνουν ένα extent (64 ΚΒ ήτοι 16 extents / 1 ΜΒ). Υπάρχουν δύο είδη extent τα uniform (και οι 8 σελίδες ανήκουν στον ίδιο object πχ. Table) και τα mixed (οι 8 σελίδες δεν ανήκουν στο ίδιο object αλλά σε περισσότερα από ένα) .

 

image Σε κάθε data file οι πρώτες 8 σελίδες είναι εξ ορισμού δεσμευμένες από κάποιες ειδικού χειρισμού σελίδες που στην ουσία κάνουν trace τον ελεύθερο και δεσμευμένο χώρο σε αυτό. Αυτές είναι οι File Header (FH), Page Free Space (PFS), Global Allocation Map (GAM), Shared Global Allocation Map (SGAM) (περισσότερα)

image Κάθε σελίδα όπως είπα και πιο πάνω είναι 8 ΚΒ. Από αυτά τα 96 ΚΒ είναι ο page header στον οποίο είναι αποθηκευμένες οι εξής πληροφορίες page number, page type, το ποσό του free space στην σελίδα, και το allocation unit ID του object στο οποίο ανήκει η σελίδα. Με το που βάζω το πρώτο record αυτό μπαίνει αμέσως μετά από τον header και στο τέλος της σελίδα υπάρχει το record offset το οποίο μπαίνει με την αντίστροφη σειρά της εισαγωγής. Άρα ο πραγματικός ωφέλιμος χώρος που έχω πάνω σε κάθε σελίδα είναι 8060 bytes. Αυτό είναι και το μέγιστο record length που μπορώ να έχω πάνω σε ένα πίνακα. Δηλαδή εάν έχω ένα πίνακα που το record length του είναι 100 bytes αυτό σημαίνει ότι σε κάθε σελίδα χωράνε 80 records, και αν ο πίνακας έχει 200 εγγραφές τότε θέλω 3 σελίδες για να αποθηκευτούν τα δεδομένα του. (περισσότερα). Επίσης θα πρέπει να το τονίσω σε αυτό το σημείο ότι ένα record ανήκει πάντα σε μια σελίδα, δεν υπάρχει ποτέ περίπτωση να είναι το μισό σε μια και το άλλο σε άλλη. Θα προλάβω μερικούς συναδέλφους που θα πουν για τα datatypes varchar(max), nvarchar(max), text, ntext, images, varbinary(max) ότι είναι σε άλλες σελίδες αλλά είναι εκεί λόγω μεγέθους.

Αυτό που σας έχω αναφέρει μέχρι τώρα είναι αρκετά σημαντικό για τον σχεδιασμό των tables, indexes σε μια database στον SQL Server. Διότι κυρίες και κύριοι συνάδελφοι εάν κάποιος αρχίζει και βάζει πεδία μέσα στον πίνακα (μέχρι 1024 πεδία μπορεί να έχει ένας πίνακας) και φτιάξει ένα record length 5000 bytes αυτό σημαίνει ότι μέσα σε μια σελίδα μπαίνει ένα και μόνο ένα record και μένουν ανεκμετάλλευτα 3000 bytes. Εάν λοιπόν ο πίνακας μου έχει 10.000 records σημαίνει ότι θέλω και 10.000 σελίδες που στην κάθε μία χάνω 3.000 bytes, άρα 3.000 bytes x 10.000 σελίδες = 30.000.000 bytes / 1024 bytes = 29296 KB / 1024 KB=28 MB χαμένου χώρου στον δίσκο, μιας και αν θεωρήσουμε ότι υπάρχει μόνο αυτός ο πίνακας στην βάση μας (κάτι φυσικά που δε συμβαίνει στην πραγματικότητα) το data file μας έχει δεσμεύσει χώρο στο δίσκο ίσο με 78 ΜΒ. Όπως γίνεται άμεσα κατανοητό ο κακός σχεδιασμός επηρεάζει άμεσα και το performance πώς? η απάντηση σε λίγο.

Επίσης όταν δημιουργούμε μια database σκόπιμο θα είναι να έχουμε κάνει μια εκτίμηση για το μέγεθος για τους πρώτους 3 μήνες της ζωής της ώστε να δεσμεύσουμε τον χώρο αυτό κατά την στιγμή της δημιουργίας της. Ο σκοπός του να γίνει κάτι τέτοιο είναι σημαντικός διότι αν δώσουμε κάτι το οποίο είναι μικρό και σε συνδυασμό με το τι έχουμε ορίσει σαν file growth policy, που συνήθως το αφήνουμε μικρό, και έχουμε μεγάλο αριθμό από transactions αυτό θα μας οδηγήσει μαθηματικά στο να έχουμε συνεχόμενο ΙΟ στον δίσκο μας επειδή ο SQL Server θα αιτείτε συνέχεια επιπλέον χώρο σε αυτόν μέσω του λειτουργικού συστήματος καθώς η database θα γεμίζει συχνότερα. Αυτό είναι καταστροφικό σε συστήματα που έχουν πολλά transactions.

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

Πρώτα από όλα επιλέγουμε μια χρονική περίοδο για την εκτίμηση μας πχ 1 μήνα , 2 μήνες κλπ ανάλογα με το είδος της εφαρμογής που χρησιμοποιεί την database, πχ σε ένα ERP θα μπορούσαμε διαλέξουμε 3 μήνες.

Έπειτα βρίσκω το record length του κάθε πίνακα αυτό το πολλαπλασιάζω με τον αριθμό των records που εκτιμώ ότι θα μπουν στην χρονική περίοδο που έχω διαλέξει. Το αποτέλεσμα τα κάνω σελίδες και τις σελίδες τις κάνω MB. Το ίδιο αλλά κάπως διαφοροποιημένο το κάνω και για τους indexes. Το άθροισμα όλων αυτών μου δίνει το αρχικό μέγεθος δημιουργίας της database μου.

Δεν θα το αναλύσω περισσότερο εδώ απλά θα σας παραπέμψω στα books online όπου έχει αναλυτικά όλη την διαδικασία. Απλά κάντε αναζήτηση για Estimating the Size of a Database.

Μέχρι τώρα δεν έχω αναφέρει τίποτα για το άλλο αρχείο που έχει μια database, το log αρχείο. Προσωπικά πιστεύω ότι είναι το σημαντικότερο αρχείο σε μία database. Σε αυτό καταγράφονται όλα εκτός από τα select statements και τα blob πεδία αν και αυτά έχω την επιλογή να πω να καταγράφονται. Συνήθως το αρχικό μέγεθος δημιουργίας του είναι το 30% του αρχικού μεγέθους του ή των data αρχείου (αρχείων). Δηλαδή αν έχω 100 ΜΒ data φτιάχνω log ίσο με 30ΜΒ. Βέβαια αυτό αν και είναι κανόνας, πάντα υπάρχει περιθώριο καταστρατήγησης του, όπως για παράδειγμα αν έχω heavily transactional databases, όπου σε αυτές τις περιπτώσεις είναι ανάλογα μεγαλύτερο. Έδω όμως θα τονίσω ότι χρειάζεται ιδιαίτερη προσοχή στην πολιτική για το πως αυτό θα μεγαλώνει όταν γεμίσει. Αυτό που έχω δει είναι ότι συνήθως βάζετε κάτι μικρό ή αφήνετε το default που είναι 10%. Αυτό είναι και το λάθος σας. Καλό είναι να βάζετε σαν πολιτική το αρχικό μέγεθος του. Δηλαδή αν έχω 30ΜΒ Log λέω στo file growth του 30ΜΒ ούτε 100% ούτε τίποτα σε ποσοστό. Και αυτό γιατί πολλοί θεωρούν το Log σαν έναν κουβά όμως τα πράγματα δεν είναι έτσι. Εσωτερικά το log χωρίζεται σε virtual logs. Ο σκοπός μου είναι να έχω πάντα ισομεγέθη virtual log ώστε να μην μου εμφανισθεί το φαινόμενο το Log file να είναι μεγαλύτερο από το ή τα data file(s). Σε κάποιο άλλο post μου θα σας πω περισσότερα για αυτό.

Τώρα βέβαια θα πρέπει να πω ότι αν παίρνω backup την βάση μου το log γίνεται truncate. Προσοχή δεν μειώνεται σαν μέγεθος στον δίσκο αλλά εσωτερικά γίνεται truncate. Αυτό σημαίνει ότι ο εσωτερικός χώρος που ελευθερώνεται επαναχρησιμοποιείται. Λογικά αν έχω εκτιμήσει σωστά το αρχικό μέγεθος δημιουργίας του log file και κάνω καθημερινό backup δεν θα το δω ποτέ να μεγαλώνει πέρα από το αρχικό του μέγεθος.

Για να δούμε πως χρησιμοποιείται το log. Τρεις είναι οι βασικοί παράγοντες που επηρεάζουν το performance, CPU, MEMORY, DISK IO. Δυστυχώς όμως το χειρότερο από όλα σε performance σε σχέση με τα άλλα είναι ο δίσκος. Σκοπός του SQL Server είναι να έχει το μικρότερο δυνατό disk io. Για να το κάνει αυτό χρησιμοποιεί μνήμη και φυσικά το log file.

O SQL Server δεσμεύει ένα ποσό από την διαθέσιμη μνήμη του συστήματος. Ένα ποσό από αυτή την μνήμη ανήκει στη buffer cache. Για να δούμε όλη την διαδικασία με ένα παράδειγμα.

Είπαμε πιο πάνω ότι τα δεδομένα μου είναι αποθηκευμένα σε σελίδες των 8KB. Έτσι όταν κάποιος χρήστης κάνει ένα select, insert, update, delete αυτό που κάνει ο SQL Server είναι να δει αν υπάρχουν στην buffer cache οι σελίδες που θα επηρεαστούν από την ενέργεια αυτή. Εάν δεν είναι τότε τις διαβάζει από τον δίσκο και τις βάζει στην buffer cache. Το επόμενο βήμα του είναι να εκτελέσει την ενέργεια πάνω στις σελίδες που είναι στην buffer cache. Για το μεν select επιστρέφει τα δεδομένα στον χρήστη, για τις άλλες ενέργειες όμως κάνει ακόμα ένα βήμα γράφει την ενέργεια στο log file. Γιατί το κάνει αυτό; Η απάντηση είναι απλή κάνει minimize το ΙΟ. Στην ουσία οι ενέργειες θα γραφτούν στο data file όταν γίνει η διαδικασία που φέρει το όνομα checkpoint process. Τι κάνει αυτή; Σε τακτά χρονικά διαστήματα έρχεται ο SQL Server και διαβάζει το log είτε από την αρχή εάν είναι η πρώτη φορά είτε από το σημείο που είχε σταματήσει την προηγούμενη φορά η διαδικασία αυτή. Και όσα transactions είναι commited βλέπει ποιες είναι οι σελίδες που έχουν επηρεασθεί από αυτά και τις γράφει στον data file δηλαδή στον δίσκο. Τώρα κάποιος θα αναρωτηθεί και αν πέσει το ρεύμα πριν γίνει η διαδικασία αυτή; ΔΕΝ ΥΠΑΡΧΕΙ ΚΑΝΕΝΑ ΠΡΟΒΛΗΜΑ. Διότι κάθε φορά που ο SQL Server ξεκινάει κοιτάζει το Log file και ότι transaction είναι ολοκληρωμένο και δεν υπάρχει στα data file αναπαράγετε, ότι ήταν σε εξέλιξη γίνεται rollback. Η διαδικασία αυτή λέγεται recovery process. Άρα θα έχω όλα μου τα δεδομένα εκτός βέβαια από αυτά που δεν είχαν προλάβει να ολοκληρωθούν.

Σας χρωστάω μια απάντηση από πιο πάνω. Θυμηθείτε το παράδειγμα με τις 10.000 σελίδες όπου στην κάθε μία έχω ένα record. Βάλτε με το μυαλό σας τι θα γίνει αν απλά θελήσω να διαβάσω όλα τα δεδομένα του πίνακα. Απλά θα έχω "τσακίσει" τους τρεις βασικούς παράγοντες που επηρεάζουν την απόδοση του SQL Server, και αυτό γιατί για να κινηθούν οι κεφάλες στον δίσκο θα πρέπει να δώσει η εντολή η CPU αυτές θα διαβάσουν τα δεδομένα , άρα μεγάλο ΙΟ και αυτά θα πρέπει αν μεταφερθούν στην μνήμη.

Έτσι απλά! τα φόρτωσα όλα, και αυτό γιατί όταν σχεδίαζα την βάση μου δεν έλαβα υπόψη μου την αρχιτεκτονική του SQL Server.

Ημερομηνία: 07 October 2009 14:46
Αξιολόγηση:
Κατηγορίες:
Tags:
Share it:

Αφήστε το σχόλιο σας - Leave your comment

Τα σχόλια έχουν κλείσει.
Επιτρέπονται μόνο τα σχόλια από τα μέλη του SqlSchool.gr.


newsletter subscription

Εάν επιθυμείτε να λαμβάνετε ενημέρωση από εμάς, δώστε μας το e-mail σας.
PASS chapter logo
Official Professional Association for SQL Server (PASS) chapter for Greece
Join to PASS