I’m a bit of a researcher. When I want to know about a topic, I start off by doing a lot of reading. After I take a lot in, I want to make sure I understand the details. At that point, I try to think like a scientist. I come up with ways to test what I’m learning and see it in action. My process isn’t revolutionary, but it goes something like this:
- Formulate a question.
- Pose a hypothesis.
- Form a prediction.
- Run a test.
- Analyze the results.
I can’t do this for everything, but I love it when it works.
Today’s story is about how I used this process to learn about how SQL Server writes to transaction log files.
This won’t be a super-practical post that will change your life. I’m not going to make any recommendations here, other than widely published best practices. But I promise to show you a tool that may help you learn a lot about how SQL Server works.
The Question: How Large are the Writes to a Transaction Log File?
A widely published SQL Server configuration best practice is to format your log file drives with a 64KB allocation unit size. There are exceptions to this for certain storage subsystems— you should always check the documentation from your storage provider, and you can also run tests with tools like SQLIO to determine how you can get the best performance with your storage implementation. (Different SAN configurations and settings like RAID stripe size make a difference when it comes to performance with a given allocation unit configuration.)
My question was: what does the allocation unit size mean in terms of how much SQL Server writes to disk when I issue a write against a transaction log? Do I always have to do the same unit of work as my allocation unit size?
In other words, am I always going to do a minimum of 64KB of IO against my log file? That seems like a lot, so I doubt it! But if not 64KB, then how much?
First, Some Background on Allocation Unit Size

The “Allocation Unit Size” on a drive is also called the “cluster size.” These are pretty much synonymous, and the fact that we have two ways to talk about this can make things confusing.
The default allocation unit size on a windows drive is 4KB. When you format the drive, you can set that to a larger size— again 64KB is recommended for SQL Server data, log, and tempdb files. The allocation unit size is basically the smallest unit of storage that any individual file can take up. If I set the allocation unit size on a drive to 64KB and then create a tiny text file which only takes up 11 bytes, that one file will take up 64KB on disk.
So 64KB isn’t a great allocation unit size for a drive with many tiny text files, but our SQL Server log files are all much larger than 64KB—- each file takes up many allocation units.
Hypothesis: We’re Writing to the Transaction Log in Small Chunks
My initial guess was this: even though I’m setting my allocation unit size to 64KB, the way that SQL Server issues the writes doesn’t write out 64KB each time. That would just be too high!
I did some reading to learn more about this from the SQL Server perspective. In the “Determining I/O Capacity” section in the Best Practices Whitepaper, it states, “Log writes are sequential in nature with a varying size, which is dependent on the nature of the workload (sector aligned up to 60 KB).”
So we’ve got a varying size, and it’s “sector aligned.” Bob Dorr explains more about sectors and transaction log writes in his SQL Server I/O Presentation: “Any time the physical flush takes place it occurs on a sector boundary. The FlushToLSN will attempt to pack as many active log records into sector aligned boundaries and write on the sector size. The sectors each contain a parity bit that the log can use to detect the valid sectors flushed before a crash recovery.”
Now we’re getting somewhere! So, in theory, the smallest write should hit ONE disk sector. A disk sector is a physical sector on a drive— it’s configured by the storage manufacturer, and isn’t something you configure. Most drives contain sectors which are 512 bytes, but now new-fangled drives (called “Advanced Format” drives) contain 4KB sectors.
To recap our terminology and put things together: if you format a single (“old school”) drive with a 64KB allocation unit size, each 64KB cluster will have 128 physical sectors. Each sector will have 512 bytes.
Based on this, my prediction is that SQL Server will write 512 bytes to the log file for a single tiny write transaction. Ideally, I want to observe this IO outside of SQL Server, not inside of it. It might be the case that SQL Server thought it was doing a small IO, when Windows saw it doing more IO.
My Test: Watching Writes with Process Monitor
It didn’t take long to find a tool to monitor IO with. I am a big fan of the SysInternals Suite suite of tools. Over the years SysInternals tools have helped me solve many problems and learn a lot.
Process Monitor does just what the name says: it helps you monitor the behavior of processes. As it monitors it streams a lot of information to the client, and I always get a bit nervous if I have to run it in production due to the volume. (Make sure you apply very good filters!)
However, for a lab environment it’s just candy: easy to use, quite intuitive, and highly configurable. I fired up process monitor and filtered out all processes except for sqlservr.exe. (Protip: all the cool kids drop vowels near the end of words. Just call me “Kendr.”)

This first filter helps reduce the abundant flow of information coming from Process Monitor. It helped me focus in on my quarry.
I was just interested in seeing IO to a log file. Next, I filtered out everything except for writes to the log file for a database named InsertTest, which was located at the path “T:\MSSQL\Data\InsertTest_log.ldf.”

I also validated in a command prompt that my T drive is formatted with a 64KB allocation unit size, and Windows understands my drive to have 512 bytes per sector. Sure enough, 64KB!

Setting Up A Database to Test
I wanted to do a very small write and see how much IO was issued, so I created the following table:
Use InsertTest; GO CREATE TABLE lilbittytable (tinycol bit)
That’s pretty darn small, right?
I started collecting data with ProcessMonitor and I ran an insert into my table:
Use InsertTest; GO INSERT lilbittytable (tinycol) SELECT 1
And, what do you know, here’s the write I saw:

