A Good Thing
Since you’re here reading this, I’m going to assume you know what food is. Further, I’m going to assume that you also know what salt is, because salt plays a pretty big part in how good or bad food tastes.
- Skimp on salt, and you’ll see a lot of disappointed faces
- Go overboard on salt, and you’ll see a lot of sour faces
This is a lot like what you’ll see if you do either one of those things with indexes in your database, unless you have Special Medical Exemptions©.
- If it’s a data warehouse, you’ll probably want fewer indexes, but you’ll also probably want to use column store indexes
- If it’s normal throughput OLTP, you’ll probably want more indexes than a data warehouse, but with narrower key column choices to support seek and lookup plans
- If it’s OLTP + Reporting (or analytics or whatever you wanna call it) you’re going to need to make a lot of tough indexing choices for them to live together
- If it’s high throughput OLTP, you’ll probably want even fewer overall indexes, and you may need to look into in-memory options for the busiest tables
With all that in mind, there might be some local factors that make some if this stuff not align particularly well with your workload. Things like version, edition, query patterns, and hardware might be holding you back. And of course, being at the mercy of a terrible vendor application would also likely put a damper on many of these plans.
If you want a quick and easy way to find indexes to both remove and add, go ahead and grab sp_BlitzIndex.
In my consulting work, the most common type of workload I see is OLTP with reporting on top of it, followed by analytics workloads. Pure OLTP workloads are pretty rare.
The index strategy for these workloads might look something like this:
- Narrow key indexes with very few includes or OLTP queries
- Fairly narrow key indexes with wider includes for reporting queries, or…
- Nonclustered column store indexes for reporting queries
It’s always tricky figuring out what the best set of indexes to have around for your workload is. There are so many missing index requests, new queries, users complaining, and new tables getting added that it’s hard not to feel like you’re drowning.
You can’t have the perfect index for every query, and you shouldn’t try to. You’d end up with the sour-salt face kind of database. But what I need you to do is make a deal with yourself: Any time you want to add an index, you have to look for an index to get rid of.
Because without fail, I see these patterns all the time:
- Indexes with a single key column along wider indexes that lead with the same column
- Indexes with the exact same key columns and key column order (sometimes one has more key columns at the end)
- Indexes that are totally unused by read queries but get modified a lot
- Indexes with only a few reads and a ton of writes
It’s all very bothersome clutter, and you’ve got to clear these out before you can add in more.
There are many good reasons to avoid over-indexing. Everyone says “writes get slow”, but that’s a shabby meme. Your writes are slow because your storage is crappy and possibly because of your poorly thought out Availability Group.
Why having an excessive number of indexes (again, barring Special Medical Exemptions©) can be bad for your database performance:
- More objects to lock means more locking generally
- More objects to lock means a greater chance of lock escalation attempts
- Buffer pool:
- More indexes means more objects in the buffer pool
- Even indexes unused by reads need to be modified when the table changes
- Transaction logging:
- More indexes to modify means more to keep track of in the transaction log
- Even databases in simple recovery log the same amount 99% of the time
So the next time you want to go add an index to a table, I want you to try a few things:
- Look for indexes on the table that are totally unused
- Look for indexes on the table with overlapping key columns to merge
- Look for indexes that could be tweaked rather than creating a whole new one
To do that, sp_BlitzIndex run like so:
EXEC dbo.sp_BlitzIndex @DatabaseName = N'YourDatabase', @SchemaName = N'ProbablyDBO', @TableName = N'YourIndexingCatastrophe';
Thanks for reading!
If this is the kind of SQL Server stuff you love learning about, you’ll love my training. I’m offering a 75% discount to my blog readers if you click from here. I’m also available for consulting if you just don’t have time for that and need to solve performance problems quickly.