Wednesday, May 20, 2015

Few of the SQL Server Storage Definitions

Page - Basic Unit of SQL Server Storage - 8KB

Extent: 8 Consecutive pages - 64KB

Extent Types:

  • Uniform Extent: If all the 8 Pages of the extent belong to the same IAM(Object)
  • Mixed Extent: If the pages in the extent belong to more than 1 IAM(Object). So a maximum of 8 different IAMs can share an extent.

When is a page allocated from a 
  • Mixed Extent: If the table size is very small then the pages are allocated from a Mixed Extent. First 8 pages of the table are stored in Mixed Extents.
  • Uniform Extent: If the table size grows beyond 8 Pages then a Uniform extent is allocated to the new pages and the free pages in the Uniform extent are reserved for that particular IAM.

GAM Page: Global Allocation Map: This page keeps information of various Extents in the system and signifies whether it is in use extent(1) or an Unallocated extent(0)
A single GAM page can keep track of 64,000 Extents = Data of almost 8GB. So a single GAM page is used to keep track of 8GB worth of Data.

SGAM Page: Shared GAM: This keeps track of whether the Mixed Extent contains free pages or not.
  • if SGAM bit = 1 then the particular extent is a mixed extent and has pages available to be used up
  • if SGAM bit = 0 then the particular extent is either Uniform Extent or a mixed extent with no free pages

Page Structure:
  • First 96 Bytes is the Header of the Page and gives a lot of information about the type of page and other metadata
  • Then there are Data record
  • Then there are Slots which gives the information of various record's offsets within that particular page.
More information about the storage could be found in the blogs written by Paul Randal: http://www.sqlskills.com/blogs/paul/inside-the-storage-engine-gam-sgam-pfs-and-other-allocation-maps/

Wednesday, May 6, 2015

Controlled IO for Heavy Processes using SQL Server 2014 Resource Governor

You would have frequently experienced that whenever few queries run, they tend to slow down the whole server and hence have an impact on the business as the other applications do not respond in a timely manner. This hugely happens because there could be some type of queries which need a lot of IO operations to happen for communicating with the disks and hence that puts a huge constraint on the disk which results in ever increasing IO queues. There are other queries which go into the wait state as they are waiting for the IO sub-system to complete the request of the IO intensive queries which had started before.

Microsoft had introduced a new feature called "Resource Governor" since SQL Server 2008 which helped to control the utilization of specific resources (CPU and Memory) by different types of query groups. This feature is made available in only the Enterprise, Developer, and Evaluation editions of SQL Server. Now, as part of SQL Server 2014, Microsoft has enhanced this feature and added another type of resource which could be well controlled and that's the IO sub system. This is a major functionality released by Microsoft and its usage is going to be big as administrators have always wanted something to control the amount of IOs that could be taken by certain types of queries so that they do not bog down the whole server.

Enabling and Implementing IO Utilization using Resource Governor:

1.) Enable Resource Governor by right clicking on “Resource Governor” from Management folder of SSMS Object Explorer and selecting “Enable”

2.) Create a resource Pool for IO which consists of MIN and MAX IOPS for it
 
USE master;
go
CREATE resource pool restrictediopool 
WITH ( max_iops_per_volume = 30, min_iops_per_volume = 1 ); 
go

3.) Create a resource Group which could be directed to the above resource pool and hence have a controlled IO utilization. By default there is a “Default” group which contains all the types of queries and an “Internal” group which is used by SQL Server for its internal processes.

USE master; 
go
CREATE workload GROUP restrictediogroup using restrictediopool; 
go

4.) Create a Resource classifier function to group the queries into Resource Groups. This classifier function will always be called whenever a query enters the system and it would be classified into a particular resource group. So this feature does have a bit of negative performance overhead with it. In this example I check that every query that comes into the system under the Login of “Backups” will go into the newly created group. I will make sure that every resource intensive query which I want to govern will be forced to run under this particular login:

USE master;

