European Windows 2012 Hosting BLOG

BLOG about Windows 2012 Hosting and SQL 2012 Hosting - Dedicated to European Windows Hosting Customer

SQL Server 2016 Hosting - HostForLIFE.eu :: Maximum Limit Value For Integer Data Type in SQL Server 2012

clock November 27, 2018 10:12 by author Peter

In this article, I described how to calculate the maximum range of various integer data types in SQL Server. TINYINT, SMALLINT, INT and BIGINT are all number data types. The difference between these data types are in the minimum and maximum values. So let's have a look at a practical example of how to calculate the maximum range of the integer data type in SQL Server. The example is developed in SQL Server 2012 using the SQL Server Management Studio.

Calculating the maximum range of various integer data types.

Bigint Data Type
The Bigint data type represents an integer value. It can be stored in 8 bytes.

Formula   2^(n-1) is the formula of the maximum value of a Bigint data type.
In the preceding formula N is the size of the data type. The ^ operator calculates the power of the value.
Now determine the value of N in Bit:
Select (max_length * 8) as 'Bit(s)' from sys.types Where name = 'BIGInt' 

 

Determine the maximum range of Bigint
The formula is:
2^(n-1) here N=64

Select Power(cast(2 as varchar),(64) -1) as 'Bigint max range'  from sys.types Where name = 'BIGInt'

The range of a Bigint data type is -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807.

INT Data Type
Int represents an integer value that can be stored in 4 bytes. INT is the short form of integer.

Formula
2^(n-1) is the formula to find the maximum of an INT data type.
In the preceding formula N is the size of data type. The ^ operator calculates the power of the value.

Now determine the value of N in Bit:
Select (max_length * 8) as 'Bit(s)' from sys.types Where name = 'Int'

Determine the maximum range of int
The formula is:
2^(n-1) here N=32
Select Power(cast(2 as varchar),(32) -1) as 'int max range'  from sys.types Where name = 'Int'

The range of an int data type is -2,147,483,648 to 2,147,483,647.

Smallint Data Type
Smallint represents an integer value that can be stored in 2 bytes.

Formula 
2^(n-1) is the formula to find the maximum of a Smallint data type.
In the preceding formula N is the size of the data type. The ^ operator calculates the power of the value.

Now determine the value of N in Bit:Select (max_length * 8) as 'Bit(s)' from sys.types Where name = 'Smallint'

Determine the maximum range of Smallint
The formula is:
2^(n-1) here N=64
Select Power(cast(2 as varchar),(16) -1) as 'Smallint max range'  from sys.types Where name = 'SMALLInt'

The range of a Smallint data type is -32768 to 32767.
Tinyint Data Type
Tinyint represents an integer value that can be stored in 1 byte.
The range of a Tinyint data type is 0 to 255.

HostForLIFE.eu SQL Server 2016 Hosting
HostForLIFE.eu is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.



How To Split/Separate Numbers And Alphabets From Alpha Numeric String In SQL Server?

clock November 13, 2018 10:11 by author Peter

Today, I am going to explain how you can split/separate numbers and alphabets from an alphanumeric string in SQL server. When you work with any database-related application, either in Web or Windows applications, sometimes based on your requirement you have an alphanumeric string and you only want numbers from that string and want to use those numbers in your entire application as per your need, possibly as a variable, parameter, or a string concatenation.

Implementation
In my case I want to generate auto-increment token number and that token number will generate with a combination of My Invoice Number and Heder Name of Store, and in my Invoice Table Invoice Number like "HSP14569" where "HSP" is Header Name of Store. That can change based on Store selection and "14569" is my Invoice Number.

Actually, what I need is to split my invoice number from "HSP14569" To "14569" and increment with "1," so that will be "14570". Now, I will contact this new number with my header of the store.

So, yesterday I wrote one user-defined function in SQL server, which will return only numeric values from my string.

SQL Server User Defined Function
    CREATE FUNCTION dbo.GetNumericValue 
    (@strAlphaNumeric VARCHAR(256)) 
    RETURNS VARCHAR(256) 
    AS 
    BEGIN 
    DECLARE @intAlpha INT 
    SET @intAlpha = PATINDEX('%[^0-9]%', @strAlphaNumeric) 
    BEGIN 
    WHILE @intAlpha > 0 
    BEGIN 
    SET @strAlphaNumeric = STUFF(@strAlphaNumeric, @intAlpha, 1, '' ) 
    SET @intAlpha = PATINDEX('%[^0-9]%', @strAlphaNumeric ) 
    END 
    END 
    RETURN ISNULL(@strAlphaNumeric,0) 
    END 
    GO 


