Author: way0utwest

  • Test Your Restores

    The ultimate testers.

    I was talking with someone the other night about their database systems and they mentioned they had implemented TDE (Transparent Data Encryption) to comply with HIPAA regulations. This person had verified that they were backing up the Database Encryption Key, which you definitely need if you want to restore a backup from a TDE encrypted database. However they weren’t sure if the certificate that protected the DEK, and the master keys on that instance were being backed up. Probably most scary to me, they hadn’t tested any restores of the database.

    Encryption is serious business, and if you are going to implement it in your databases, you had better be sure you understand how the various keys and certificates work. You better be sure you have protected your passwords, and that you can find them in the event of some issue.

    Most importantly, though, is that you need to practice recovering your database to another instance. Preferably you’d learn how to recover on an instance that hasn’t ever enabled encryption as well as one that has a different SMK or DMK.

    Practicing restores isn’t just about encryption and the potential for data loss because you don’t have a key. Practicing restores is important for all of your systems to be sure you have the skills to successfully complete a restore. It helps ensure you know where the files, tapes, disks, or any other resources are located. Most importantly it ensures that your backup process is actually running smoothly.

    Please don’t assume your backup process works. Whether you’re an accidental DBA stuck with their first SQL Server, or a ten year senior DBA that has performed hundreds of restores at previous jobs. You need to test your process and ensure that you can perform restores on the systems you are managing.

    Steve Jones


    The Voice of the DBA Podcasts

    We publish three versions of the podcast each day for you to enjoy.

  • T-SQL Tuesday #37 – A Month of Joins

    tsqltuesdayIt’s time once again for T-SQL Tuesday, and this month is hosted by SQLity.net, Sebastian Meine.

    If you want to know more or participate, read the invitation and write your own blog post.

    The topic this month is joins, in honor of Sebastian’s a-join-a-day series. He’s writing about various aspects of joins, and invites us all to do the same thing on this Tuesday.

    Writing Better Joins

    I’m not a T-SQL expert. I can write code, and understand many type of queries, but I’m not one to dazzle others with their code, like Jeff Moden can. Instead, I want to talk about how I’ve learned to ensure that my code makes sense, is understandable, and most importantly, easy to find the mistakes inside.

    I mainly do this by paying attention to the formatting of the code. I would say that once I started to get away from writing code like this, I found bugs easier, and understood the code better:

    WITH [EMP_cte]([BusinessEntityID], [OrganizationNode], [FirstName], [LastName], [RecursionLevel]) -- CTE name and columns
    AS (
    SELECT e.[BusinessEntityID], e.[OrganizationNode], p.[FirstName], p.[LastName], 0 -- Get the initial list of Employees for Manager n
    FROM [HumanResources].[Employee] e INNER JOIN [Person].[Person] p ON p.[BusinessEntityID] = e.[BusinessEntityID]
    WHERE e.[BusinessEntityID] = @BusinessEntityID
    UNION ALL SELECT e.[BusinessEntityID], e.[OrganizationNode], p.[FirstName], p.[LastName], [RecursionLevel] + 1 -- Join recursive member to anchor
    FROM [HumanResources].[Employee] e INNER JOIN [EMP_cte] ON e.[OrganizationNode].GetAncestor(1) = [EMP_cte].[OrganizationNode]
    INNER JOIN [Person].[Person] p ON p.[BusinessEntityID] = e.[BusinessEntityID]
    )
    SELECT [EMP_cte].[RecursionLevel], [EMP_cte].[OrganizationNode].ToString() as [OrganizationNode], p.[FirstName] AS 'ManagerFirstName', p.[LastName] AS 'ManagerLastName',
    [EMP_cte].[BusinessEntityID], [EMP_cte].[FirstName], [EMP_cte].[LastName] -- Outer select from the CTE
    FROM [EMP_cte] INNER JOIN [HumanResources].[Employee] e ON [EMP_cte].[OrganizationNode].GetAncestor(1) = e.[OrganizationNode]
    INNER JOIN [Person].[Person] p ON p.[BusinessEntityID] = e.[BusinessEntityID]
    ORDER BY [RecursionLevel], [EMP_cte].[OrganizationNode].ToString()
    OPTION (MAXRECURSION 25) 

    I often find code in forums, or sent to me and I need to reformat it so that it looks better. I prefer something like this:

    WITH    [EMP_cte] ( [BusinessEntityID], [OrganizationNode], [FirstName], [LastName], [RecursionLevel] )
              -- CTE name and columns
              AS (
                   SELECT
                    e.[BusinessEntityID]
                   ,e.[OrganizationNode]
                   ,p.[FirstName]
                   ,p.[LastName]
                   ,0 -- Get the initial list of Employees for Manager n
                   FROM
                    [HumanResources].[Employee] e
                    INNER JOIN [Person].[Person] p
                        ON p.[BusinessEntityID] = e.[BusinessEntityID]
                   WHERE
                    e.[BusinessEntityID] = @BusinessEntityID
                   UNION ALL
                   SELECT
                    e.[BusinessEntityID]
                   ,e.[OrganizationNode]
                   ,p.[FirstName]
                   ,p.[LastName]
                   ,[RecursionLevel] + 1 -- Join recursive member to anchor
                   FROM
                    [HumanResources].[Employee] e
                    INNER JOIN [EMP_cte]
                        ON e.[OrganizationNode].GetAncestor(1) = [EMP_cte].[OrganizationNode]
                    INNER JOIN [Person].[Person] p
                        ON p.[BusinessEntityID] = e.[BusinessEntityID]
                 )
        SELECT
            [EMP_cte].[RecursionLevel]
        ,   [EMP_cte].[OrganizationNode].ToString() AS [OrganizationNode]
        ,   p.[FirstName] AS 'ManagerFirstName'
        ,   p.[LastName] AS 'ManagerLastName'
        ,   [EMP_cte].[BusinessEntityID]
        ,   [EMP_cte].[FirstName]
        ,   [EMP_cte].[LastName] -- Outer select from the CTE
        FROM
            [EMP_cte]
            INNER JOIN [HumanResources].[Employee] e
                ON [EMP_cte].[OrganizationNode].GetAncestor(1) = e.[OrganizationNode]
            INNER JOIN [Person].[Person] p
                ON p.[BusinessEntityID] = e.[BusinessEntityID]
        ORDER BY
            [RecursionLevel]
        ,   [EMP_cte].[OrganizationNode].ToString()
    OPTION
            ( MAXRECURSION 25 ) 

    That actually came from reformatting the code using SQL Prompt, a product from my employer, Red Gate Software. I’m lucky in that SQL Prompt formats things as I’d prefer them, indenting and getting the JOIN and ON clauses onto separate lines.

    Having code with structure, where you can clearly see the tables being joined, the clauses in use, and not miss any of the columns being selected at a glance is important. When you’re under stress and trying to debug or develop something, it’s easy to miss something that’s happening in the code if it’s not formatted correctly.

    Whether you like commas before or after columns, or you want things indented so that the names of objects line up doesn’t really matter. What’s important is that you and your team agree on a set of formatting, or have tools that reformat things for each developer in a consistent way. You’ll spend less time trying to understand the code and more time building or fixing it, if it has a consistent layout.

  • Grace Under Pressure

    I once worked at a large, 10,000+ person company. We had a large data center with hundreds of machines, where one day we lost power. Not power from the electric utility; no UPSs or generator kicking. We had a maintenance worker accidentally flip a switch and cause all of our UPSs to trip offline, cutting power to all the servers.

    I was in the data center, surprised by the sudden quiet. Unfortunately, one of our senior executives was also in the data center and proceeded into the raised floor area. As various technicians and sysadmins attempted to restore power and reboot systems, this senior executive watched, commenting, questioning, and often berating the employees. Not a good situation for anyone, least of all the people trying to reconnect high-voltage wires together.

    Most of you will never experience a large disaster and need to recover your systems. Even fewer of you will recover from disasters with anyone other than your peers or a direct manager watching you. However, you shouldn’t count on being that lucky. Whether the disaster is small or large, your fault or a natural occurrence, I hope that you are able to successfully restore your systems with some professionalism and grace under pressure.

    The key to a strong performance in a stressful situation is the same in technology as it is in sports, music, and almost any other endeavor with an audience. The key is practice.

    Simulate disasters; pretend that a refresh of a development system is really a restore after a fire. Think about the various possible scenarios that might require you to recover a system and incorporate practice time into your daily routine.

  • Planning

    I made it to the UK on a very smooth, uneventful, on-time trip. That’s just what I like when traveling. After arriving at Heathrow and traveling to Cambridge, I arrived at the Red Gate office just in time for lunch. A fortuitous event as I was hungry after flying all night.

    Most of my afternoon was meeting with various product groups talking about planned enhancements and changes and how these items might benefit DBAs in the field. Grant and I are usually called on for sanity checks on thoughts, ideas, and plans.

    It’s interesting to discuss with product groups how and why they want to make changes. I can’t talk about specifics, but hearing from developers and project managers is always interesting to me. We see the world differently and it’s good to give feedback on products that can make a DBA’s job easier. I haven’t always had the chance to do that, but when I do, it’s a growing experience to hear how a vendor sees the world.

    I wrote about this recently, and a few disagreed, thinking that Microsoft doesn’t listen to them. I disagreed then, and I still do. I get an opinion at Red Gate, and with Microsoft. I don’t get to make a decision, or even much of a vote, but I do get to voice my opinion. Just because it isn’t followed doesn’t mean that someone didn’t listen.

    I don’t know to what extent my thoughts will influence the products, but I did see and discuss things with a variety of people in different departments, and the discussions evolved, so I know my opinion is heard. Whether it changes things remains to be seen.