go

CREATE FUNCTION dbo.Restrictediousage()
returns SYSNAME
WITH schemabinding
AS
  BEGIN
      DECLARE @GroupName SYSNAME

      IF Suser_name() = 'Backups'
        BEGIN
            SET @GroupName = 'RestrictedIOGroup'
        END
      ELSE
        BEGIN
            SET @GroupName = 'default'
        END

      RETURN @GroupName;
  END

go 


5.) Once the above components are created, we need to map the Resource Governor to the above created Classification function:
USE master;
GO

ALTER resource governor WITH (classifier_function = dbo.restrictediousage);
ALTER resource governor RECONFIGURE; 

Demo to check the IOPS counter when we run a resource intensive operation

I will run a consistency check operation of the AdventureWorks database and see how many IOPS are getting generated for this operation as I will be running this under the login “Backups” and hence it would automatically be sent to the RestrictedIOGroup which in turn would be directed to the RestrictedIOPool
DBCC CHECKDB(AdventureWorks2012)

Add the following counters from the Perfmon window to view the specific Counters of MSSQL$SQL2014_Instance_Name:Resource Pool Stats Object:

1.) Disk Read IO/Sec - Default Instance
2.) Disk Read IO/Sec - RestrictedIOpool Instance


clip_image002

Here you can clearly see that the max IOPS is always around 30 as we had set initially to be the max resource for this particular pool. In this way any query under this pool would not take the complete IO for its request and hence other queries would be able to process simultaneously:



clip_image004

Now let us increase the MAX IOPS for this Resource pool and see how it behaves:

ALTER resource pool restrictediopool WITH (max_iops_per_volume=300);
ALTER resource governor RECONFIGURE;go 

Here we can now see that the IOPS is going well beyond 30IOPS to as much as required to satisfy the request without any upper bound:

clip_image006

This is a very valuable feature released by Microsoft which should help the administrators to well control their IO subsystems between different type of user groups or other type of groups.

Reducing the Page Splits – The Hidden IO intensive operation

Existing system: We generally have a system in place which checks the fragmentation levels of various indexes and accordingly reorganizes or rebuilds them. I have noticed that there are various tables which get rebuilt everyday due to their fragmentation being greater than 40%.
Assumption: I would assume that since the Index pages are getting so highly fragmented on a very regular basis, throughout the day it might be happening that several pages must be getting split to accommodate new data. This page split operation is a very resource intensive operation and hence must be a constant hidden reason of heavy server load. The page split might be happening because we keep the index pages fully filled. This is determined by the fill factor which is applied at the server level and if there is no explicitly defined fill-factor at the index level then server settings get used by default. Server setting default Fill-factor is set to 100% so all the indexes must be getting filled completely.
Investigation: Once the above assumption is confirmed then we can try changing the fill-factor of various indexes to about 80 or 90% to start with so that there is enough space in the pages to accommodate the new data and hence page splits would get drastically reduced. We could then analyze the page splitting for next 3 to 4 months then again increase the fill factor based on our further analysis.
Few important points:
1.) If the clustered index is on Identity_key then there would not be any page splits as the data is entered in orderly fashion and hence there would not be any data to be inserted in between which would cause page splits. Hence the above theory would be applicable on any other type of indexes which is not incremental in nature (It could be Clustered or Non-Clustered Indexes)
2.) Be cautious when you add the fill factor to an existing index as I would believe that the size of the table would increase in accordance with the fill factor. So for e.g., if there are about 10K pages and if we add a fill –factor of 20% then the new index size would become about 12K.
3.) Another point to investigate is that since the number of pages would increase by adding the fill-factor then definitely the queries that might be accessing these tables would have to access more number of pages and hence there would be an increase in IO. So we would need to weigh this against the page split operations that would happen if pages are 100% filled up and see which one would be better option. I would believe that Page-splits would need to be drastically reduced as definitely it is a very heavy operation and hence needs to be reduced greatly