Reasons Why You May Not Want to Use a Heap

I have started compiling a list of reasons why heaps aren’t usually a good choice when designing a database. Now, I didn’t say that heaps are always bad, but in most cases, I think they should be avoided (read the list to see why).

As I compiled the list, in some cases I have had the opportunity to verify that they are true, but in other cases, I have not had the time to verify them. I would like your input on the list. Is there anything on the list that is not true, or only partially true (under some circumstances, but not others), and what other reason are there to avoid using heaps that have I left out?

I look forward to your feedback.

  1. If non-clustered indexes are not added to a heap, then all queries against a heap will require table scans to retrieve the requested data. If the heap is large, then these queries will be very resource intensive and hurt SQL Server’s overall performance.
  2. Since the data in a heap is unordered, performing a table scan on a heap can cause a lot of extra I/O activity because inefficient random reads, not efficient sequential reads, are more the norm.
  3. While a non-clustered index can be added to a heap to speed up some queries, when the non-clustered index is non-covering, the use of a RID bookmark lookup is required. A RID lookup means that once the record(s) to be returned by the query are identified in the non-clustered index, additional reads (the RID bookmark lookup) must be made of the related rows in the heap, so that all of the data requested by the query is returned. This is not very I/O efficient, especially if many rows are returned. At some point, it may be faster for SQL Server to do a table scan than it is to use a non-clustered index when returning many rows. On the other hand, if the non-clustered index is covering, then the non-clustered can be used to immediately return the data to the user without having to lookup anything in the heap.
  4. If you want to create an XML index on an XML data column, a clustered index must exist on the table.
  5. If you want to create a spatial index on a spatial data column (GEOMETRY or GEOGRAPHY), a clustered index must exist on that table.
  6. If a heap has a non-clustered index on it (as the primary key), and data is inserted into the table, two writes have to occur. One write for inserting the row, and one write for updating the non-clustered index. On the other hand, if a table has a clustered index as the primary key, inserts take only one write, not two writes. This is because a clustered index, and its data, are one in the same. Because of this, it is faster to insert rows into a table with a clustered index as the primary key than it is to insert the same data into a heap that has a non-clustered index as its primary key. This is true whether or not the primary key is monotonically increasing or not.
  7. When data is updated in a heap, and the updated row is larger than the old row and can’t fit into the old space, a forwarding record is inserted into the original location that points to the new location of the page. If this happens a lot, then there is a lot of space wasted in a database maintaining the forwarding records. This also contributes to additional I/O activity as both the pointer, and the row, have to be read.
  8. Even if data updated in a heap is not larger than the old row (the updated data is smaller or the same size than the original data), updating a heap with a non-clustered primary key is slower than updating the same table that has a clustered index as the primary key. This is because updating a table with a clustered index is less write intensive than updating a heap with a non-clustered index as its primary key.
  9. If a row is deleted from a heap with a non-clustered index as its primary key, it is slower than deleting the same row from the same table with a clustered index as its primary key. This is because it takes more I/O to perform this task on a heap than on a clustered index.
  10. When data is deleted from a heap, the data on the page is not compressed (reclaimed). And should all of the rows of a heap page are deleted, often the entire page cannot be reclaimed. This not only wastes space, it contributes to fragmentation of the data pages within a database.
  11. If you take two identical tables, one that is a heap with a non-clustered index as its primary key, and a table that has a clustered index as its primary key, the heap with the non-clustered index will be substantially larger, wasting valuable space and increasing disk I/O.
  12. The ALTER INDEX rebuild and reorganize options cannot be used to defragment and reclaim space in a heap (but they can used to defragment non-clustered indexes on a heap). If you want to defragment a heap in SQL Server 2005, you have three options: 1) create a clustered index on the heap, then drop the clustered index; 2) Use SELECT INTO to copy the old table to a new table; or 3) use BCP or SSIS to move the data from the old table to a new table. In SQL Server 2008, the ALTER TABLE command has been changed so that it now has the ability to a rebuild heap.

Do You Verify Your Database Backups?

In the past, I have written and spoken a lot about SQL Server “best practices”. One that I emphasize over and over again is the need for DBAs to verify, regularly, the integrity of their database backups. However, I sometimes feel my advice is falling on deaf ears. When giving a presentation, I often ask how many DBAs in the audience regularly verify their backups. Invariably, few hands are raised. When I visit a SQL Server shop to review their database maintenance plans, I always ask the same question. Very few even know what I am talking about.

Why is this? Do some DBAs have a false belief that database backups are always perfect? Perhaps these DBAs don’t know the mechanics of to how to verify a backup? Maybe, they just don’t have the time to perform the verification? Most likely, they haven’t even given the issue any thought because they have not – yet – had a restore fail, and had to explain to an irate manager why their data is lost.

Backup verification is a vital part of a well-designed database maintenance plan. Fortunately, I learned this lesson very early in my career. Back in 1982, a time before hard disks were available for desktop computers, I worked for a computer retail store that performed its accounting on a desktop computer, storing the data on floppy disks. Every day, the owner of the company would religiously make backups of the floppy disks and then sit these backups on the floor, next to her desk. Also, every night, she would vacuum her office, keeping it nice and tidy to meet with customers. One day, one of the main floppy disks became corrupted, so she went to her backup floppy disks in order to restore her data. The only problem was that backup floppy disks had all been corrupted by the vacuum cleaner’s strong magnetic field. None of her backups were good. She had to start from scratch, reentering all of the lost data by hand.

It was a very painful lesson and ever since then I have been a fanatic when it comes to making lots of backups, and regularly verifying that I can restore them if needed.

I’d be interested to hear how regularly people here test the integrity of your database backups, how often you’ve encountered environments where test restores were never performed, and what excuses were given for this.

Do You Run Antivirus Software on Your SQL Servers?

I have been to some IT departments where the standard procedure is to install antivirus/antispyware software on all servers, no matter what applications are running on it. In addition, the default settings are left untouched, which means that virtually every byte of data is examined, in real time, before it is read or written to disk. This virus checking is in addition to any regularly scheduled scans of most of the files on the server’s drives.

If you have ever examined the amount of memory, CPU, and disk I/O resources used by antivirus/antispyware software, you will know that it is a performance hog and, on a busy SQL Server, can cause huge performance issues for your users.

So what do you do? Depending on your situation, you have one of three options:

  1. Run the AV software using its default settings, and buy big enough hardware to overcome any resource contention issues.
  2. Remove the AV software entirely, but take other measures to help ensure that viruses can’t affect your server.
  3. Compromise. Some DBAs remove the AV software from their SQL Servers, but remotely scan it from another server on a scheduled basis, and during a time when the server is not too busy. Other DBAs leave the AV software on their SQL Servers, but change the default settings so that the scans exclude .mdf, .ldf, .ndf, .bak, .trn, full-text catalog files, and any folders that include Analysis Services data.

If your SQL Server is running on a web server that is accessible from the Internet, then the first option might be the right choice. If your SQL Server is running on a closed network, then the second option might work fine. If your SQL Server is in a mixed environment, combined with other servers and end-users connected to the same network, then the third option might be best.

So, here’s my question to you. Have you given any serious thought as to the level of antivirus/antispyware protection you need for your SQL Server instances, and to the performance implications of the strategy you have chosen? If you have, tell us what you have done, and why you have made the choices you did.