Πολλά πράγματα μέσα στον SQL Server γίνονται με βάση το LSN (Log Sequence Number). Αρκετές πάλι είναι οι ερωτήσεις που δέχομαι για αυτό και κυρίως αφορούν πως αυτό μεταφράζεται. Μέσα από αυτό το άρθρο θα προσπαθήσω να το εξηγήσω όσο καλύτερα και ευκολότερα γίνεται.
Αρχικά θα πρέπει να αναφερθεί αυτούσιο αυτό που τα BOL γράφουν σχετικά με το LSN
"Every record in the SQL Server transaction log is uniquely identified by a log sequence number (LSN). LSNs are values of data type numeric(25,0). Arithmetic operations (for example, addition or subtraction) are not meaningful and must not be used with LSNs"
Αυτό σημαίνει ότι υπάρχει συνεχόμενη αύξουσα σειρά το οποίο σημαίνει ότι το μεγαλύτερο μεταξύ δυο LSNs είναι και το πρόσφατο.
Επίσης θα πρέπει να επισημανθεί ότι συναντάμε το LSN σε αρκετά σημεία μέσα στο SQL Server ιδιαίτερα στα backups αλλά και σε metadata DMVs που αφορούν πληροφορίες σχετικά με την εκάστοτε database.
Σε αυτά όλα τα σημεία συναντάμε το LSN σε δύο μορφές.
Η μία είναι στην μορφή ΧΧΧΧΧΧΧΧ:ΧΧΧΧΧΧΧΧ:ΧΧΧΧ και η άλλη σαν αριθμό.
Στην πρώτη μορφή όπως φαίνεται υπάρχουν τρία τμήματα τα οποία χωρίζονται με το χαρακτήρα column (:) και το πρώτο και δεύτερο είναι 8 χαρακτήρες και το τρίτο 4 χαρακτήρες και οι τιμές σε αυτά είναι σε HEX (δεκαεξαδικό).
Το πρώτο από αυτά είναι ο αριθμός του Virtual Log File (VLF) στο οποίο βρίσκεται το συγκεκριμένο log record.
To δεύτερο είναι το offset από το οποίο ξεκινάει το συγκεκριμένο log record μέσα στο VLF.
Το τρίτο είναι ο slot number μέσα στο VLF στο οποίο υπάρχει το log record.
(Μπορείτε να δείτε τα σχετικά μου άρθρα & videos στο SQLschool.gr σχετικά με τα VLFs εύκολα με μια απλή αναζήτηση με το keyword VLF)
Επειδή όπως είπα και παραπάνω οι τιμές είναι σε HEX αλλά στο SQL Server δεν υπάρχει function που να κάνει convert σε δεκαδικό χρησιμοποιούμε την convert function στην οποία στην τιμή του κάθε τμήματος προσθέτουμε το '0x' και αυτό το κάνουμε varbinary με style=1 στο αντίστοιχο όρισμα της convert πχ convert(varbinary,'0x'+left ([current lsn],8),1).
Δεν θα σας κουράσω με λόγια καθώς ο παρακάτω κώδικας είναι αρκετά εύκολος και περιγράφει με λεπτομέρεια την διαδικασία εύρεσης των τιμών και την μετατροπή του LSN από την πρώτη μορφή στην δεύτερη δηλαδή σε αριθμό.
Για το ανάποδο θα πρέπει να ακολουθηθεί η αντίστροφη διαδικασία.
Μια όμως παρατήρηση έχω για να σας προλάβω και να μην έχετε προβλήματα.
Όπως θα δείτε χρησιμοποιώ την fn_dblog function με την οποία μπορεί κάποιος να διαβάσει τα περιεχόμενα του log σε μια database. Αυτό το κάνω σε ένα περιβάλλον που είναι για lab. Φυσικά και μπορείτε να το κάνετε και σε παραγωγικό περιβάλλον απλά πρέπει να ξέρετε ότι η συγκεκριμένη function μπορεί να πάρει αρκετή ώρα μέχρι να φέρει αποτέλεσμα και όση ώρα εκτελείται δημιουργεί καθυστερήσεις.
use TSQLV4;
select
[Current LSN],
-- part 1
left ([current lsn],8) as lsn_part1,
convert(varbinary,'0x'+left ([current lsn],8),1) as hex_of_lsn_part1,
cast(convert(varbinary,'0x'+left ([current lsn],8),1) as int ) as int_of_lsn_part1_is_vlf_id,
-- part 2
substring([current lsn],10,8) as lsn_part2,
convert(varbinary,'0x'+substring([current lsn],10,8),1) as hex_of_lsn_part2,
cast(convert(varbinary,'0x'+substring([current lsn],10,8),1) as int) as int_of_lsn_part2_is_offset_in_log_block,
-- part 3
RIGHT([current lsn],4) as lsn_part3,
convert(varbinary,'0x'+RIGHT([current lsn],4),1) as hex_of_lsn_part3,
cast(convert(varbinary,'0x'+RIGHT([current lsn],4),1) as int) as int_of_lsn_part3_is_slot_num_inlog_block,
-- lsn as a number
cast (right('00000000'+cast(cast(convert(varbinary,'0x'+left ([current lsn],8),1) as int ) as varchar(8)),8)+
right('00000000'+cast(cast(convert(varbinary,'0x'+substring([current lsn],10,8),1) as int) as varchar(8)),8)+
right('00000'+cast(cast(convert(varbinary,'0x'+RIGHT([current lsn],4),1) as int) as varchar(5)),5) as bigint ) as lsn_in_number_format
from fn_dblog(null,null);
//antonch