Στα τόσα χρόνια που ασχολούμαι με τον SQL Server και γενικότερα με τα data και τις databases έχω μάθει καλά ότι ο μη σεβασμός στην αρχιτεκτονική των RDBMS και ειδικότερα σε αυτό που ονομάζεται concurrency είναι η αιτία των περισσότερων "προβλημάτων" της καθημερινότητας.
Έχω μιλήσει και γράψει πολλές φορές για το θέμα concurrency και θα συνεχίσω να το κάνω με την ελπίδα επιτέλους να γίνει κατανοητό από όλες και όλους. Δεν πρόκειται να ξεκινήσω να εξηγώ το θέμα αυτό από την αρχή καθώς ήδη το έχω εξηγήσει πριν από χρόνια σε αυτό το SQL Saturday Night. Αν δεν το έχετε παρακολουθήσει , παρακολουθήστε το, αν το έχετε κάνετε επανάληψη.
Η ανάγκη ύπαρξης των locks είναι απαραίτητη, καθώς διασφαλίζουν την πιστότητα / ποιότητα των δεδομένων μας. Όταν όμως το concurrency δεν είναι αυτό που πρέπει καταλήγουμε σε blocks, που όταν αυτά είναι μεγάλα σε χρονική διάρκεια τότε δημιουργούνται προβλήματα. Σε αυτό το άρθρο μου θα εξηγήσω το πως μπορούμε να καταλάβουμε αν SQL Server instance υποφέρει εξαιτίας του σεβασμού στο concurrency κατανοώντας τα σχετικά με αυτό wait statistics.
How can get lock information
Για να μπορέσουμε να καταλάβουμε τι γίνεται θα πρέπει πρώτα να είμαστε σε θέση να βλέπουμε τι γίνεται και για αυτό το λόγο στο SQL Server έχουμε πολλά ενδιαφέροντα DMVs τα οποία πρέπει να γνωρίζουμε όπως τα sys.dm_tran_locks και sys.dm_os_waiting_tasks.
Lock Modes
Στον SQL Server έχουμε τα εξής lock modes
- Shared (S): Κάθε φορά που εκτελείται ένα select query τοποθετείται στο resource το lock αυτό.
- Update(U) : Κάθε φορά που γίνεται αλλαγή σε κάποιο resource τοποθετείται στο resource το lock αυτό.
- Exclusive (X) : Κάθε φορά που ένα transaction θέλει να κάνει αλλαγή σε κάποιο resource τοποθετείται στο resource το lock αυτό.
- Schema (Sch) : Κάθε φορά που γίνεται αλλαγή σε ένα table όπως η προσθήκη μιας νέα κολώνας τοποθετείται το lock αυτό στο table.
- Intent (I): Αυτό το είδος lock έχει σαν σκοπό να δείχνει ότι υπάρχουν locks σε χαμηλότερο επίπεδο της ιεραρχίας των locks.
Locking Hierarchy
Στον SQL Server υπάρχει μια ιεραρχία στα locks που επιτρέπει να τοποθετούνται αυτά σε διαφορετικά επίπεδα του εμπλεκόμενου objects.
Τα βασικά επίπεδα της ιεραρχίας αυτής είναι τα παρακάτω με σειρά από το υψηλότερο στο χαμηλότερο.
- Database
- Database file
- Table/Object
- Extent
- Page
- RID (heap) /KEY (clustered index)
LCK_M_S wait type
Κάθε φορά που ένα task περιμένει να τοποθετήσει ένα Shared lock σε κάποιο resources εμφανίζεται το συγκεκριμένο wait type. Αυτό σημαίνει ότι κάποιος προσπαθεί να διαβάσει data αλλά κάποιος έχει locked αυτά και για αυτό καταγράφεται το συγκεκριμένο wait type.
LCK_M_U wait type
Κάθε φορά που ένα task περιμένει να τοποθετήσει ένα Update lock σε κάποιο resources εμφανίζεται το συγκεκριμένο wait type.
Ένα update lock γίνεται όταν θέλουμε μεταβολή στα δεδομένα που γίνεται με ένα Insert/Update/Delete statement. Υπάρχει για την αποτροπή των deadlocks.
LCK_M_X wait type
Κάθε φορά που ένα task περιμένει να τοποθετήσει ένα Exclusive lock σε κάποιο resources εμφανίζεται το συγκεκριμένο wait type.
LCK_M_Ixx wait type
Κάθε φορά που ένα task περιμένει να τοποθετήσει ένα Intent lock σε κάποιο resources εμφανίζεται το συγκεκριμένο wait type.
LCK_M_IS : Intent Share lock , LCK_M_IX : Intent Exclusive lock, LCK_M_IU : Intent Update lock
LCK_M_SCH_x
Εδώ θα συναντήσουμε τα LCK_M_SCH_S & LCK_M_SCH_M wait types. Και τα δύο σχετίζονται με locks σε table level και για αυτό τα λέγονται schema locks.
To LCK_M_SCH_S ονομάζεται Schema Stability lock και τo LCK_M_SCH_M ονομάζεται Schema Modification lock
Επίλογος
Σε κάθε περίπτωση δεν σημαίνει ότι υπάρχει πρόβλημα. Πρόβλημα θα έχουμε όταν ο αριθμός εμφάνισης είναι υπερβολικά μεγάλος συνδιαστικά με το χρόνο αναμονής. Σε αυτές τις περιπτώσεις θα πρέπει να εντοπιστούν τα transactions ώστε να ελεχθούν με σκοπό την μείωση των wait types αυτών.
//antonch