Tuesday, June 20, 2017


Overview of SQL Server index


In this article I am going to discuss about SQL Server index. At first I will give you a book example, we all are reading books. So, the index page of a book, which contains all the information about book’s chapters and their page numbers are enough information to find out a page or a chapter in a book. Similarly, In SQL Server indexes are the set of pages that arranged in a tree structure (B-Tree), which is hierarchical in nature. Basically two types of indexes are available in SQL Server.
  • Clustered index
  • Non-clustered index
These two cluster and noncluster indexes and their working procedure I will discuss after describing the basic structure of index in SQL Server.

Basic Structure of Index in SQL Server

The SQL Server creates indexes on columns in a table or views and provides a rapid way to access the data according to the values. Indexes are helpful in enhancing the overall performance of SQL Server.
There are three filtering levels, which helps in faster access of the data.
  • Root Level
  • Intermediate Level
  • Leaf Level
DATABASEINDEXES2.gif
Root Level: This is the highest level of the index. If the table is large and the search is performed against an indexed column, the query engine starts finding from the root node and the root node navigates down to the intermediate nodes and intermediate node navigates down through leaf node the search query is not found. There is only a single root page in an index.
Intermediate Level: This is the middle level of the index. The intermediate level comes in between Root Level and Leaf Level. If the table is too small then there is no intermediate level.
Leaf level: This is the last level of the index. If the search not found between Root Level and Intermediate Level, then the query engine navigates down to Leaf Level.
So, these three indexing level sort the data pages and then helps the query engine to find the searched result quickly and enhance the performance of SQL Server.
Now the question is that, how these indexing levels work on cluster and noncluster index?

What is Cluster and Noncluster Index?

Clustered Index

In a clustered index the data rows are stored at leaf leaf level of the index and the indexed values of a clustered index are sorted in either ascending or descending order. It is possible that, there can be one clustered index available on a view or table. The data is sorted in a table if there is clustered index defined on that table and that table is known as clustered table. A table that doesn’t have any clustered index, is called as heap.

Non-Clustered Index?


The B-tree works same in nonclustered indexes as it works in clustered indexes, but the differences are that the data pages are same, but the leaf pages are different and each row in a table has a one key-pointer that is stored by leaf level. The page pointers and index keys are stored by the leaf-level pages, And also a pointer of the row offset table on the data pages. By merging page pointer and row offset number is also called the row ID. The index keys and page pointers of other index pages are stored by root and intermediate levels. With the same size of keys, The nonclustered indexes need more space than clustered indexes.

Differences between Clustered and Non-Clustered Indexes:


Clustered Index 
  • A Table can have ONLY 1 Clustered Index.
  • A Clustered Index always has Index Id of 0.
  • A Primary Key constraint creates a Clustered Index by default.
  • A Primary Key constraint can also be enforced by Nonclustered Index, You can specify the index type while creating Primary Key.
  • If the table does not have Clustered Index it is referred to as a "Heap".
  • The leaf node of a Clustered Index contains data pages of the table on which it is created.
  • Clustered Index enforces a logical order on the rows. Rows are ordered based on Clustering Key.
Nonclustered Index 
  • Prior to SQL Server 2008 only 249 Nonclustered Indexes can be created. With SQL Server 2008 and above 999 Nonclustered Indexes can be created.
  • Nonclustered Indexes have Index Id > 0.
  • A Unique Key constraint created a Nonclustered Index by default.
  • A Unique Key constraint can also be enforced by Clustered Index, You can specify the index type while creating Unique Key
  • Nonclustered Index does not order actual data, It only orders columns present in the Nonclustered Index based on Index Key specified at the time of creation of Nonclustered Index.
  • A table may not have any Nonclustered Indexes.
  • The leaf nodes of a Nonclustered Index consists of Index pages which contain Clustering Key or RID to locate Data Row.
  • When Clustered Index is not present leaf node points to Physical Location of the row this is referred to as RID. When a Clustered Index is present this points to Clustering Key (Key column on which Clustered Index is created).

Cluster Index and Non-Clustered Index - Explained