Note
You can modify this user defined function based on your need.

Let's see how you can use this user-defined function. Below, I have included some of the ways to use this function.
 
Sql Server Select Statment
    SELECT dbo.GetNumericValue('') AS 'Empty'; 
    SELECT dbo.GetNumericValue('HSP14569AS79RR5') AS 'Alpha Numeric'; 
    SELECT dbo.GetNumericValue('14569') AS 'Numeric'; 
    SELECT dbo.GetNumericValue('HSP') AS 'String'; 
    SELECT dbo.GetNumericValue(NULL) AS 'NULL'; 


Output

Summary
You can see the result was generated as above. If you have some alternate way to achieve this kind of requirement then please let me know, or if you have some query then please leave your comments.

 

HostForLIFE.eu SQL Server 2016 Hosting
HostForLIFE.eu is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.



SQL Server 2016 Hosting - HostForLIFE.eu :: All About Primary Key And Its Basics

clock November 7, 2018 08:44 by author Peter

In this series of articles, we will go deep into SQL Server from scratch and will gain knowledge of queries, optimization, and database administration. This is the first article of the series where we will learn about general SQL queries and their functioning. Images have been used wherever necessary so as to make you understand every command properly.

All Queries which I am posting today you can use  directly on your query plan like copy, paste and execute this query.
Each query has a valid column name and similarly I have shown in the form of image for proper understanding and proper usage

Find all Primary key in Give Database in following format,

SELECT i.name AS IndexName, 
    OBJECT_NAME(ic.OBJECT_ID) AS TableName, 
    COL_NAME(ic.OBJECT_ID, ic.column_id) AS ColumnName 
FROM sys.indexes AS i 
INNER JOIN sys.index_columns AS ic 
ON i.OBJECT_ID = ic.OBJECT_ID 
AND i.index_id = ic.index_id 
WHERE i.is_primary_key = 1  


Finding Constrains and Type of Constrain i.e. Primary and foreign key relation in the given database

SELECT OBJECT_NAME(OBJECT_ID) AS NameofConstraint, 
    SCHEMA_NAME(schema_id) AS SchemaName, 
    OBJECT_NAME(parent_object_id) AS TableName, 
    type_desc AS ConstraintType 
FROM sys.objects 
WHERE type_desc IN('FOREIGN_KEY_CONSTRAINT', 'PRIMARY_KEY_CONSTRAINT')  


Detailed level relationship and description of primary key and foreign key

SELECT f.name AS ForeignKey, 
    SCHEMA_NAME(f.SCHEMA_ID) SchemaName, 
    OBJECT_NAME(f.parent_object_id) AS TableName, 
    COL_NAME(fc.parent_object_id, fc.parent_column_id) AS ColumnName, 
    SCHEMA_NAME(o.SCHEMA_ID) ReferenceSchemaName, 
    OBJECT_NAME(f.referenced_object_id) AS ReferenceTableName, 
    COL_NAME(fc.referenced_object_id, fc.referenced_column_id) AS ReferenceColumnName 
FROM sys.foreign_keys AS f 
INNER JOIN sys.foreign_key_columns AS fc ON f.OBJECT_ID = fc.constraint_object_id 
INNER JOIN sys.objects AS o ON o.OBJECT_ID = fc.referenced_object_id 


Use the above snippets as per your requirement.

In most of the cases it's is going to be used in the Database Analysis where Database size and table are large and high in number.

Thus, we learned about the basic queries of SQL. If you have some doubt, or want to add some more information in this article, please feel free to write me in the comments section.

 

HostForLIFE.eu SQL Server 2016 Hosting
HostForLIFE.eu is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.



SQL Server 2016 Hosting - HostForLIFE.eu :: How To Check If A String Contains A Substring In SQL Server?

clock November 2, 2018 12:14 by author Peter

In this blog, I wil explain how to check a specific word or character in a given statement in SQL Server, using CHARINDEX function or SQL Server and check if the string contains a specific substring with CHARINDEX function.
 
Alternative to CHARINDEX() is using LIKE predicate.
 
Method 1 - Using CHARINDEX() function

CHARINDEX()
This function is used to search for a specific word or a substring in an overall string and returns its starting position of match. In case no word is found, then it will return 0 (zero).
 
Let us understand this with examples.

Syntax
    CHARINDEX ( SearchString,WholeString[ , startlocation ] )

Example
    Declare @mainString nvarchar(100)='Kenneth James    ' 
    ---Check here @mainString contains Kenneth or not, if it contains then retrun greater than 0 then print Find otherwise Not Find 
    if CHARINDEX('Kenneth',@mainString) > 0  
    begin 
       select 'Find' As Result 
    end 
    else 
        select 'Not Find' As Result 


