What is the Data Type Precedence order and how is it used for Implicit Converts?

There are many data types that can be used in SQL Server.  Picking the proper data type is essential, however it is also important to know when SQL Server will automatically complete a type conversion.  When SQL Server automatically converts data types, it will use the Data Type Precedence to determine what will be the target data type for the conversion.

When does SQL Server need to automatically convert data types?  There are a number of places, however you will commonly see this when joining on columns that are not the same data type or in the WHERE clause when comparing two values that are not the same data type.

This image below is a screenshot of the list that was taken from the following Microsoft document, Click Here.

Let’s take a few minutes to go over where data types are used in SQL Server and how to gather information about the data types.  As expected you can use them when creating tables and defining columns.  Each column will have a data type assigned to it.  If you look at the image below you can see the various data types on the Production.Product table in the AdventureWorks2014 sample database.

Another way to get the data types for a particular table is to run one of the following queries.  Of course you will need to change the parameter at the end to the name of the table you are looking for.  Below are two examples. One using an information_schema view, while the other is using the sys.columns table.

SELECT TABLE_CATALOG
, TABLE_SCHEMA
, TABLE_NAME
, ORDINAL_POSITION
, DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = ‘salesorderheader’

SELECT name
, Type_name(user_type_id) AS ‘DataType’
, max_length
, precision
, scale, is_nullable
FROM sys.columns
WHERE object_id = OBJECT_ID(‘production.product’)

You will also see data types used with declaring variables and stored procedure parameters.  We declaring a variable, can you not only provide a data type but can also assign the variable a value on the same line.

DECLARE @amount INT = 20

Just an FYI, you can still use the SET keyword to assign the variable a value, as in the code below.

DECLARE @amount INT

SET @amount = 20

Now that the variable is declared and assigned a value, it can now be used.  The type conversions will happen in a few places in the TSQL.  Most commonly it will be seen in the WHERE clause when the datatype in the column is different than the data type of the variable. Using the query below as an example, the variable has been incorrectly declared as a Varchar data type, while the SalesOrderID column is an INT database.  This difference is what is forcing a type conversion when doing the comparison.

DECLARE @SorderID VARCHAR(20)

SET @SorderID = ‘43659’

SELECT *
FROM [Sales].[SalesOrderHeader]
WHERE [SalesOrderID] = @SorderID

How Do I know an Auto Type Conversion took place?  Well there are a couple of different methods.  The first method is to use an Execution Plan. Before running your query, click the button in the red box below.

When looking at an Execution plan you will see a warning sign on the operator if there is an issue.  You can see this below on the operator to the far left, it is a yellow triangle.  This can be a warning for a few things, implicit convert is just one of them.

To find out if this is indeed an implicit convert warning float your mouse over it.  When you do, you will see a popup similar to below.  This clearly shows that a convert took place.

This not only tells you that the convert happened, it also identifies the consequence of the convert.  In this case, if the Cardinality Estimate is affected in a negative manner, the query optimizer may pick a less than ideal plan.  This could lead to a performance problem.

Another approach you can use to find out if an implicit convert happened is to use the sql_variant_property function.  This function accepts two arguments, an expression and a property.  The expression is what you think it might be, this is what we would like to evaluate for the datatype.  While the property has multiple options, we are going to focus solely on using the BaseType property.  We will use this to determine the data type of an expression.  Click here for find more information about the sql_variant_property.

If you look at the code below, you will see that there are two variables being declared and then in turn being passed into the first argument of the sql_variant_property function.  Notice that the two variables are different types, one TinyInt while the other is varchar.

DECLARE @one TINYINT
DECLARE @two VARCHAR(20)

SET @one = 1
SET @two = ‘2’

SELECT SQL_VARIANT_PROPERTY(@one + @two,‘basetype’) AS ‘ResultOfExpression’
, SQL_VARIANT_PROPERTY(@one,’basetype’) AS ‘DataTypeOf @one’
, SQL_VARIANT_PROPERTY(@two,’basetype’) AS ‘DataTypeOf @two’

When you run the above query you will get the results below.  Notice that the second two column return the same data type as the one specified when each of the variables were declared.  As for the first column, I am taking a TINYINT data type and adding it to a varchar datatype.  Because the data types are different, SQL Server will automatically convert the result to the variable data types that are higher up the precedent level.  In this case the resulting value will be a TINYINT.  SQL Server converted the ‘2’ to an tinyint data type from a varchar data type.