Read More

Monday, June 19, 2017

Did you know that mainstream support for SQL 2000 ended in April of 2008? Here is a list of the SQL versions and the relevant release and support end dates:


SQL Server VersionRelease DateEnd of Mainstream SupportEnd of Extended SupportLink
SQL 7Mar 01 1999Dec 31 2005Jan 11 2011Support Lifecycle
SQL 2000Nov 30 2000Apr 8 2008Apr 9 2013Support Lifecycle
SQL 2005Jan 14 2006Apr 12 2011Apr 12 2016Support Lifecycle
SQL 2008Nov 6 2008Jan 14 2014Jan 08 2019Support Lifecycle
SQL 2008 R2Jul 20 2010Jan 14 2014Jan 08 2019Support Lifecycle
SQL 2012May 20 2012Jul 11 2017Jul 12 2022Support Lifecycle
SQL 2014June 5 2014Jul 9 2019Jul 9 2024Support Lifecycle
SQL 2016June 1 2016Oct 12 2021Oct 13 2026Support Lifecycle
The Support Lifecycle links will have more detailed information about Service Packs and support guidelines for the specific versions.

When does my SQL Server support end?

Read More

Working with SQL Server File Tables 


Did you ever think that your SQL server can work as a file server? The odds are that you didn’t – neither did I until I tried a FileTable feature first introduced in SQL Server 2012. The FileTable feature is the next step in the FILESTREAM technology that allows you to store files and folders in the special tables but access them using traditional Windows SMB protocol – users can create/read/modify/delete files from a generic file share without even being aware of the underlying SQL commands. In other words, FileTables let us use SQL tables for non-transactional access.
In my opinion, one of the greatest benefits of FileTables feature is the storing of file attributes (such as Last-WriteTimeLast_AccessTime, etc.) that allows administrators to audit file access operations using the corresponding columns in the FileTables. In this article I’d like to show you how SQL Server 2012-2016 can be used for the file storage and what auditing mechanisms may be leveraged for files and folders residing in the SQL file shares.  Some prerequisites must be met before File Tables can be created in a database and we’ll go over all the steps required to prepare for File Tables, then create several tables and see how we can work with them.
Let’s start from enabling the FILESTREAM for the SQL 2012 instance and creating a new FILESTREAM database:
I Enable FILESTREAM at the Windows level
  1. Open SQL Configuration manager:
    02
  2. Make sure the following checkboxes are selected:
    03
II Enable FILESTREAM at the SQL Instance level:
  1. In SQL Server Management Studio, click New Query to display the Query Editor.
  2. In Query Editor, enter the following Transact-SQL code:
    EXEC sp_configure filestream_access_level, 2
    RECONFIGURE04
III Provide a FILESTREAM Filegroup at the Database Level
Before we can create FileTables in a database, the database must have a FILESTREAM filegroup. For more information about this prerequisite, please see Create a FILESTREAM-Enabled Database.
Since I’m going to create a new database I will first create a folder to contain FileTables:
01
and then define a Filestream filegroup in this code:
CREATE DATABASE FILESERVER
ON
PRIMARY (NAME = FS,
FILENAME = ‘c:\FILESERVER\FSdat.mdf’),
FILEGROUP FileStreamFS CONTAINS FILESTREAM(NAME = FSgr,
   FILENAME = ‘c:\FILESERVER\fs1’)
LOG ON (NAME = FSlog,   FILENAME = ‘c:\ FILESERVER \FSlog.ldf’)
GO
Attention! As MS says: “For a FILESTREAM filegroup, FILENAME refers to a path. The path up to the last folder must exist, and the last folder must not exist.” In the preceeding code, c:\FILESERVER must exist, but fs1 must NOT at the time you execute the CREATE DATABASE statement.
05
10
The Filegroups database property page now displays the FileStreamFS filestream for the FILESERVER database:
07
IV Enable Non-Transactional Access at the Database Level
Once we’ve got the database created the last step in preparing it for FileTables is to enbable non-transactional access at the database level.
FileTables let Windows applications obtain a Windows file handle to FILESTREAM data without requiring a transaction. To allow this non-transactional access to files stored in SQL Server, you have to specify the desired level of non-transactional access at the database level for each database that will contain FileTables. If we execute the following code –
SELECT DB_NAME(database_id), non_transacted_access, non_transacted_access_desc 
   FROM sys.database_filestream_options;