You'll have to take my word for it here, but the "Path" column confirms the write was to InsertTest_log.ldf
As soon as I inserted the row, I hadn’t defined an explicit transaction, so it auto-committed. This required that the row be flushed to the log. This write went into my log file with a length of 512— and that length is reported by Process Monitor in bytes.
This verified my theory: tiny transaction log file writes are indeed written in a unit that corresponds to a single phyiscal disk sector, as defined by the drive itself. The answer to my original question is that the size of data written is NOT influenced by the allocation unit size you set when you format a drive.
Wrapping Up
There are lots of questions that the information I showed today may raise for you. What happens when you write larger records, or have multiple sessions doing writes at the same time? Does this all correspond to what you see inside the SQL Server transaction log when you read it with the (undocumented) fn_dblog function? What sizes of writes do you see happening against the data files after a checkpoint?
Good news: it’s really easy for you to find out! Firing up Process Monitor on a test environment is super easy, and will take you less time than reading this post did. Give it a shot, and happy exploring.
Argenis Fernandez June 1, 2012 | 7:31 pm
If you know me, you know I love this stuff!!!
Good post, Kendra!
AJ June 2, 2012 | 3:46 pm
This information post helped me understand the fundamentals on disk usage for tran log writes and also introduced me to Process Monitor. Thank you very much Kendr!
I could be wrong…but I wanted to check with you on a possible typo:
To recap our terminology and put things together: if you format a single (“old school”) drive with a 64KB allocation unit size, each 64KB cluster will have 128 physical sectors. Each sector will have 512KB.
Is it 512KB or should it be 512 Bytes?
AJ June 2, 2012 | 5:23 pm
…and of course I meant to say “This informative post…”
Kendra Little June 3, 2012 | 1:04 pm
That should be 512 bytes– thanks for the note!
Alain Krikilion June 4, 2012 | 3:48 am
64KB clustersize for TL for performance.
But if SQL can write only 512 bytes at a time in a transactionlog and the clustersize is 64KB, wouldn’t it be faster having a smaller cluster-size for an ERP-DB where most transactions contain only 1 or few records?
Kendra Little June 4, 2012 | 7:51 am
Hi Alain,
512 bytes is the *smallest* transaction log write size– but not the only size.
Here’s the quote from the Best Practices Whitepaper: “Log writes are sequential in nature with a varying size, which is dependent on the nature of the workload (sector aligned up to 60 KB).” (Link: http://technet.microsoft.com/en-us/library/cc966412.aspx)
You can see the larger writes with the same method I used. I just wanted to confirm the smallest possible write size using external tools in this test.
Mike June 11, 2012 | 11:28 am
Your SQL Server IDE is black – which program do you use to get color schemes?
Thanks
Kendra Little June 11, 2012 | 11:30 am
Hey Mike,
The highlighting in the post is from the “syntax highlighter evolved” wordpress plugin. I put the code in that way so that people can copy/paste it easily — wish I could use sceenshots and still get that, but no such luck.
Meher September 27, 2012 | 7:46 am
That is Kendra. You write in so simple language and make it easy for us to understand.
Great post and Thank you very much.
Matt October 8, 2012 | 8:39 pm
That is very odd. I can see why writing as small of a chunk as possible would be helpful in that it gets the transaction committed as quickly as possible.
But, I obviously have some learning to do, this shouldn’t be possible in that SQL Server could want to do a 512B write but should only be aware of the smallest units presented to it… which is the allocation unit as defined when creating the NTFS volume. The volume is an abstraction layer. SQL Server can look up the BytesPerSector but it can’t address them.
A) How is a 512B write passed through a 4k allocation unit NTFS layer (assuming the NTFS volume was created at 4k)? With the fun follow up question of what is the point of the allocation unit if applications write based upon the disk sector size?
B) How can I change this behavior to only write at the size of the NTFS volume or, if not that, in the size that I want. Assume I have a good reason. Sybase has a “sp_logiosize” and Oracle has a configuration for its redo write block size. Anything for us SQL Server folk?
I realize that you are the messenger, not the code writer.. but still, thought I’d ask.
I now wonder the point of Microsoft recommending a 64k allocation unit size for log volumes.
Very informative, thanks.
Matt
Kendra Little October 9, 2012 | 6:44 pm
Hi Matt,
I was writing very very tiny records in all the testing I did here– if you use transactions that write more data, you get larger write sizes. I was just trying to see what the smallest I could get are. If you check the paper I link to by Bob Dorr, you’ll see that the max size of the writes for the tlog is 60KB (not quite 64KB– just shy of it). I didn’t publish all the steps in my article but I can indeed see the larger writes.
The allocation unit size has to do both with efficiency in managing files for windows more than anything else. You generally want to use the largest allocation unit size possible that works with your application and your storage subsystem– and this is typically 64KB– but as I mention I always like to test new storage with a tool like SQL IO, as some fancy storage subsystems can show different results.
So I hope this explains more about why there’s the general recommendation and how you can test it here.
Hope this helps!
Kendra
Matt October 9, 2012 | 9:06 pm
Kenra,
Thanks for the follow up. I was mostly hoping to find some sort of tunable that would allow me to force the transaction logs to write at a 4k minimum vs 512, even if the disk sector is set to 512. It sounds like SQL Server doesn’t have a traceflag or configurable to change this behavior. Thanks!
Matt
Pingback: Technical: Microsoft – SQL Server – Datafiles – Log File Write Patterns | Daniel Adeniji's – Learning in the Open