Output

CHARINDEX
 
Method 2 - Using LIKE Predicate
    DECLARE @WholeString VARCHAR(50) 
    DECLARE  @ExpressionToFind VARCHAR(50) 
    SET @WholeString = 'Kenneth James' 
    SET @ExpressionToFind = 'James' 
      
    IF @WholeString LIKE '%' + @ExpressionToFind + '%' 
        PRINT 'Yes it is find' 
    ELSE 
        PRINT 'It doesn''t find' 

HostForLIFE.eu SQL Server 2016 Hosting
HostForLIFE.eu is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.



SQL Server 2016 Hosting - HostForLIFE.eu :: Identity Column In SQL Server

clock October 23, 2018 11:42 by author Peter
In this article, we will learn about identity function and how we reset identity columns in SQL Server. Identity keyword is used in SQL Server to auto increment column value.
Identity is a function which can be used to generate unique id values of a particular column automatically. It can be applied on integer datatype column only. A table should contain only one identity column.

Syntax
identity(seed,increment)
Default value of identity is identity (1,1)

The seed represents the starting value of an ID and the default value of seed is 1.

Increment: It will represent the incremental value of the ID and the default value of increment is 1.

Example

Create table student(Id int Primary key Identity ,Name varchar(50),City varchar(50),TotalNumer int)  
insert into student(Name,City,TotalNumer) values('A','Delhi',120)  
insert into student(Name,City,TotalNumer) values('B','Noida',110)  
insert into student(Name,City,TotalNumer) values('C','Gurgaon',125)  
select * from student  

Check the table, ID value is increased automatically. The default value of identity is the identity (1,1) ID column starts with 1 and increased by 1.

Example
User defined seed and incremental values,

create table tec(Id int identity(10,5),Deptname varchar(50))  
insert tec values('Dot Net')  
insert tec values('SQL')  
select * from tec 

Id value starts by 10 and increases by 5.

Note
If we want to insert the values into an identity column explicitly then we should follow the syntax.

Set identity_insert <Table name> off/on

Off-It is a default connection; we cannot insert a value into an identity column explicitly.

On-we can insert the values into an identity column explicitly. 

Reset Identity Column
Syntax
dbcc checkident('table name',reseed,0)
 
We can reseed identity column value using the DBCC CHECKIDENT command of SQL. Using this command we can reset identity column values,
dbcc checkident('student',reseed,0)

In this article, we have learned about identity column in SQL Server and how we can reset identity column values.

HostForLIFE.eu SQL Server 2016 Hosting
HostForLIFE.eu is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.



SQL Server 2016 Hosting - HostForLIFE.eu :: Resolving The "Wait Operation Timed Out" Error When TFS Stops Working

clock October 17, 2018 11:48 by author Peter

Today, I will share one more interesting issue. A few days ago, our system administrator installed the Microsoft Test Manager 2012 on Microsoft Team Foundation Server 2010 (TFS 2010). Suddenly, our TFS stopped working. TFS was not able to extract the data from the database. Then I checked the error in the Event Viewer and found the error as below.

I did confirm that all the services inside the SQL Server were working fine. It became very difficult to find out the cause of this error because in our environment, SharePoint Server also existed and it was using the same SQL Server and working fine. After searching a lot about it on the internet, I found somewhere that the people got the same error after installing the Visual Studio 2011 and Visual Studio 2012.
 
Finally, I got the solution. I removed “.NET FrameWork 4.5″ from the system and reinstalled the ”.NET FrameWork 4.0". Then, our TFS Server went up again and started running fine. But it wasted a lot of time to find this solution, so, I am posting this it here to help people. However, I would advise you to be careful before making any changes or installing something new on the running server.

HostForLIFE.eu SQL Server 2016 Hosting
HostForLIFE.eu is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.



SQL Server 2016 Hosting - HostForLIFE.eu :: How To Use TRY CATCH In SQL Procedure?

clock October 10, 2018 11:18 by author Peter

