Sometimes you need to perform a check against all servers to verify settings are correct. There are many ways to do this, but in some cases, you just need an idea of how many servers have “fallen through the cracks”. Probably the fastest way to check all servers is to use a multi-server query through a Central Management Server, and using
NOT EXISTS with a subquery will get those wayward servers.
In this scenario, I wanted to verify every nonsystem database was using the Full Recovery Model. I knew there were a few out there that were in Simple, and I needed to provide a list of each of those. The tsql to get this isn’t too hard.
SELECT [DatabaseName] = name ,recovery_model_desc FROM sys.databases WHERE recovery_model_desc = 'SIMPLE' AND database_id > 4
The results include the Server Name since it was a multi-server query. (Told you it was easy)
Great, I have a list of the offending databases. The next thing I did was create a policy that’s evaluated daily to ensure that all the new and existing databases continued being in Full Recovery. It’s a very easy condition to make. Policy-Based Management can be a daunting feature to get into with SQL Server, as there is not much documentation out there, but my link above will explain some of the basics for setting up a policy to get you started.
However, the next issue to tackle was that I needed a list of all the servers that were missing a log backup job. Those needed to be catalogued and subsequently fixed. This is where it got a bit tricky. Using a CMS, I could get all the servers with the job very quickly, but what a pain that would be to filter and sort manually. I thought about it for a few moments, and came up with a great solution, using the
NOT EXISTS clause. I’ve probably only used this clause a handful of times in the past, but this seemed like a perfect application.
SELECT [LogBackupJob] = 'Missing' WHERE NOT EXISTS (SELECT * FROM msdb.dbo.sysjobs WHERE name LIKE 'BackupLog%'
Again, the CMS displays the Server Name in the results, so I just added a static column to the select clause so that when I copied the results into another file, it would still make sense.
One thing to mention about
NOT EXISTS. The select statement inside doesn’t matter. You can do Select *, Select 1, Select 50/0. It doesnt’ matter. In short, the select is not evaluated, the statement is just checking for existing records. There are a few quality articles out there explaining the evaluation process, or lack thereof, but they can be hard to find.
The applications for
NOT EXISTS in retrieving a list of servers missing a feature are limitless, and now that I realized how well it works, I’ll likely be using it a lot more in the future. Security compliance, maintenance, and more can be monitored quickly to find offending instances.