One additional tool you can use to capture implicit converts is Extended Events.  If are not familiar with Extended Events this is just a bit outside the level of this post.  However, I will cover a few basics.  Extended Events is a tool that can be used to capture information about what is happening on your server. Here is a link of a session I did at the SQL Saturday event in Dallas in 2018.  This will give you a high level overview of how to create a session.  Click Here.  Also, Grant Fritchey has a number of great blog posts on Extended Events.  They can be found here.

If you are familiar with Extended Events, the event you will want to use is the plan_affecting_convert event.

Here is the description of this event:

“Occurs when a type convert issue affects the plan. The expression value indicates the conversion that can cause inaccurate Cardinality Estimation or prevent from using a seek based plan in the query plan choice. If performance is affected, rewriting the query could help.”

Below is an example of what the data will look like.  We are able to collect the time as well as the query.  While these additional items are not in the below image, you can also collect the host, database name and login name.

Now that we have covered what implicit converts are, you might be wondering how can I prevent the auto conversions?  This is more of an matter of design than anything else.  Below are a few suggestions that will help prevent type conversions.

      • Declare data types appropriately for variables when writing TSQL code
      • User proper data types when designing parameters for stored procedures
      • Chose proper data types for table columns

In summary, there are a number of tools that we can use to identify when implicit converts.  Once you know when they are happening you can now begin to assess if it is causing a performance issue or not.  If so, you can begin to work on a solution.

Thanks for visiting my blog!!!

ADS: TSQL Checker

Azure Data Studio has quite a few extensions that are very useful.  Over the past six to eight months I have completed a number of posts on quite a few of these extensions.  So far one of my favorite extension is the PoorSQL Formatter.  It provides great assistance in the formatting of Transaction SQL code. What it doesn’t do, is help identify code that is not in line with best practices.  This is where the TSQL Checker comes into play.

This extension was developed by Daniel Janick. Daniel is a Microsoft MVP from the Austin, TX area.  He can be found at @SQLSME on Twitter.

You might be wondering exactly what does this extension check.  According to the extension documentation this is what it checks:

“TSQL checks for hints, select * from options”

Of course “SELECT *” is a very well known problem in query design.  Hints and options can also create significant performance issues as well.   What exactly is a hint?  According to Microsoft’s documentation a hint is something that will over ride the execution plan that the query optimizer might select for a query. Here is a link to Microsoft’s documentation on hints.  Hints will act on the four DML statements, SELECT, INSERT, UPDATE and DELETE.  Hints should only be used as a last resort and only by experienced developers or DBAs.

While this extension is still in preview mode, it can still be very useful.  To install it you will click the “Install” button, green button below.  This will appear when you are looking at the documentation of the extension.  When you do, you will be asked to open the GitHub sight for this extension.

When you click open, you will be taken to the GitHub site for this extension.  You will want to download the tsqlchecker-0.0.1.vsix file.  It is highlighted below.  When saving it, save it in a location where it will not be overwritten.

To install this extension, simply go to the File menu and then go to “Install extension from Vsix file”.  While some extensions require a restart of Azure Data Studio, this extension does not.

The purpose of this extension is to help you identify code that is not inline with best practices.  In order to do so, the extension needs to mark the offending code in some manner.  The extension will do this one of three ways.

    1.  Highlighting the code with a box:
    2.  Highlighting the code in yellow:
    3. Highlighting the code in red:

Let’s take a look at some of the code that the TSQL Checker will flag.

Note: This code was take from the Microsoft documentation.  This really isn’t a post on what these things do, just how TSQL Checker flags them.  Refer to the Microsoft documentation for more information on these.

SELECT *

MAXDOP

FORCESEEK

FORCESCAN

LOOP JOIN

MERGE JOIN

OPTIMIZE FOR

HASH JOIN

For all of these warnings, the developer has also added a popup that will provide additional information.  When you float the cursor over the warning you will see somethings similar as you is in the image below.

I really like this extension.  It reminds us of code that is less than ideal and should be reviewed.  Remember, few if any of these hints are recommended for production use.  If you run into a situation that you think these are part of the solution, just do your homework first.  Research and see if there is a better way to address the problem.

Thanks for visiting my blog!!!

 

ADS: DB Snapshot Creator

Like many Azure Data Studio extensions, DB Snapshot Creator is designed to bring functionality into ADS that is not present by default.  This extension was developed by Sean Price. As the name suggests, this extension can be used to easily create database snapshots.  Before going too deep into this extension, let’s take a quick moment to go over what a snapshot is.

First of all don’t think of it as a backup.  Think of it as a read-only copy of the database.  As pages are modified for the first time in the source database, SQL Server will move the original unmodified pages to the snapshot.  This process will allow users to see that snapshot that is a mirror of the database when the snapshot was created. You might be asking, why should I use a snapshot?  There are a number of reasons, but the biggest in my mind is the ability to use the snapshot for reporting purposes.

