801-285-0251       info@sqlsolutionsgroup.com      

Recent Updates RSS Toggle Comment Threads | Keyboard Shortcuts

  • Randy Knight 10:00 am on December 4, 2012 Permalink | Log in to leave a Comment
    Tags: Events, Performance Tuning,   

    Winter 2012 Performance Palooza! 

    This Thursday, December 6, 2012, the SQL PASS Performance Virtual Chapter will be holding online sessions all day long in an the first ever Performance Palooza!.  There are  eight one-hour online sessions, covering a variety of performance related topics.  It is a fantastic speaker line-up, of which I feel privileged to be part of.  All times below are UTC/GMT time.  More details can be found at the Virtual Chapter website.

     

    Time (GMT) Session
    16:00 Title: Recompile or Reuse? Making the Most of Plan CacheSpeaker: Kalen Delaney
    17:00 Title: Troubleshooting SQL Server with SysInternals ToolsSpeaker: Argenis Fernandez
    18:00 Title: Troubleshooting Query Plan Quality IssuesSpeaker: Joe Sack
    19:00 Title: 12 Steps to Workload TuningSpeaker: John Sterrett
    20:00 Title: Effective Index Partitioning & Compression StrategiesSpeaker: Neil Hambly
    21:00 Title: Understanding Transaction Isolation LevelsSpeaker: Randy Knight
    22:00 Title: SQL Server 2012 Column Store IndexSpeaker: Kevin Boles
    23:00 Title:Virtualizing Business Critical SQL ServersSpeaker: David Klee
     
  • Randy Knight 3:43 pm on November 30, 2012 Permalink | Log in to leave a Comment
    Tags:   

    Another First. Speaking at the PASS Summit 2012 

    I have spoken at a lot of SQL Server Events over the past few years including a bunch of SQL Saturdays, User Groups, PASS Virtual Chapters, and PASS SQL Rally.  But my abstracts for The PASS Summit were never accepted.  Until this year.  So a few weeks ago, I had my chance to speak for the first time at the premiere SQL Server Conference.  To say I was a bit nervous is an understatement.  Especially because when I gave the session at our local SQL Saturday the month before, one of my demos blew up.  To make matters worse, I took the Microsoft Certified Master (MCM) lab exam the Monday before the conference.  So it was a nerve-wracking week to say the least.

    So I prepared and rehearsed like crazy and went for it.  At the time I felt like the session went very well.  The audience seemed engaged and all my demos went off without a hitch.  I also had practiced with and used ZoomIt during all the demos and tried to remember to repeat all the questions.

    All Summit sessions are recorded.  Some were on PASS TV this year but mine was not one of those.  But they do record the audio and presentation from all sessions and make them available for streaming, download, or on a USB stick after the conference.  This is a great way to catch all the sessions you couldn’t make it to so I always buy them and watch them over the course of the year.  This also meant this was the first time I could actually watch my own presentation end to end and see how I did.  I was pleasantly surprised. It is true that we are often our own harshest critic … it was good to hear myself.  I picked up on a few things I can work on as well.

    Today the Session Evals came out.  I was pretty pleased with my results.  Some very nice comments from the attendees and if one “ranks” the sessions by eval scores I came in at #20.  Not bad for a first timer.

    Hopefully I can do this again next year.  It was a great experience.

     
  • Randy Knight 5:36 pm on October 28, 2012 Permalink | Log in to leave a Comment
    Tags: ,   

    Using Linked Servers the Right Way 

    Linked Servers are a very popular way to access distributed data in environments with lots of SQL Server instances on different serves, or even on other Database Management Systems like Oracle or MySQL.

    While linked servers can be very useful if used correctly, I have found that more often than not, they are not used correctly and are a source of lots of performance problems.  In this article we’ll take a look at the right (and wrong) ways to configure and use linked servers.

     

    Linked Server Review

    To start with, lets look at how a linked server works.  We configure a linked server in by specifying the remote data source and a name for the sever.

    image

     

    This allows us to use the linked server name ADVENTUREWORKS to access the AdventureWorks database on the instance RKLAPTOP\SS.  Note that the Linked Server name can be whatever we want it to.  It does not have to be the name of the instance. I prefer this practice because you can use the same linked server name in multiple environments (Development, QA, Production, etc.)

    Authentication settings have to be configured as well.

    image

    In this case, I am saying to just pass through the login’s security context to the remote server.  I could also choose to always use a certain security context or to map local login’s to remote logins.

     

    Four Part Naming

    Now that we have a linked server set up, we can access it from the local SQL Server instance.  The most common way to do this is to use four part names to refer to objects on the remote server.

    <LinkedServerName>.<DatabaseName>.<Schema>.<Object>

     

    SELECT *
    FROM ADVENTUREWORKS.AdventureWorks.HumanResources.Employee
    WHERE Gender = 'M'

     

    While this is the most popular way to use Linked Servers, it is also the worst way in terms of performance.  To understand this, you need to always ask the following question: “Where will the query be optimized?”

    In this case, the optimizer on the local server will determine the execution plan.  But it doesn’t know anything about indexes and statistics that exist on the Employee table on the remote server.  There may well be an index on Gender which could be taken advantage of, but the local optimizer has no way to know that.   So this query will result in a table scan, every time, regardless of remote indexes. In addition, all of the data will be sent across the network only to be filtered for Gender on the local system.

    OPENQUERY()

    A better way to do this is to use a function like OPENQUERY().  Essentially what we are doing is executing a remote query on the linked server and just asking for the results back.

    SELECT *
    FROM OPENQUERY
       (
        ADVENTUREWORKS,
        'SELECT * FROM AdventureWorks.HumanResources.Employee WHERE Gender = ''M'''
       )

    The function takes two parameters.  The remote server to execute the query on, and the query itself.  Note that this is remotely executing so if the server was to another DBMS, you’d want the query written in that engine’s flavor of SQL.

    This is a simple example, but imagine if the remote table had a million plus rows.  The inefficient table scan plus bringing all that over the network so that it can be filtered locally.  I have “fixed” queries that were taking 12+ hours to run and reduced the time to just minutes by making this simple change to the code.

     

     

     

     

     

     
  • Randy Knight 1:11 pm on October 20, 2012 Permalink | Log in to leave a Comment
    Tags:   

    The Demo Dementors Strike Again 

    Whenever a demo fails, it always seems to be something really stupid.  This time was no exception.  In my first session today here at SQL Saturday #153 in Salt Lake City, my last demo inexplicably didn’t work.  I had tested it this morning right before the session. So I promised the attendees I would post what it was once I figured it out.

    It ended up being really simple.  Database context.  Connection 1 was in master instead of Adventure Works.  Connection 2 was in AdventureWorks.  Apparently at some time I had also created the demo table in master so it wasn’t’ obvious.

    So to the attendees of my session on Transaction Isolation Levels, I promise if you run the scripts that I upload to the the SQL Saturday site, they will work!

     
  • Randy Knight 9:31 am on October 18, 2012 Permalink | Log in to leave a Comment
    Tags: ,   

    SQL Saturday #153 in Salt Lake City 

    Really looking forward to the event this Saturday (October 20, 2012) at Neumont University in South Jordan.  SQL Solutions Group has been a sponsor of the event for 5th event we have sponsored and and it has always been a great experience.  We’ll be there with a booth so stop by and say hello.

    In addition to sponsoring, we are well represented on the speaking schedule.  The following sessions are being presented by SQL Solutions Group Consultants.

    Time Speaker Topic
    10:15 AM Ben Miller SMO Internals for High Performance Powershell
    11:30 AM Randy Knight Understanding Transaction Isolation Levels
    2:45 PM TJay Belt Release Management: A Necessary Evil
    4:00 PM Ben Miller SQL Server TDE
    4:00 PM Randy Knight But it worked great in Dev! Performance for Developers

    Hope to see you there!

     
  • Randy Knight 11:05 am on October 10, 2012 Permalink | Log in to leave a Comment
    Tags: ,   

    Dynamic SSIS Error Logging 

    When building ETL processes, one of the things we always like to do is to account for every row.  But setting up error data flows can be very time consuming since they are schema dependent.  The following solutions is a generic way to log bad rows that can be re-used without modification. It is also set-based so we are only writing one error row no matter how many errors we had.

    The basis of the solution is that we store the data as XML.  This way we maintain the structure and schema and can shred it as needed later on but we don’t have to have schema-specific tables.

     

    To start with, we need a table to store the results.

    CREATE TABLE [dbo].[ErrorRows_XML](
        [ErrorID] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
        [ErrorDate] [datetime] NOT NULL,
        [ErrorSource] [varchar](500) NULL,
        [ErrorCount] [int] NULL,
        [RowData] [xml] NULL,
    )
    GO

     

    The next thing we need to do is create an SSIS variable to store the results.  We are going to use a Recordset destination so we need a variable of type Object to store the Recordset in.

    For the variable name, I use the following naming convention:

    Error_<PackageName>_<CFStepName>_<DFStepName>

    As you can see from the screenshot below, the DataType is Object and the Value is set for you as System.Object.

    image

     

    In this example, I am using the No Match output of a Lookup transform.  If we can’t find the key, we don’t want the row to go to the fact table via the Match output, but we don’t want to lose the data either so we can troubleshoot the key issue.

    image

     

    The destination is a Recordset Destination, which uses the Advanced Editor.  On Component Properties, the only thing we need to specify is the VariableName, which we created in the previous step.

    image

     

    On the Input Columns tab, we specify which columns from the data flow we want to store as XML.  I generally limit this as much as possible to just the data I need to figure out why this particular operation didn’t work.  In this case that would be the primary key of the input for the data flow and the columns used in the lookup.

    image

     

    At this point, when the Data Flow runs, the rows to be logged will be stored in the Recordset variables.  The last step (typically at the end of the control flow) is a Script Task to write the data to the ErrorLog table created above.

     

    The variable we stored the data in needs to be specified in the Script Task (ReadOnly is fine).

    image

     

    The script uses this function to do the work.

     public void WriteError(string variable)
            {
                //serialize to xml
                OleDbDataAdapter da = new OleDbDataAdapter();
                DataTable dt = new DataTable();
                DataSet ds = new DataSet();
    
                da.Fill(dt, Dts.Variables[variable].Value);
                ds.Tables.Add(dt);
                string xml = ds.GetXml();
    
                if (xml != "<NewDataSet />")
                {
                    //write to db
                    string ErrSource = Dts.Variables[variable].Name;
                    SqlConnection cn = new SqlConnection();
                    cn = (SqlConnection)(Dts.Connections["DW01_ADO"].AcquireConnection(Dts.Transaction) as SqlConnection);
                    SqlCommand cmd = new SqlCommand("insert dbo.EFC_ErrorRows_XML(ErrorSource,RowData) values(@ErrorSource, @XML)", cn);
                    cmd.Parameters.Add("@ErrorSource", SqlDbType.VarChar).Value = ErrSource;
                    cmd.Parameters.Add("@XML", SqlDbType.Xml).Value = xml;
                    cmd.ExecuteNonQuery();
                }
            }

     

    The body of the script just calls the function for each variable that contains errors.

     public void Main()
            {
                WriteError("Error_FactEFCTaps_StageTaps_TripKey");
                WriteError("Error_FactEFCTaps_StageTaps_ActionKey");
                WriteError("Error_FactEFCTaps_StageTaps_ServiceKey");
                WriteError("Error_FactEFCTaps_StageTaps_ZoneKey");
                WriteError("Error_FactEFCTaps_StageTaps_YardKey");
                WriteError("Error_FactEFCTaps_StageTaps_MTTapDateKey");
                WriteError("Error_FactEFCTaps_StageTaps_MTTapTimeKey");
                WriteError("Error_FactEFCTaps_StageTaps_StopKeyEndDateNull1");
                WriteError("Error_FactEFCTaps_StageTaps_NoPlatformKey2");
                WriteError("Error_FactEFCTaps_StageTaps_RouteID0");
                WriteError("Error_FactEFCTaps_StageTaps_PlatformKey1");
                WriteError("Error_FactEFCTaps_StageTaps_NoPlatformKey3");
                WriteError("Error_FactEFCTaps_StageTaps_NoPlatformKey1");
                WriteError("Error_FactEFCTaps_StageTaps_AllStopKey");
                WriteError("Error_FactEFCTaps_StageTaps_NoPlatformKey");
                WriteError("Error_FactEFCTaps_StageTaps_InstitutionKey");
                WriteError("Error_FactEFCTaps_StageTaps_ProductKey");
                WriteError("Error_FactEFCTaps_StageTaps_CardKey");
                WriteError("Error_FactEFCTaps_StageTaps_VehicleKeyTraxFR");
    
                Dts.TaskResult = (int)ScriptResults.Success;
            }

     

    We now have the data in the Error Log table as XML

    image

     

    XQuery can be used to shred the XML to get at specific data.  For common errors, I create views for the specific error type.

    SELECT 
        x.ErrorID
        ,x.ErrorDate
        ,tbl.col.value(N'(id_sess)[1]',N'bigint') AS id_sess
        ,tbl.col.value(N'(cardid)[1]',N'nvarchar(255)') AS CardID
        ,tbl.col.value(N'(CC_CompanyName)[1]',N'nvarchar(255)') AS CC_CompanyName
        ,tbl.col.value(N'(CDListMembership)[1]',N'nvarchar(255)') AS CDListMembership
        ,tbl.col.value(N'(FaceNumber)[1]',N'nvarchar(255)') AS FaceNumber
        ,tbl.col.value(N'(id_payee)[1]',N'bigint') AS id_payee
        ,tbl.col.value(N'(LastCDListChangeDate)[1]',N'datetime') AS LastCDListChangeDate
        ,tbl.col.value(N'(ProductKey)[1]',N'int') AS ProductKey
        ,tbl.col.value(N'(ShortName)[1]',N'nvarchar(255)') AS ShortName
        ,tbl.col.value(N'(SubscriptionEndDate)[1]',N'datetime') AS SubscriptionEndDate
        ,tbl.col.value(N'(SubscriptionStartDate)[1]',N'datetime') AS SubscriptionStartDate
        ,tbl.col.value(N'(InstitutionKey)[1]',N'int') AS InstitutionKey
    from dbo.EFC_ErrorRows_XML x
    cross apply RowData.nodes(N'//Table1') as tbl(col)
    WHERE ErrorSource = 'Error_FactEFCTaps_StageTaps_CardKey'

     

     

     

     

     
  • Randy Knight 10:00 am on March 19, 2012 Permalink | Log in to leave a Comment
    Tags: California, , ,   

    SQL Saturday #120 – Orange County, CA 

    Looking forward to heading to Southern California this weekend for SQL Saturday #120 in Huntington Beach.  They always put on a great event and you can’t beat the location.  Not to mention that it is very close to where I grew up so I get to see some old friends while I’m there.

    I will be doing two sessions at this event:

    Of course there are many other fantastic sessions as well as a pre-conference session all day on Friday.

    Hope to see you there!

     
  • Randy Knight 8:19 pm on March 12, 2012 Permalink | Log in to leave a Comment
    Tags: ,   

    Utah Code Camp Spring 2012 

    This last Saturday was the most recent iteration of Utah Code Camp  and I have to say it was a resounding success.  In addition to speaking, I was invited to participate in an “Ask a DBA” panel discussion and also had the opportunity to have SQL Solutions Group sponsor the event.  So it was a busy day.

    My first session was the last one before lunch and is one of my favorites to give.  But it worked in Dev!  SQL Server Performance for Developers is always a lively session with good discussion.  Given that this was a code camp, the audience was almost all developers so it worked out great.  Based on the discussions both during and after the session, I am confident more than a few developers will be looking at their SQL more closely than they did before.  There was one participant who was actually pretty shaken up when learning what “NOLOCK” really does and does not do.  I think I may have ruined his weekend but as they say, forewarned is forearmed.

    Thanks to Platinum Sponsor Domo, we had a great lunch catered by Famous Dave’s.  Then it was on to afternoon sessions.  I finished the day participating in a panel discussion of DBA’s called “Ask a DBA”.  This was an informal session with DBA’s representing SQL Server, Oracle, and mySQL.  Most of the attendees were SQL Server users so that is where the discussion seemed to focus but it was great hearing the contrast between the systems anyway.  There were some great questions regarding scalability (up vs. out), NoSQL, and many others. Kudos to Pat Wright for putting this together.

    The most impressive thing about this Code Camp was the attendance.  I believe 380 was the offical count and that is almost double what they had last year.  As a sponsor, this was fantastic as we had a ton of people come by the booth and made some good contacts, both as prospective clients and as prospective consultants.  Since the gating factor for the growth of my business has been more in relation to having the consultants to do the work than in having enough work to do, this part is important.

    Thanks to the folks at Utah Geek Events who as always, did a fantastic job putting on the event.

     

     

     

     
  • Randy Knight 12:10 pm on September 2, 2011 Permalink | Log in to leave a Comment
    Tags:   

    SQL Saturday #91 – Omaha, NE 

    This is a bit late but wanted to post about my experience at the recent SQL Saturday held in Omaha, Nebraska. This was a fantastic event, particularly given that it was the first SQL Saturday held in Omaha. It was well-organized, had great sponsor support, and the facility at the University of Nebraska at Omaha was top notch. Kudos to John Morehouse and team for putting on a fantastic SQL Saturday.

    I had the privilege to present on two topics at the event. I try to come up with catchy titles for my presentations but attendance was a bit down for these (both new sessions) so I wonder if the issue was people had no idea what they were really about. In any case I am happy to report we had quality if not quantity in attendance. Great feedback / input from the attendees. And I tried hard not to offend the developers too badly.

    As always, the best part about SQL Saturday is the interaction and networking with other speakers and attendees. I didn’t get to attend many other sessions but I did sneak into Kathi Kellenburger’s session on new T-SQL features in Denali. Good stuff.

    Links to session downloads:

    Next up: SQL Saturday #94 in Salt Lake City. In addition to speaking, my company is a sponsor so it will be a busy day.

     
  • Randy Knight 1:08 pm on July 13, 2011 Permalink | Log in to leave a Comment
    Tags: backups, powershell, robocopy, sql server agent   

    Using RoboCopy in SQL Server Agent Jobs 

    One of the most important tasks for the DBA is managing backup files. Often the SQL Server backups files themselves are written to a drive local to the database server, but we then need to copy them off to a remote share.  RoboCopy is a fantastic utility included in Windows that is great at doing this.  If you’re not familiar with this tool, you can find detailed information on it here

    However, when using SQL Server Agent to schedule a RoboCopy job, you run into an issue with Process Exit Codes.  This is because RoboCopy does not always return a 0 for success, non-zero for error.  So when you tell SQL Server Agent that 0 = Success, you get false job failures.  In fact, what RoboCopy returns is a bitmask as follows:

    Bit Description
    16 Serious error. Robocopy did not copy any files. This is either a usage error or an error due to insufficient access privileges on the source or destination directories.
    8 Some files or directories could not be copied (copy errors occurred and the retry limit was exceeded). Check these errors further.
    4 Some Mismatched files or directories were detected. Examine the output log.
    2 Some Extra files or directories were detected. Examine the output log.
    1 Some Extra files or directories were detected. Examine the output log.
    0 No errors occurred, and no copying was done. The source and destination directory trees are completely synchronized.

    As you can see from the above, there are several exit codes that are successful.  1,2,3,7,8,9, etc. In most cases, any combination of the 0,1,2,4 bits would be fine.  So what we need is a way to interpret the bitmap that is returned and send a 0 or 1 to SQL Server indicating success or failure.

    Enter PowerShell

    I wrote a short PowerShell script to deal with this as follows

       1:  param
       2:  (
       3:      [Parameter(Position=0, Mandatory=$true)] [string]$SrcFolder,
       4:      [Parameter(Position=1, Mandatory=$true)] [string]$TgtFolder
       5:  )
       6:   
       7:  ##copy
       8:  robocopy $SrcFolder $TgtFolder /S /XO /XC /XN /NP /MIN:1024 /R:2 /W:2
       9:   
      10:  ##set exit code
      11:  $exit = $lastexitcode -band 24
      12:   
      13:  exit $exit

    The script used the powershell bitwise operation –band to check to see if bits 8 or 16 are set, as these are the two actual errors we are concerned about.  It then exits with a 0 or 1, which is what SQL Server Agent expects from an OperatingSystemCmdExec job step.  Note that this applies mainly to SQL Server 2005.  In 2008 and 2008 R2 you can create a PowerShell job step so you might handle this a bit differently.

     

     
c
compose new post
j
next post/next comment
k
previous post/previous comment
r
reply
e
edit
o
show/hide comments
t
go to top
l
go to login
h
show/hide help
esc
cancel