Author: way0utwest

  • SubQuery Performance

    Why would you do this?

    select distinct(hostname),
    (
    select count(*) as criticalCnt
    from @temp where severity_guid='0168A833-1732-411E-8205-C2F6CD91737D'
    and hostname=t.hostname
    group by hostname),
    (
    select count(*) as criticalCnt
    from @temp where severity_guid='CB2F2B90-2DA4-4075-BCAA-DD5D2CEFBFD5'
    and hostname=t.hostname
    group by hostname),
    (
    select count(*) as criticalCnt
    from @temp where severity_guid='C4CF8A23-A106-4617-BAB0-94DA3CA74EF1'
    and hostname=t.hostname
    group by hostname)
    from @temp t

    I ran into this on a post where someone had asked about how to basically call a CASE statement. The posted didn’t know how and someone posted this as a way to tally the various counts of alerts.

    I had glossed over it when I saw it, but when someone else replied with this statement, saying performance was better, I decided to look at see how much better.

    select hostname,
    sum(case when severity_guid='0168A833-1732-411E-8205-C2F6CD91737D'
    then 1 else 0 end) as [Count_Of_0168A833-1732-411E-8205-C2F6CD91737D]
    ,sum(case when severity_guid='CB2F2B90-2DA4-4075-BCAA-DD5D2CEFBFD5'
    then 1 else 0 end) as [Count_Of_CB2F2B90-2DA4-4075-BCAA-DD5D2CEFBFD5]
    ,sum(case when severity_guid='C4CF8A23-A106-4617-BAB0-94DA3CA74EF1'
    then 1 else 0 end) as [Count_Of_C4CF8A23-A106-4617-BAB0-94DA3CA74EF1]
    from @temp
    group by hostname

    I set the statistics on for these queries and found these results.

    Query 1:

    Table ‘#45544755’. Scan count 52, logical reads 52, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    Query 2:

    Table ‘#473C8FC7’. Scan count 1, logical reads 1, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

    That’s a huge difference. If this were to be run with any significant frequency on a system, you’d be using (4 x the number of rows) as many scans of the data than you needed to. Even though they are logical scans, it’s still CPU and memory movement you are requiring, and if this were a significant amount of data.

    You can also see a drastic difference in the execution plans:

    ScanPlan1

    ScanPlan2

    I’ll let you figure out which plan goes to which query.

    This is a simple example, but it shows where someone really can get poor performance over time with badly written SQL. It’s nice to have various ways to solve problems, but you also want to choose the appropriate tool. Subqueries make sense at times, but this isn’t one of them.

  • Scanning Without Wires – Epson Workforce 610

    We are trying to buy another property here at the ranch. My wife had to leave town in the middle of this, and asked me if I could sign the contract and then scan it in to email to the other party. It was late at night, I was tired and didn’t want to mess with it that night, so I said sure.

    The next morning I hooked up our ancient Epson Perfection 610 to my machine, a process that involves dragging a large piece of hardware out of the closet, plugging it in the wall with the cord running across the floor to the scanner on the floor, and plugging a USB cable into my desktop. I used to do that every month or so for expenses, but apparently I haven’t in a few months. Guess I know why Accounting is a little annoyed with me.

    The scanner didn’t work.

    Windows 7 x64 didn’t recognize it, and when I tried downloading 2 different drivers from Epson that didn’t work I stopped. I had a virus on my machine recently and am nervous about making too many changes without really thinking about it. I plugged the scanner into my Windows 7 x86 machine and it didn’t work their either. So much for extensive Windows 7 support of older hardware.

    Since I had committed to doing this for my wife, and I do need a scanner, I decided to look for one. I had a conference call, but a cell phone and a mute button let me drive to Best Buy and grab a new scanner for $90. I decided on an Epson Workforce 610 because it was wireless, did what I needed, would handle copies and faxing as well, and the 18 year old at Best Buy said he had one and it worked great.

    I brought it home, basically removed all the plastic wrap and tape, loaded ink cartridges, and it was ready. I think I pressed 3 buttons for it to auto detect my wireless network and connect. I ran a CD install of 3 or 4 programs (to handle printing, management, scanning, fax) and then my Win 7, x64 machine detected the printer and sent a test page over. That was cool, but scanning was what I needed.

    I brought up the scanner utility, put the first page of the contract on the bed and hit scan. Across the room, through the magic of wireless, the image appeared saved on my hard drive. I added the rest of the contract in the document feeder, and soon I had 16 jpgs in a new folder.

    That was cool. Scanning has always been a bit of a hassle, like printing, but this was a very cool device.

    And my daughter thinks that the color inkjet is “the bomb” for printing pictures of cats.

  • SQL Saturday Advice – Build a Foundation

    I think this is a good idea, and I’ll give you some reasons, but every SQL Saturday ought to consider having a few sessions an hour before the main event starts.
    When the Rocky Mountain TechTrifecta v2 came to Denver this past February, I was one of 7 or 8 people that was asked to run an early morning session. From 7:30-8:30, before the 9:00am kickoff, we had a number of sessions in various rooms that were essentially discussions. I actually picked up someone else’s session since they couldn’t make it, and had about 10 slides, but it was really me leading a discussion with 6 or 7 people in the room.
    I wondered what was the point, but as I talked with Julie Yack, the organizer, she said that the previous year they’d had lots of people show up early to register and then stood around, not knowing what to do. I’ve seen that in other events, including many SQL Saturday’s as well. It takes time to register 200+ people, even if you are just giving out a name badge, and so the first person to come in has a lot of time to waste.
    There’s also a lot of people that come to SQL Saturday that are very new beginners. They don’t understand a lot about SQL Server, and they’ll get lost during other sessions. Or they are experienced in one area, but not another.
    This is the time for a basic foundation for SQL Server. Honestly I would suggest that every SQL Saturday recruit 4 or 5 speakers, and offer these basic sessions, a very, very junior level session, before the main event.

    1. Introduction to SQL Server
    2. Introduction to Reporting Services
    3. Introduction to Querying in T-SQL
    4. Introduction to Integration Services
    5. Introduction to Analysis Services (if you have speakers in this area)

    Set up a few rooms, start them at 7:30 if you start the event at 9:00 and publicize them for beginners. You will have some very, very happy attendees.

  • Core DBA Skill – Backing up the tail log

    I’ve never had to do this in production, and I’ve only practiced it a few times, but I think this is a core DBA skill. Along with being able to backup and restore your databases, you should be able to recover to a point in time. That can mean a tail log backup.

    I read this in Paul Randal’s blog recently and decided to practice it. So I created my own new database and added a few transactions:

    create database db5
    go
    use db5
    go
    create table MyLog
    ( Txt varchar(max)
    , LogDate datetime default (getdate())
    )
    go
    insert MyLog select 'No backup', GETDATE()
    go
    backup database db5 to disk = 'c:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLServer\MSSQL\Backup\db5_full.bak' with init
    go
    insert MyLog select 'Full backup complete', GETDATE()
    insert MyLog select 'Misc Transaction', GETDATE()
    go
    backup log db5 to disk = 'c:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLServer\MSSQL\Backup\db5_log.trn' with init
    go
    insert MyLog select 'Log Backup Complete', GETDATE()
    go

    I’ve added a couple backups here. If I were to restore this full, I ought to have 1 row in this table. If I add the log restore, I’ll have 3, but I’ll be missing the last line that says “Log Backup Complete”. Now I’ll wreck the database, as per Paul Randal.

    use master
    go
    alter database db5 set offline
    go

    I then rename the mdf file from db5.mdf to db5xxx.mdf, essentially “deleting” it from view by the SQL Server service. When I set this db online

    alter database db5 set online
    go

    I get

    Msg 5120, Level 16, State 101, Line 1
    Unable to open the physical file "C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\db5.mdf". Operating system error 2: "2(The system cannot find the file specified.)".
    Msg 945, Level 14, State 2, Line 1
    Database 'db5' cannot be opened due to inaccessible files or insufficient memory or disk space.  See the SQL Server errorlog for details.
    Msg 5069, Level 16, State 1, Line 1
    ALTER DATABASE statement failed.

    As expected, we have a problem. How do I backup the tail of the log? Remember that file is still visible. We’ll use Paul’s trick to add NO_TRUNCATE to the command:

    backup log db5 to disk = 'c:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLServer\MSSQL\Backup\db5_log_tail.trn' with init, no_truncate

    I get a successful backup, so let’s test. Here’s my restore script, restoring this db as a new database on this instance.

    RESTORE DATABASE [db7]
    FROM
    DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\Backup\db5_full.bak'
    WITH
        MOVE N'db5' TO N'C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\db7.mdf'
    ,  MOVE N'db5_log' TO N'C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\db7_1.LDF'
    ,  STANDBY = N'C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\Backup\ROLLBACK_UNDO_db7.BAK'
    ,  NOUNLOAD,  STATS = 10
    GO
    select * From db7.dbo.mylog
    go
    RESTORE log [db7]
    FROM disk = 'c:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLServer\MSSQL\Backup\db5_log.trn'
    with standby = N'C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\Backup\ROLLBACK_UNDO_db7_log.BAK'
    go
    select * From db7.dbo.mylog
    go
    RESTORE log [db7]
    FROM disk = 'c:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLServer\MSSQL\Backup\db5_log_tail.trn'
    with standby = N'C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\Backup\ROLLBACK_UNDO_db7_log.BAK'
    go
    select * From db7.dbo.mylog

    When I go through this, I get result sets of 1, 3, and 4 rows respectively. I see all my inserts, so despite having a corrupted, destroyed, or renamed (in my case) MDF, I can get all my data back with the log.

    Learn and practice a tail log restore. It’s worth it.

    And don’t forget to set the db active:

    restore database db7 with recovery