GO
…we’ll see that no databases have non-transactional access enabled:
08
To enable non-transactional access to files at the database level (for the FILESERVER database in this case) one more option must be specified – a directory for FileTables: it is the directory I’ve created in the begining of the article – C:\FILESERVER, but the directory name should be typed without the drive letter and the symbol “\”:
ALTER DATABASE FILESERVER
    SET FILESTREAM ( NON_TRANSACTED_ACCESS = FULL, DIRECTORY_NAME = N’FILESERVER’ )
GO
09
In the FileTable folder hierarchy, this database-level directory becomes the child of the share name specified for FILESTREAM at the instance level, and the parent of the FileTab les created in the database” – it means FILESERVER will be the subfolder of MSSQLSERVER share as I havn’t changed it in step I-2. For more information, please see Work with Directories and Paths in FileTables
Executing this code again will show the non-transactional access has been enabled successfully:
SELECT DB_NAME(database_id), non_transacted_access, non_transacted_access_desc
   FROM sys.database_filestream_options;
GO
09-1
The following code displays the directory name for the FILESERVER databse:
Select DB_NAME ( database_id), direcory_name
  FROM sys.database_filestream_options;
GO
11
Here’s the “SQL” file share that users can now use for storing their files and folders:10-1110-12
If I had renamed the default MSSQLSERVER share into something like SHARE1 in step I-2 there would have been no indication of any SQL Server involved – from the user’s perspective it would be just an ordinary file share.
All prerequisites for creating FileTables are fulfilled now and we can proceed to creating FileTables.
I will create the four FileTables:
  • USERS
  • Documents
  • Confidential
  • HR
use FILESERVER
GO
CREATE TABLE USERS AS FileTable;
GO
use FILESERVER
GO
CREATE TABLE Documents AS FileTable;
GO
use FILESERVER
GO
CREATE TABLE Confidential AS FileTable;
GO
use FILESERVER
GO
CREATE TABLE HR AS FileTable;
GO
14
16-1
The corresponding folders are created in the MSSQLSERVER\FILESERVER share:16
Then we can create several personal user folders in the USERS folder:18
Here’s the corresponding new rows in the USERS file table:
2121-1
As you can see each row corresponds  to a file (is_directory = 0) or a folder (is_directory = 1) in the file share.
What permissions should users have to be able to create  files/folders in the “SQL” file share? First of all, we must create a server login (at least with public role) and a database user login (public + other permissions or roles) for each user  – otherwise he/she won’t even be able to access the share – for example I tried to access \\sql1\mssqlserver share as User2 which has neither sql server login no db login:
21-3
For the purpose of this test I will create two sql server logins that will map to the corresponding database users – User1 and User2:
21-16
and make them members of the db_datareader role:21-1221-13
Now User2 can browse the share:
21-621-7
..but not to create new file/folders (i.e.  insert new rows) or modify them (i.e. update the table):
21-821-921-10
Consider the following situation: User1 should be able to insert and update information in Confidential file table, User2 should have only read access. All insert/update operations on the Confidential file table (or creating/modifying file/folders from the file share’s perspective) must be audited.
Since User2 already has read access I will grant User1 the nesessary permissions:
30
Next I should create two new tables (the ordinary tables, not File Tables!) that will contain the auditing information, for example:
1) AuditCONFIDENTIALinsert table
use FILESERVER
CREATE TABLE AuditCONFIDENTIALinsert
(
ID int IDENTITY NOT NULL,
InsertTime    DateTime,
ServerLogin nvarchar(50),
DBuser nvarchar(50),
FileName nvarchar(50),
CONSTRAINT PKAuditConfidentialInsert
PRIMARY KEY (ID)
)
GO
191
2) AuditCONFIDENTIALupdate table
use FILESERVER
CREATE TABLE AuditCONFIDENTIALupdate
(
ID int IDENTITY NOT NULL,
UpdateTime    DateTime,
ServerLogin nvarchar(50),
DBuser nvarchar(50),
FileName nvarchar(50),
CONSTRAINT PKAuditConfidentialUpdate
PRIMARY KEY (ID)
)
GO
192
The tables are created:
193
To fulfill the auditing requirements I will add the two triggers to Confidential table:
1) Trigger for the insert operations
use FILESERVER
go
IF OBJECT_ID (‘CONFIDENTIALinsertTR’,’tr’) IS NOT NULL
DROP TRIGGER ‘CONFIDENTIALinsertTR’
go
CREATE TRIGGER ‘CONFIDENTIALinsertTR’
ON dbo.CONFIDENTIAL
AFTER INSERT
NOT FOR REPLICATION
AS
BEGIN
   INSERT INTO dbo.AuditCONFIDENTIALinsert (InsertTime, ServerLogin, DBuser, FileName)
