Identifying In-Memory Objects When Querying the Transaction Log
Continuing on the theme of SQL Server 2016, my boss sent me a copy of Kalen Delaney's (b|t) SQL Server 2016 In-Memory Internals white paper. I delved into in-memory internals when SQL Server 2014 released, but then other projects got in the way of my delving time.
I created an in-memory table to explore the contents of the in-memory log records. To do this, I used the table-based function fn_dblog_xtp. If you are familar with fn_dblog, fn_dblog_xtp contains the same column list, with 12 new columns added. A sample SELECT statement is shown below, with the new columns highlighted:
USE yourdatabase; SELECT f.[Current LSN], f.Operation, f.Context, f.[Transaction ID], f.operation_desc, f.tx_end_timestamp, f.total_size, f.xtp_object_id f.newrow_identity, f.newrow_data, f.newrow_datasize, f.oldrow_begin_timestamp, f.oldrow_identity, f.oldrow_key_data, f.oldrow_key_datasize, f.xtp_description, f.[Log Record Fixed Length], f.[Log Record Length], f.[Flag Bits], f.[Log Reserve], f.[Log Record] FROM fn_dblog_xtp(NULL,NULL) WHERE Operation LIKE '%HK%';
The two NULL parameters being passed are the start and end Log Sequence Numbers (LSN). Passing NULLs will return all log records. The WHERE Operation LIKE '%HK%' will return only log records related to in-memory tables.
Transactions against an in-memory table will return a single row in the result set from fn_dblog, while the result set from fn_dblog_xtp will contain a row for all activity. For example, if you insert 100 rows into an in-memory table, fn_dblog will contain 3 records: a BEGIN TRANSACTION, a single row for the INSERT, and a COMMIT TRANSACTION. fn_dblog_xtp will contain 102 records: a BEGIN TRANSACTION, and a row for each row inserted, and a COMMIT TRANSACTION.
One of the new columns in fn_dblog_xtp is xtp_object_id. I tried to join this to the sys.objects table to return the object name, but the values didn't match. After banging my head against my monitor for a while, I posed the question to #sqlhelp on Twitter. Andreas Wolter (b|t) responded that a correlation can be made using DMV sys.memory_optimized_tables_internal_attributes. Excited, I tried to join fn_dblog_xtp to the DMV, but was disappointed.
On further examiniation, I determined the xtp_object_id from fn_dblog_xtp was a very large positive number while xtp_object_id from the DMV was a very large negative number. I looked closer and found that the first in-memory object created in a database will receives two xtp_object_id values, 2147483648 and -2147483648. Both of these values are increment for additional in-memory objects. So your second in-memory object will receive values of 2147483649 and -2147483647.
So, to bring a very long story to a close, you can join fn_dblog_xtp to the DMV using the following query:
SELECT f.[Current LSN], f.Operation, f.Context, f.[Transaction ID], f.operation_desc, f.tx_end_timestamp, f.total_size, OBJECT_NAME(m.object_id) AS ObjectName, f.newrow_identity, f.newrow_data, f.newrow_datasize, f.oldrow_begin_timestamp, f.oldrow_identity, f.oldrow_key_data, f.oldrow_key_datasize, f.xtp_description, f.[Log Record Fixed Length], f.[Log Record Length], f.[Flag Bits], f.[Log Reserve], f.[Log Record] FROM fn_dblog_xtp(NULL,NULL) AS f INNER JOIN sys.memory_optimized_tables_internal_attributes m ON (f.xtp_object_id - 2147483648) = (m.xtp_object_id + 2147483648) WHERE Operation LIKE '%HK%'
Once again, I hope this saves some folks frustration interrogating the transaction log for in-memory objects.