What if an 8-K page is modified twice?  SQL Server will only copy the page to the snapshot the first time it is modified.  After that, the page will not be copied again.

In Microsoft’s documentation, found here, right at the beginning of the document MS makes one very important point.

“Database snapshots are unrelated to snapshot backups, snapshot isolation of transactions, or snapshot replication.”

To find if there are any snapshots you can use the code below.  This code will not only tell you if snapshots exist, it will also return what database it is associated with and when it was created.

SELECT    a.name AS ‘Snapshot Name’
                , a.create_date AS ‘Snapshot Create Date’
                , b.name AS ‘Source Database’
                , b.create_date AS ‘Database Create Date’
FROM sys.databases a
     INNER JOIN sys.databases b
ON a.source_database_id = b.database_id

This is what the results will look like.

Microsoft has some good documentation on Snapshots.  Go here to read it.

How to Create the Snapshot in SSMS

This is pretty easy to do.  Many times if you want to do something with a database you can right click on the database and easily perform the desired task. This could be completing a backup, shrink the database and restore the database.  One task that is not present is Create Snapshot.  Given this, you will need to use TSQL to create the snapshot.  Note the file extension, it is not MDF or NDF.

CREATE DATABASE [AdventureWorks2014_Snapshot_02_27_2020_01] ON
(NAME = [AdventureWorks2014_Data],
FILENAME = ‘C:\Program Files\Microsoft SQL Server\MSSQL14.MSSQLSERVER\MSSQL\DATA\AdventureWorks2014_Snapshot_02_27_2020_01.ss’)
AS SNAPSHOT OF [AdventureWorks2014];
Below is a screenshot of the files in the file system.  As you can see, the file for the snapshot has a different extension and there is not a corresponding .ldf file.

How to Create the Snapshot in Azure Data Studio

The option to use TSQL is always present, even in Azure Data Studio.  And just as in SSMS, when you right click on the database, Create Snapshot is not an option.  This is where the DB Snapshot Creator extension can help.  Something to keep in mind as we go over this extension, it is still in preview mode.  Neither the documentation in Azure Data Studio nor the GitHub site have a great deal of documentation on this.  However, there is an FAQ that answers three questions.  These questions are below and were taken directly from the extension documentation.

To install the extension you will first need to download the .vsix file.  When viewing the extension the in the Extension Marketplace, you can click the green Install button. This will take you to the Github where you can download the file.

Make sure the place this file in a location where it will not be deleted.  Once downloaded, you can go to the File menu and to “Install Extension from VSIX package”.

Then simply find the file and it will install.  Now when you right click on a database you will see a new menu item to create the snapshot.

By default, when you click the above menu item Azure Data Studio will write the code to create the extension, but not actually create it.  The CREATE DATABASE statement earlier in this post was created by this extension.  This code is also below.

CREATE DATABASE [AdventureWorks2014_Snapshot_02_27_2020_01] ON
(NAME = [AdventureWorks2014_Data],
FILENAME ‘C:\Program Files\Microsoft SQL Server\MSSQL14.MSSQLSERVER\MSSQL\DATA\AdventureWorks2014_Snapshot_02_27_2020_01.ss’)
AS SNAPSHOT OF [AdventureWorks2014];

However, if you would like to skip the step of having the code written, you can go to preferences and uncheck the box below.

While in SSMS, the snapshots are located in a folder as seen below.

In Azure Data Studio, the snapshots are located at the same level as the rest of the databases.

 

This extension makes the creation of a database snapshot very easy!  And like all other extensions, it has a great price. FREE!!

Thanks for visiting my blog!!

 

Why do I include Plan Guides in my Server Assessment

When I complete a server assessment there are a number of areas I look at.  These areas include security, performance and configuration.  Most of the specific items fall into one of these categories.  In my opinion, a complete server assessment should not only return the state of the server but should also return any configuration settings that may have an impact on performance.  Plan Guides fall into this area.  They can have a negative impact on performance just a quickly as they can have a possible impact on performance.

I my over 20 years of working with SQL Server I have never seen a plan guide actually used in production.  This doesn’t mean they are not being used, just that i haven’t seen it.

Before getting into why I look for Plan Guides, let’s take a few moments to go over exactly what a plan guide is.

Below is the definition from Microsoft:

“Plan guides let you optimize the performance of queries when you cannot or do not want to directly change the text of the actual query in SQL Server 2019 (15.x). Plan guides influence the optimization of queries by attaching query hints or a fixed query plan to them.”

