Everyone know SQL Server loves memory. It will happily gobble up all the RAM you throw at it. On physical boxes, this may not be a big deal, especially if you plan for it and properly configure your max and min memory settings within SQL Server. RAM makes SQL Server run faster and who doesn’t want that?
In a virtual environment, this RAM gluttony can be a detriment. If you are just beginning to experiment with virtualizing SQL Server, odds are, the first servers you virtualize are going to be the lesser used ones. You (or your network / VM people) will likely just do a P2V of the server and you’ll soon find yourself holding the keys to a shiny new VM. Presto-chango, you’ve just virtualized your SQL Server and you are done!
Not so fast. Think about what just happened. The P2V process cloned your physical hardware and made a VM out of it, without giving any thought to if that hardware was correct for the system. Suppose the system you just virtualized was a little used system that was built on a server that was used for a more active programs in the past. Perhaps the heavily used databases had been migrated off of this server over time and now the server is hosting half or one-third of the load it was originally built for. You could end up with a server that is way overpowered its current load.
In the virtual world, this can hurt you. Remember that each VM is sharing it’s resources with other VMs on the same set of host hardware. So if your VM is running with 12 GB of RAM and 8 CPUs, that’s fewer resources available to the other VMs on that host.
I will take a timeout here to point out that VM hosts do provide tools to share RAM and CPU amongst all VMs as the load on each VM changes. For example, “ballooning” is a method where a VM can borrow RAM from another VM on the same host to temporarily satisfy memory needs on another. Of course, all these sharing techniques come with a price – when they occur, performance degrades. I’m lucky at my company because the VM team here is very conservative with our SQL Server VM hosts. They never oversubscribe RAM and are very conscientious about CPU allocation. In short, I never really have to worry about resource contention amongst my SQL VMs.
Be a good corporate citizen. If you don’t need so many resources, give them back. Your network and VMs admins will love you. Everyone is ALWAYS bugging them for more resources. No one ever tells them “Hey, I’ve got too much. You can have some back.” The trick is determining if you do have too many resources.
I’m going to focus on RAM only in this post, because this is a situation I found myself in recently. As part of my normal DBA monitoring processes, I was reviewing the page life expectancy of my SQL Servers using the Typeperf data collection tool I’ve written about previously. I noticed one SQL Server had an absurdly high page life expectancy:
This particular server has 12 GB of RAM. Three million seconds is just over 34 days. That’s a long time for SQL to keep data in memory. Also, note the pattern. The drop offs are when the server was rebooted for patching. When the server comes back up, it basically loads data into memory and never needs to flush it out again.
Now, of course, whether or not this represents a waste of resources depends on your situation. If this was for a heavily used report server, this could be a highly desired performance pattern. But in my case, this chart is for a SQL Server back-end of a phone system. There are no other databases on the system and it is not under a heavy load. Also remember what I said previously about my VM admins – they do not over-allocate RAM on SQL Server VMs. So I’ve clearly got RAM on this VM that could most likely be better utilized elsewhere.
So what do I do to correct this? Luckily, the solution is fairly easy. By changing SQL Server’s maximum memory setting, I can restrict the amount of memory SQL Server can use to a lower value and see how that affects performance. Furthermore, this is a setting that can be changed on the fly, so no downtime is required. In my case, I configured SQL to use a maximum of 7 GB of RAM (which would reserve 1 GB for the OS on an 8 GB system) and am letting it run for a couple weeks. If no performance issues are noted, I will reconfigure this VM to have 8 GB of RAM instead of 12 GB and I will reallocate that 4 GB RAM to another one of my SQL Server VMs on that same host that I know can use more RAM. And if performance issues do crop up, it’s a quick fix to add the RAM back by increasing SQL’s max memory setting again. By contrast, changing the amount of RAM in a VM requires a reboot, so that is why I’m testing first by changing the SQL Server memory settings.