VALUES ((SELECT Top 1 Creation_Time FROM dbo.Confidential), SUSER_SNAME(), 
USER_NAME(), (SELECT Top 1 name FROM dbo.Confidential))
END
GO
194

2)  Trigger for the update operations
use FILESERVER
go
IF OBJECT_ID (‘CONFIDENTIALupdateTR’,’tr’) IS NOT NULL
DROP TRIGGER CONFIDENTIALupdateTR
go
CREATE TRIGGER CONFIDENTIALupdateTR
ON dbo.CONFIDENTIAL
AFTER UPDATE
NOT FOR REPLICATION
AS
BEGIN
INSERT INTO dbo.AuditCONFIDENTIALupdate (UpdateTime, ServerLogin, DBuser, FileName)
VALUES ((SELECT Top 1 Creation_Time FROM dbo.Confidential), SUSER_SNAME(),
USER_NAME(), (SELECT Top 1 name FROM dbo.Confidential))
END
GO
195
These triggers add a new row containing the time of the insert/update operation, sql server login and database user login under which this operation has been performed and the file which has been inserted/updated.
Now it’s time to see how it works:
1) I will copy the file SecretReport.xlsx to the \\FILESERVER\Confidential share – in other words we’ll see how the auditing of the insert operation works:
205
This code will show the content of the Confidential file table:
use FILESERVER
go
select name, file_type, cached_file_size, is_directory, creation_time, last_write_time, 
last_access_time from Confidential
order by creation_time desc
go
206
This one will show the content of the AuditConfidentialInsert  table:
use FILESERVER
go
SELECT *  FROM AuditCONFIDENTIALinsert
order by InsertTime desc
go
207-Audit
This table shows what has been created (“inserted”), when and by whom.

2)  This time we’ll see how the auditing of the update operation works – I will open SecretReport.xlsx, make some changes and save the file:
253-TestUpdateFile254-TestUpdateFile
Here’s the content of the AuditConfidentialUpdate table:
use FILESERVER
go
SELECT * FROM AuditCONFIDENTIALupdate
order by UpdateTime desc
go
255
I’d like to draw your attention to the following facts:
1) working with the document (“updating”) produces more the one row in the audit table even if you click “Save” button only once,
2) the updating takes place for the temporary file ~$___, not for the original file name
3) for the reason unknown to me only the first update event is registered under the name of the current user – Testcompany\Administrator – all subsequent ones are registered under the sa account and the most interesting fact:
4) some time after I took the previous screenshot  (minutes or hours later) the same code produces another output:
260
…and this really can become an issue when auditing file modifications because 1) it was only User1 who was changing the SecretReport.xlsx file at 2016-01-12 05:14:34.880 and 2) if Administrator had really changed this document at the exactly same time as User1 why whould SQL Server have not  added the corresponding row to the table at 2016-01-12 05:14:34.880 and have done it only some time later?
I hope this article provided some insight into what the FileTables feature is, how it can be used and what issues you may encounter working with them.

Working with SQL Server File Tables

Read More