Basically Plan Guides allow you to utilize optimizer hints without modifying the source code.  For example, Plan Guides allow for the use of a particular physical join type.  The optimizer utilizes a Hash Match join and you feel that the query might perform in a more optimal manner with a Nested Loop, the Plan Guide will allow this to happen without changing any code.

While this really isn’t a post about how to create and use Plan Guides, I think it is important to have a basic understanding of them. This is a link to Microsoft that will provide more detail.

When using the Object Explorer, Plan Guides can be found under Programmability in each database.

When I execute the query below in the AdventureWorks2014 database the actual execution plan will utilize a Merge Join operator.  This is without a plan guide to tell the optimizer to do anything different.  Of course, as you can see, an optimizer hint is also not used in the query.

SELECT *
FROM Sales.Customer AS c
INNER JOIN Sales.Customer AS ca
ON c.CustomerID = ca.CustomerID
WHERE ca.TerritoryID = 5

 

When a Plan Guide is created, you will be asked to provide the desired hint.  In the case below, the hint is to use a Nest Loop whenever the above query is sent to the server.

When the plan exists, the execution plan will include the use of the Nest Loop join.  This is because the query that matched the one in the defined in the Plan Guide.

Something to keep in mind, Plan Guides are both case sensitive and space sensitive.  If the plan guide includes the query below:

SELECT *
FROM Sales.Customer AS c
INNER JOIN Sales.Customer AS ca
ON c.CustomerID = ca.CustomerID
WHERE ca.TerritoryID = 5

And the following query is executed:

select *
FROM Sales.Customer AS c
INNER JOIN Sales.Customer AS ca
ON c.CustomerID = ca.CustomerID
WHERE ca.TerritoryID = 5

Notice that the SELECT keyword is not capitalized.  This will force the plan guide to be ignored.  The plan guide will also be ignored if there is a trailing space at the end of one of the lines.

Also, plan guides can also be enabled\disabled.  This can be done by simply right clicking on the plan guide in Management Studio and going to “Enable” or “Disable”.

When to use Plan Guides

While I haven’t used Plan Guides I can see where they have the potential to improve performance of a particular query in certain situations.  Many vendors don’t allow you to change the code of the stored procedures to add a query hint, not to mention this also may not be the best idea in the first place.

So why do a look for Plan Guides during the server assessment?

During the server assessment, I look for these more for awareness than anything else.  If a particular query performs poorly, it could be because of the plan guide.  If they do exist then it is important to determine if is helping or contributing to the poor performance.  As mentioned earlier, if a Plan Guide does exist, you will also need to determine of it is enabled or disabled.

The code below will check every database and return a row for each plan guide found.  In addition, it will return the query and whether or not it is enabled.

        CREATE TABLE #PGInfo
          ( DBName                 VARCHAR(128)
          , GuideName            VARCHAR(500)
          , CreateDate              DATETIME
          , ModifiedDate         DATETIME
          , IsEnabled                BIT
          , QueryStatement    VARCHAR(300)
          , Type                         NVARCHAR(Max))
       
       EXECUTE master.sys.sp_MSforeachdb ‘USE [?] INSERT INTO #PGInfo   SELECT
         DB_Name()
          , Name
          , create_date
          , modify_date
          , is_disabled
          , query_text
          , scope_type
        FROM sys.plan_guides ‘
        SELECT *
        FROM #PGInfo
        IF @@ROWCOUNT = 0
        BEGIN
         SELECT ‘No Plan Guides were found in any databases.’
        END
        DROP TABLE #PGInfo

 

As stated earlier, looking for Plan Guides is more about awareness than anything else.  If there is a performance issue with a particular query, knowing that these exist important.

Thanks for visiting my blog!

 

ADS: Simple Data Scripter

Moving data in a table from a production server to a lower environment such as a development server can be done a number of different ways.  These include backup\restore, using SSIS to move the data, import\export wizard and scripting the data in SQL Server Management Studio.  Azure Data Studio by itself doesn’t have a way to script the data in a table and it does not have the import\export wizard.  This is where the Table Data Scripter extension comes in handy.

Like most extensions for Azure Data Studio, this extension is also in a preview state.  As of the date of this post, it is currently at version 0.1.1 and is published by Sean Price. The documentation for this extension can be found here, Simple Data Scripter. In the documentation there are a few limitations identified

      • Not all data types are supported, specifically the binary datatypes like text, binary and varbinary
      • Has only been tested with SQL Server
      • Does not work on a view