In this post, we will learn how to use TRY CATCH in SQL procedure and store an error with error text. Here is a simple example for generating the error and storing it in a SQL table. Let's start coding. For saving the error in the table first we need to create the table in SQL Database. See below.
    CREATE TABLE [dbo].[Error_StoreProcedure]( 
        [ID] [bigint] IDENTITY(1,1) NOT NULL, 
        [ErrorNumber] [varchar](50) NULL, 
        [ErrorSeverity] [varchar](50) NULL, 
        [ErrorState] [varchar](50) NULL, 
        [ErrorProcedure] [varchar](500) NULL, 
        [ErrorLine] [varchar](50) NULL, 
        [ErrorMessage] [varchar](max) NULL, 
        [EntryDate] [datetime] NULL, 
     CONSTRAINT [PK_Error_StoreProcedure] PRIMARY KEY CLUSTERED  
    ( 
        [ID] ASC 
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] 
    GO

After creating the above table we need to create one procedure for saving the error in the table;  see below.
 CREATE PROCEDURE usp_GetErrorInfo   
    AS   
    BEGIN 
        INSERT INTO Error_StoreProcedure SELECT   
        ERROR_NUMBER() AS ErrorNumber   
        ,ERROR_SEVERITY() AS ErrorSeverity   
        ,ERROR_STATE() AS ErrorState   
        ,ERROR_PROCEDURE() AS ErrorProcedure   
        ,ERROR_LINE() AS ErrorLine   
        ,ERROR_MESSAGE() AS ErrorMessage 
        ,dbo.GetDateTimeZone()   
    END


After creating the above procedure now we have to use the above procedure inside the other procedure.
    CREATE PROCEDURE TESTING_ERROR_PROCEDURE 
      
    AS 
    BEGIN 
     SET NOCOUNT ON; 
     
        BEGIN TRY   
             
            -- Generate divide-by-zero error.   
            SELECT 1/0;   
         
        END TRY   
        BEGIN CATCH   
             
            -- Execute error retrieval routine.   
            EXECUTE usp_GetErrorInfo;   
         
        END CATCH;    
     
    END 
    GO


The above procedure generates the error and goes to the CATCH part and saves all information of the error into our error table.
Run this query SELECT * FROM Error_StoreProcedure

See the output of the above table. Output displays procedure name and line number of the error.

European SQL 2016 Hosting
European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



SQL Server 2014 Hosting - HostForLIFE.eu :: Transfer Database From SQL Server 2008 To 2014

clock September 27, 2018 11:52 by author Peter

There are lots of companies that use Microsoft services for creating and editing databases and table records. It is one of the most sought-after technology when it comes to relational database management system. They keep upgrading their products to remove bugs and improve services. One may need to transfer database from SQL Server 2008 to 2014 to keep up with the latest requirements. It is better to have complete knowledge with respect to steps involved in performing the migration. There are different ways to perform this procedure without any data loss.

Different Ways to Transfer Database from SQL Server 2008 to 2014
Following is a snapshot of all the methods one can opt for when moving databases,

  • Transfer Database using Backup and Restore Option
  • First, archive the full database with all the instances.
  • Then, copy the backup to the target location.
  • Next, restore it on the destination Server specify the ‘WITH NORECOVERY’ option.
  • To migrate SQL Server 2008 database to 2014 by overwriting the pre-existing database, use the ‘WITH REPLACE’ option.

Move Database using Attach and Detach

  • First, detach the source Server by using the sp_detach_db stored procedure.
  • Then, copy the .mdf, .ldf and .ndf files to the destination computer.
  • Next, use the sp_attach_db stored procedure to attach the database to the target Server.
  • Browse to the location where the copied files are saved on the new machine.

Transfer using Import and Export Wizard
There is an inbuilt facility provided by Microsoft for SQL Server 2008 to 2014 migration. It is the Data Transformation Services Import and Export Data Wizard. It has the ability to transfer complete databases or selectively move objects to the destination database. It can be implemented by repeating the steps below:
First, go to SQL Server Management Studio on the source Server and select the database to export.
Then, right-click on it and go to Tasks >> Copy Database Wizard.
Now, select the source and destination credentials and choose appropriate settings.
Then, click Next or schedule SQL Server 2008 to 2014 migration for some other time.
Finally, click on the Execute button to implement the changes made.

Transfer SQL Server Scripts to Destination Server
First, launch the SQL Server Management Studio on the source server.

  • Then, select the database and right-click on it.
  • Then, go to Tasks >> Generate Scripts Wizard(GSW).
  • Next, select the appropriate choice from the multiple options available.
  • Make sure that the ‘script data = true’ is selected to move data as well.
  • Then, select Next >> Next >> Finish.
  • Next, connect to the Database Server and create a new database in it.
  • Then, select a ‘New Query’ button from the navigation bar and paste the scripts generated by the GSW.
  • Finally, execute them on the destination database.

It is a smarter decision to transfer database from SQL Server 2008 to 2014. It contributes towards organization’s growth and technology upgrade needs. There are far too many ways to perform this migration. It is not easy to understand and to implement them without any trouble. Even technical professionals can use some help now and again. This post discusses all the manual means to migrate SQL Server 2008 database to 2014. One can also go with SysTools SQL Server Database Migrator to transfer SQL Server database from one Server to another in a small down time in few clicks.

HostForLIFE.eu SQL 2014 Hosting
HostForLIFE.eu revolutionized hosting with Plesk Control Panel, a Web-based interface that provides customers with 24x7 access to their server and site configuration tools. Plesk completes requests in seconds. It is included free with each hosting account. Renowned for its comprehensive functionality - beyond other hosting control panels - and ease of use, Plesk Control Panel is available only to HostForLIFE's customers. They
offer a highly redundant, carrier-class architecture, designed around the needs of shared hosting customers.

 



European SQL 2016 Hosting - HostForLIFE.eu :: Ten SQL Server Shortcuts You Must Know

clock September 19, 2018 12:31 by author Peter
SQL Server is a relational database management system (RDBMS) developed by Microsoft. As a Database Server, it is a software product with the primary function of storing and retrieving data as requested by other software applications, which may run either on the same computer or on another computer across a network.
Many developers are familiar with using some of the below listed shortcuts for SQL Server Management Studio. Using keyboard is always a preferred way of working as it boosts the working speed tremendously. Thus, I thought of sharing my experience listing these shortcuts that I usually find helpful while working with SQL Server Management Studio.

New Window
CTRL + N: Open up a new query Window in SQL Server Management Studio (SSMS).

Comment Code
CTRL + K, CTRL + C: Comment the selected text.
CTRL + K, CTRL + U: Uncomment the selected text.

Go to Line
CTRL + G: Go to specified line number in the current query window.

Result Pane
CTRL + R: Shows/Hides the Result Pane. Toggle the query results.
CTRL + T: Display results to Text
CTRL + D: Display results to Grid
CTRL + SHIFT + F: Display results to File

Change Case
CTRL + SHIFT + U: TChange the selected text to UPPER CASE.
CTRL + SHIFT + L: Change the selected text to lower case.
 

IntelliSense
CTRL + SPACE, TAB: Using Ctrl + Space, suggestions would be given, and using Tab, you can complete that suggestion.
Query Execution
F5 or ALT + X or CTRL + E: Execute all the queries written on query window.
CTRL + F5: Parse the query to check if there are any syntax errors.
 

Profiler
CTRL + ALT + P: Open up SQL Server Profiler. Profiler is generally used for tracing and analysing.
 

System SP
ALT + F1 (Select any stored procedure on query editor and press ALT + F1) : It runs the sp_help system stored procedure.
CTRL + 1: In the same way, it runs the sp_who system stored procedure. It will provide you the details like who created the SP, spid, host name, on which DB the SP was created and so on.
 

Screen
SHIFT + ALT + ENTER: Toggle full screen mode.
I hope you found the post "Ten SQL Server Shortcuts You Must Know" useful and worth reading.
 

What do you think?
If you have any questions or suggestions, please feel free to email us or put your thoughts in the  comments below. We would love to hear from you. If you found this post useful, please share with your friends and help them to learn.

European SQL 2016 Hosting
European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



SQL Server 2016 Hosting - HostForLIFE.eu :: Using Materialized Views Effectively

clock September 18, 2018 09:08 by author Peter

Materialized views have served me well in day-to-day life – both as an application developer and business intelligence developer. In this article, I’ll explain some of the “why’s,” along with a specific example that takes advantage of the SQL MERGE statement to incrementally reconcile changes to a persistent data store, optimized for reads.

Motivations and Mechanics
The link above offers some good detail on why and how we might use materialized views, but I can offer some practical examples, too.

We had a system with an event table; we could determine a lot of detail from events, but querying against them was complex, and ultimately the product of those queries was heavily used. Simply putting those queries into views was not ideal for performance (it was tried!). Instead, we used triggers on the event table to calculate and store the resulting query values. The rule was the only way they were updated was through event changes, and this was an efficient update, based on the row-by-row feed (leveraging indexes). In keeping with the principle of this being a materialized view, we could have lost this persisted table and subsequently fully recover it based on the original view which served as the source for the drip-feed. These persisted values were used extensively by application and report alike, but this was not a “free” process: OLTP transactions bore the cost of maintaining the table, but the benefits far outweighed the cost.

In a BI setting, we had a report that became extremely slow. The reporting tool (out of our control) had constructed some ugly SQL, and this was largely due to the natural complexity and multiple layers of views. The results were correct – but a correct report isn’t useful if it never completes! It was possible to identify a set of three attributes, where if they were included on an additional table, they’d hopefully act as a core filter when included in the report (based on what I expected the report tool and SQL Server would probably do). That set of attributes could be persisted as a read-only materialized view, and the result was exactly as desired: the report became fast with no other changes.

What about alternatives such as indexed views? This is a very real option – but only when the limitations of indexed views don’t become a problem. In both the situations described above, the need for OUTER JOIN’s and subqueries automatically ruled out indexed views. For materialized views, there are really no limitations on the complexity of source queries, and given the target is a physical table, we can use all available tools such as partitioning, COLUMNSTORE indexes, etc.

A consideration when using materialized views is latency. In my first example, using a trigger meant the materialized view was always in-sync with source table updates. In the second example, the refresh of the materialized view could occur as a final step of the process that was used to populate the source tables (effectively ETL). In many other cases, it’s not practical to keep your materialized view in-sync with your source in real-time. If that’s the case, you’ll need to make decisions about how current your view needs to be: is one minute good enough? An hour? A day? At that point, SQL Agent or your scheduler of choice can be used.

I’ve already alluded to a few ways to update a materialized view – one of which is triggers – but when you’re not using triggers, what are your options?

TRUNCATE / INSERT. This tends to be straightforward, but it has limitations including the fact you’ll have some period when your table is empty before it’s refreshed. For cases where you have no good time window options to filter an incremental update or most of your data can change, this approach lets you effectively rebuild your entire table from scratch.

  1. Using sp_rename (or ALTER SCHEMA). This approach is like TRUNCATE/INSERT, but you’re filling a work table, swapping out your “real” materialized view and swapping in the work table to replace it (the swap itself in a transaction). The advantage is the period when the table appears empty can be eliminated. The problem tends to be with blocking: a schema lock is required to do the swap operation, and although the swap itself can be fast, it can be blocked by readers and writers. (With a heavily used table, this can become a problem.)
  2. Using a MERGE statement. This tends to be a good choice, especially if only a small subset of your rows will change during each refresh.
  3. Using SSIS. This approach is particularly suited to BI solutions, most often when combining data from disparate sources. Ultimately, though, with something like materialized view population, the final step can still involve a MERGE statement, called through a SQL Task.


A More Detailed Example

Let’s look at a contrived example that contains a single core event table and a code table:
    CREATE SCHEMA [Source] AUTHORIZATION dbo 
    GO 
    CREATE SCHEMA [Dest] AUTHORIZATION dbo 
    GO 
     
    CREATE TABLE [Source].[EventType] ( 
    EventTypeID tinyint NOT NULL IDENTITY PRIMARY KEY, 
    EventTypeCode varchar(20) NOT NULL, 
    EventTypeDesc varchar(100) NOT NULL); 
     
    INSERT [Source].[EventType] (EventTypeCode, EventTypeDesc) VALUES ('ARRIVE', 'Widget Arrival'); 
    INSERT [Source].[EventType] (EventTypeCode, EventTypeDesc) VALUES ('CAN_ARRIVE', 'Cancel Widget Arrival'); 
    INSERT [Source].[EventType] (EventTypeCode, EventTypeDesc) VALUES ('LEAVE', 'Widget Depart'); 
    INSERT [Source].[EventType] (EventTypeCode, EventTypeDesc) VALUES ('CAN_LEAVE', 'Cancel Widget Depart'); 
     
    CREATE TABLE [Source].[Event] ( 
    WidgetID int NOT NULL, 
    EventTypeID tinyint NOT NULL REFERENCES [Source].[EventType] (EventTypeID), 
    TripID int NOT NULL, 
    EventDate datetime NOT NULL, 
    PRIMARY KEY (WidgetID, EventTypeID, TripID, EventDate)); 
       
    CREATE INDEX IDX_Event_Date ON [Source].[Event] (EventDate, EventTypeID) INCLUDE (WidgetID); 
    CREATE INDEX IDX_Event_Widget ON [Source].[Event] (WidgetID, TripID, EventDate) INCLUDE (EventTypeID); 
    CREATE INDEX IDX_Event_Trip ON [Source].[Event] (TripID, WidgetID); 

The nature of this scenario is we will record the dates of arrival and departure for widgets (key: WidgetID), which can come and go multiple times based on a “trip” (key: TripID). If we incorrectly recorded an arrival or departure, we’ll use a cancellation event that ties back to the widget and trip in question. This fits in with the idea of a log table which only allows insertion. (Truthfully, we could also have done this via “canceled attributes” as well, but let’s assume this is our standard.)

Let’s say our query of interest is this, placing it in a view for convenience,
    CREATE VIEW [Dest].[uv_WidgetLatestState] 
    AS 
    SELECT 
        lw.WidgetID 
        , la.LastTripID 
        , lw.LastEventDate 
        , la.ArrivalDate 
        , (SELECT MAX(de.EventDate) 
            FROM [Source].[Event] de 
            WHERE de.EventTypeID = 3 
            AND de.WidgetID = lw.WidgetID 
            AND de.TripID = la.LastTripID 
            AND NOT EXISTS 
                (SELECT 0 
                FROM [Source].[Event] dc 
                WHERE lw.WidgetID = dc.WidgetID 
                AND la.LastTripID = dc.TripID 
                AND dc.EventTypeID = 4 
                AND dc.EventDate > de.EventDate)) AS DepartureDate 
    FROM 
        (SELECT 
            e.WidgetID 
            , MAX(e.EventDate) AS LastEventDate 
        FROM 
            [Source].[Event] e 
        GROUP BY 
            e.WidgetID) lw 
        LEFT OUTER JOIN 
        (SELECT 
            ae.WidgetID 
            , ae.TripID AS LastTripID 
            , ae.EventDate AS ArrivalDate 
        FROM 
            [Source].[Event] ae 
        WHERE 
            ae.EventTypeID = 1 
        AND ae.EventDate = 
            (SELECT MAX(la.EventDate) 
            FROM [Source].[Event] la 
            WHERE la.EventTypeID = 1 
            AND la.WidgetID = ae.WidgetID 
            AND NOT EXISTS 
                (SELECT 0 
                FROM [Source].[Event] ac 
                WHERE la.WidgetID = ac.WidgetID 
                AND la.TripID = ac.TripID 
                AND ac.EventTypeID = 2 
                AND ac.EventDate > la.EventDate))) AS la ON lw.WidgetID = la.WidgetID 


This tells us the most recent arrival and departure date for a widget, along with the trip identifier for the last trip, based on event dates. (This supports the possibility that an arrival could get cancelled, although our standard will be to only store cases where we have a non-NULL ArrivalDate.) It’s obvious this type of query can be useful to manage the current business process for our hypothetical widgets - our events remain as detail to document history.

Ignoring the fact that we might be okay with performance achieved only by indexing on the source tables, suppose it’s important we persist the results of this query. Our materialized view table could be defined as,
    CREATE TABLE [Dest].[WidgetLatestState] (   
    WidgetID int NOT NULL PRIMARY KEY,   
    LastTripID int NOT NULL,   
    LastEventDate datetime NOT NULL,   
    ArrivalDate datetime NOT NULL,   
    DepartureDate datetime NULL); 
       
    CREATE INDEX IDX_WidgetLatestState_LastTrip ON [Dest].[WidgetLatestState] (LastTripID); 
    CREATE INDEX IDX_WidgetLatestState_Arrival ON [Dest].[WidgetLatestState] (ArrivalDate); 
    CREATE INDEX IDX_WidgetLatestState_Departure ON [Dest].[WidgetLatestState] (DepartureDate); 


In this case, our key for the query would be the WidgetID – all other values are derived details about a given widget. We’ve defined this as the primary key, and we’ve added a couple of additional non-clustered indexes on the target.

Let’s also assume we’re fine with having the target data updated on a schedule. We can do an effective “full refresh” using a single MERGE statement,
    MERGE [Dest].[WidgetLatestState] AS a 
     USING ( 
     SELECT 
       v.[WidgetID] 
        , v.[LastTripID] 
        , v.[LastEventDate] 
        , v.[ArrivalDate] 
        , v.[DepartureDate] 
     FROM 
       [Dest].[uv_WidgetLatestState] v 
     ) AS T 
     ON 
     ( 
       a.[WidgetID] = t.[WidgetID] 
     ) 
    WHEN MATCHED AND t.ArrivalDate IS NOT NULL THEN 
         UPDATE 
          SET LastTripID = t.LastTripID 
        , LastEventDate = t.LastEventDate 
        , ArrivalDate = t.ArrivalDate 
        , DepartureDate = t.DepartureDate 
    WHEN NOT MATCHED BY TARGET AND t.ArrivalDate IS NOT NULL THEN 
          INSERT ( 
            WidgetID 
        , LastTripID 
        , LastEventDate 
        , ArrivalDate 
        , DepartureDate 
          ) VALUES ( 
            t.[WidgetID] 
        , t.[LastTripID] 
        , t.[LastEventDate] 
        , t.[ArrivalDate] 
        , t.[DepartureDate] 
          ) 
    WHEN MATCHED AND t.ArrivalDate IS NULL THEN 
         DELETE; 

My preference in this situation is to deal in three primary objects: the target table (materialized view), a view that expresses the desired query, and a procedure that houses our MERGE (plus adds some logging). With the hard logic contained in the view, the MERGE is largely just boilerplate code and makes it easy to templatize.

I’ve created a test harness available on GitHub that demonstrates the performance of doing a TRUNCATE/INSERT using 2,150,000 source events. (Note: if you clone this repository to try it out, search for the “TODO” and change the file path of the data file to match your local directory for where you extract the Event20180903-1336.dat file.) The result of 4.15 seconds (3 trials, averaged) becomes a baseline on top of which we can add tweaks. The most obvious is to see what the performance is by doing a MERGE with no data changes, post-initial-population. This is 3.40 seconds, and checking @@ROWCOUNT after the operation, we see that it’s updated 196,291 records – which is basically everything in the materialized view. In this case, there was a mild performance gain over TRUNCATE/INSERT and we didn't spend any time with no data in the target table.

The first real tweak is to filter our first WHEN MATCHED clause to check for material changes on non-key columns, as accomplished by,
    WHEN MATCHED  
         AND t.ArrivalDate IS NOT NULL 
         AND ((a.[LastTripID] <> CONVERT(int, t.[LastTripID])) 
              OR (a.[LastEventDate] <> CONVERT(datetime, t.[LastEventDate])) 
              OR (a.[ArrivalDate] <> CONVERT(datetime, t.[ArrivalDate])) 
              OR (a.[DepartureDate] <> CONVERT(datetime, t.[DepartureDate]) OR (a.[DepartureDate] IS NULL AND t.[DepartureDate] IS NOT NULL) OR (a.[DepartureDate] IS NOT NULL AND t.[DepartureDate] IS NULL))) THEN 


This costs something, namely the need to read and compare data, but saves on the need to write back rows where nothing changed. In the test harness, this shows as a net benefit with a result of 1.14 seconds, and @@ROWCOUNT shows zero rows affected.

Another tweak is to use a control date to limit the scope of change checks to a certain timeframe. That timeframe could be fixed (e.g. the last month) or be tied to when the process was the last run. The latter obviously leads to the minimum necessary range but does require some extra infrastructure, including maintaining the control date in a persisted form. For storage of this date, I prefer to use a name/value pair table that can support multiple such needs within a single (BI) database. Doing it this way also requires that we’ve got a way to identify “change dates” in the source data, something that I discuss in another recent C# corner article. (In my example here, the LastEventDate is assumed to be monotonically increasing.)

Using a control date is something I demonstrate in the GitHub script, with an important change being to filter the query of the source view itself,
    USING ( 
    SELECT 
      v.[WidgetID] 
    , v.[LastTripID] 
    , v.[LastEventDate] 
    , v.[ArrivalDate] 
    , v.[DepartureDate] 
    FROM 
      [Dest].[uv_WidgetLatestState] v 
    WHERE 
      v.LastEventDate > @lastprocessed 


The remainder of the query already has the necessary bits to insert, update or delete depending on what the final state of the data is, as returned by the view.

The performance of this final version is 0.46 seconds - 89% better than our baseline! (That includes all the overhead of dealing with loading and storing the control date.) Doing a similar test with some added new events shows similar performance.

Our non-clustered indexes are there to support efficient lookup against the calculated fields (e.g. LastEventDate, DepartureDate). I also tried running a query against the source view as opposed to the materialized view as another benchmark,
    SELECT @temp = COUNT(*) 
    FROM [Dest].[uv_WidgetLatestState] w 
    WHERE w.DepartureDate IS NULL 
    AND w.ArrivalDate IS NOT NULL; 

Unsurprisingly the materialized view performance is 94% better than using the source tables through the “non-materialized” view.

Conclusion
Materialized views can be a life-saver for both applications and BI solutions – but they should follow the design principle of being a read-only, fully-computed product of other data.

I showed how a simple MERGE statement supported the incremental population of a materialized view, with good performance. My example was highly simplistic, and you should evaluate your workload based on what’s required and what’s acceptable, considering performance, complexity, data integrity, etc. Obviously doing this for every query in your system is impractical, so pick-and-choose wisely. I have another blog article that expands on some of what I’ve discussed here and offered some ideas on how to templatize the building of materialized views, significantly cutting down on the coding effort.

European SQL 2016 Hosting
European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.

 

 



About HostForLIFE.eu

HostForLIFE.eu is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.

We have offered the latest Windows 2016 Hosting, ASP.NET Core 2.2.1 Hosting, ASP.NET MVC 6 Hosting and SQL 2017 Hosting.


Tag cloud

Sign in