Some extensions will add options under Preferences.  This extension does not add any options.  Given that, there is limited ability to configure this, which is OK, not really much of a need to do any configuration.

Just as a review, let’s take a look at how we can script the data in SQL Server Management Studio.  After right clicking on the database and going to Tasks…Generate Scripts…  When you do, a wizard will pop up and then after a few clicks on next, you will arrive at the screen below.  The box highlights the “Types of data to script” option.  With this there are three options, Data Only, Schema and Data and finally Schema Only.

When right clicking on a database in Azure Data Studio you will see limited options none of which are related to scripting data.  This is also true when right clicking on a table in the database.  Here are the options we see by right clicking on a table, as before, none of which are related to scripting data.

In order to script the data in Azure Data Studio we will need to install the Simple Data Scripter extension.  This is a pretty straight forward and simple install.  You will need to download the .vsix file.  You can get to the GitHub to download the file from the documentation for the extension in ADS.  You can install it under the File menu.  While you will not be prompted to restart ADS when you install it, I usually like to restart ADS anyway.  In this case, the extension doesn’t move to the installed extensions until after a restart.

Now that the extension is installed, you will see a new option when you right click on a table.  This is another potential limitation of the extension, there isn’t an option to script all the data in the database.  Well, at least I haven’t found it yet.  But then again, I am not sure having a simple place to script all the data in one place if the best way to go.

When clicked the following screen will appear at the top Azure Data Studio.  Initially when we look at it our first thoughts might be, what a bad query.  But it does make sense, we are creating a script of all the data in the table.

If you click anywhere, ADS will cancel the query and you will see this pop up in the lower right corner and the above screen will disappear.

If you press enter Azure Data Studio will execute the query and generate the script. You will not see a result set but you will see the script.  It will look similar to below.  Notice the Create Table statement at the top, it is commented out.  The table that is used for the example is named RentalCar.  The script is working with a table named #tempRentalCar.

When the script is finished, the Task window will open up at the bottom of the screen.  The top two are successful executions while the third failed, reason for the failure will be covered shortly.

You may be wondering if the query can be modified.  The answer is yes, however not every type of statement will work.  If you want to add a WHERE clause that works just fine.  However, as the query become more complex it failed more frequently.  I attempted to run a query with a join in it and it failed.  That is the failure in the image above.  The error stated “Query has no results to return”.  However, the query works just fine when running in ADS or SQL Server Management Studio.

Here are some of the statements I have tried.

      • Query with a join – failed
      • Query with a sub-query – failed
      • Query with a WHERE clause and just one table – succeeded

When compared to the expectations, this extension works very well and I can definitely see a use for this.

Thanks for visiting my blog!!

 

Auto Delete Jobs????

Have you ever looked at something in SQL Server and wonder why it is there?  That is what I think when I see this option in the SQL Server Agent job properties.  I can not come up with any good reason of why you would want a job to delete itself upon completion.  I even did a Google search and really didn’t find a good reason.  However, if you know of a great reason of why you would want to enable this, I would love to hear about it.

If you are not familiar with this option, you can find it under the Notifications tab of the job properties.

Just like all the notifications, you have several options.

      1. When the job secceeds
      2. When the job fails
      3. When the job compeletes

When the job deletes, it will also take a job history with it.  Basically there will be no evidence that the job ever existed.  This is pretty straight forward, so you might be wondering why bring it up.  Well, I see this setting as a potential danger, especially if you have a disgruntled DBA.  While being a DBA is a great job, there are, from time to time things that can have a negative impact on how we feel about our job.  Luckily the SQL Server community is filled with really great people.

We have a job that checks all of our jobs looking for any jobs that has this set.  You can use the query below to get the necessary information. There is a column, delete_level in sysjobs that will allow us to get the information needed.

SELECT    name
  , delete_level
  , CASE delete_level
    WHEN 0 THEN ‘Not Set’
    WHEN 1 THEN ‘Delete on Success’
    WHEN 2 THEN ‘Delete on Failure’
    WHEN 3 THEN ‘Delete on Completion’
    END AS ‘Delete Level Setting’
FROM sysjobs

So why do I think this is potentially dangerous?  Image the disruptive code that could be written and then imagine that same code in a job that is scheduled to execute 6 months later.  Now go one step further, all evidence of that job running is now gone.  I really don’t want to give too much information, but I can think of several things that could be done that could cost the company a ton of money.  This is why we check for this.

I also include this check on my server assessment scripts.

As I said earlier, if anyone can give me a good reason to have this set, I am willing to listen and will update this post accordingly.  Giving proper credit of course.

My suggestion is to look for this!

Thanks for visiting my blog!!!!