FILESTREAM Example

  • 9:36 AM
  • 0 comments

FILESTREAM Feature

FILESTREAM was introduced in SQL Server 2008 for the storage and management of unstructured data. The FILESTREAM feature allows storing BLOB data (example: word documents, image files, music and videos etc) in the NT file system and ensures transactional consistency between the unstructured data stored in the NT file system and the structured data stored in the table.
Storing BLOB data in NT file system, allows SQL Server to take advantage of the NTFS I/O streaming capabilities and at the same time, maintain transactional consistency of the data. FILESTREAM uses NT System Cache for caching file data. This minimizes the effect that FILESTREAM data might have on the Database Engine performance. When accessing FILESTREAM data through the streaming API, SQL Server buffer pool is not used and hence it does not reduce the amount of memory available for Database Engine query processing.
The term ‘FILESTREAM data type’ or ‘FILESTREAM column’ is very commonly used and it gives an indication that the FILESTREAM feature is implemented as a data type. This is not true. FILESTREAM is not a data type; instead, it is an attribute that can be assigned to a VARBINARY (MAX) column. When the FILESTREAM attribute of a VARBINARY (MAX) column is set, it becomes a ‘FILESTREAM enabled’ column. Any data that you store in such columns will be stored in the NT file system as a disk files and a pointer to the disk file is stored in the table.  A VARBINARY (MAX) column with FILESTREAM attribute is not restricted to the 2 GB limit SQL Server imposes on Large Value Types. The size of the file is limited by the size of the disk volume only.
When the FILESTREAM attribute is set, SQL Server stores the BLOB data in the NT file system and keeps a pointer the file, in the table. SQL Server ensures transactional consistency between the FILESTREAM data stored in the NT file system and the structured data stored in the tables.

Installing and Configuring FILESTREAM

The default installation of SQL Server 2008 disables FILESTREAM feature. It is quite easy to enable the FILESTREAM feature as part of a new SQL Server 2008 installation. If the SQL Server 2008 instance is already installed without FILESTREAM feature, it can still be enabled following the steps explained later in this section.

Enabling FILESTREAM as part of installation

The easiest way to enable FILESTREAM feature is to do so as part of the installation process. You will see a new tab labeled “FILESTREAM” on the “Database Engine Configuration” page of the installation wizard. This tab allows you to specify the FILESTREAM configuration options that you wish to enable on your new SQL Server Instance.
FILESTREAM feature may be enabled with three different levels of access to the FILESTREAM data, namely: 
  1. Enable  FILESTREAM for Transact-SQL access
  2. Enable FILESTREAM for file I/O streaming access
  3. Allow remote clients to have streaming access to FILESTREAM data

Enabling FILESTREAM during an Unattended installation

If you are installing SQL Server 2008 in ‘Unattended mode’, you can use /FILESTREAMLEVEL and /FILESTREAMSHARENAME configuration options to configure FILESTREAM features. For more information about installing SQL Server 2008 in ‘Unattended mode’, see How to: Install SQL Server 2008 from the Command Prompt

Enabling FILESTREAM after installation

Enabling FILESTREAM feature on a SQL Server 2008 Instance, installed without FILESTREAM features, would require a little more work. To enable FILESTREAM feature, go to ‘SQL Server configuration Manager’ and right click on instance of SQL Server Service and select ‘properties’. The property page will show an additional tab labeled ‘FILESTREAM’, which looks exactly the same as the FILESTREAM configuration page shown as part of the installation wizard. The FILESTREAM feature can be enabled by setting the appropriate options on this page.
If you wish to automate this process, you could try running the VBScript given at How to enable FILESTREAM from the command line. to do it.
Once FILESTREAM feature is enabled, the next step is to configure FILESTREAM Access Level. This is an additional step that is required only if you configure FILESTREAM after the installation of SQL Server. Open SQL Server Management Studio and open the properties of the SQL Server 2008 instance. Select the ‘Advanced’ tab and change the ‘FILESTREAM Access Level’ to ‘Transact-SQL Access enabled’ or ‘Full access enabled’.
Alternatively, ‘FILESTREAM Access Level’ can be configured using TSQL by running the following statement.
EXEC sp_configure filestream_access_level, 2
GO
RECONFIGURE
GO
The last parameter to sp_configure specifies the Access Level, where 0 means ‘Disabled’, 1 means ‘Transact-SQL Access Enabled’ and 2 means ‘Full Access Enabled’

Using FILESTREAM

Once you have an instance of SQL server 2008 with FILESTREAM feature enabled, you are ready to go ahead and create FILESTREAM enabled databases. When you create a FILESTREAM enabled database, the FILESTREAM data should be placed in a separate file group having a special attribute that indicates that the file group contains FILESTREAM data.
SQL Server allows FILESTREAM file groups to be on compressed volumes. If you are using FILESTREAM on a clustering environment, FILESTREAM file groups must be on shared disk resources.

Creating a FILESTREAM enabled database

A basic FILESTREAM enabled database should have the following storage components:
  • MDF File
  • LOG File
  • FILESTREAM Data Container
MDF File and LOG files are familiar to us and do not need any explanation. However, FILESTREAM Data Container may be new to some. FILESTREAM Data Container is a special folder in the NT File System where SQL Server will store FILESTREAM data as disk files. We will examine FILESTREAM Data container a little later in this article.
Here is the script that creates a FILESTREAM enabled database.
CREATE DATABASE NorthPole
ON
PRIMARY (
      NAME = NorthPoleDB,
      FILENAME = 'C:\Temp\NP\NorthPoleDB.mdf'
), FILEGROUP NorthPoleFS CONTAINS FILESTREAM(
      NAME = NorthPoleFS,
    FILENAME = 'C:\Temp\NP\NorthPoleFS')
LOG ON (                        
      NAME = NorthPoleLOG,
    FILENAME = 'C:\Temp\NP\NorthPoleLOG.ldf')
GO
Note the portion highlighted in yellow. That is the part that adds the FILESTREAM Data Container to the database. One important point to note here is that the last sub directory in the FILESTREAM Data Container path should not already exist. In the above example,  “c:\temp\np” should exist, however, the root level folder “NorthPoleFS” should not exist in “c:\temp\np” at the time of creating the database. SQL Server will create the root folder and configure it. If the folder already exists, the operation will fail with an error.

Understanding FILESTREAM Data Container

The root folder where FILESTREAM data of a database is stored is called FILESTREAM Data ContainerWhen you create a database with FILESTREAM feature enabled, the FILESTREAM Data Container will be created with the path you specify in your CREATE statement. The root directory in the FILENAME parameter will be configured as FILESTREAM Data Container. It is important that this folder should not exist at the time of creating the database. SQL Server will create this folder and will configure it as FILESTREAM Data Container.

Reviewing the FILESTREAM Data Container

Let us go ahead and take a look at the FILESTREAM data container. You may not do this every time you create a FILESTREAM enabled database or table. However, for the purpose of understanding the FILESTREAM Data Container structure, let us take a look at how the folder looks like.
When we created the database, we had specified the path to the location that we wanted to have configured as the FILESTREAM Data Container for our database. If you have not modified the location I specified in the code snippet, it will be “C:\temp\NP\NorthPoleFS”.  Open windows explorer and navigate to the folder you specified as FILESTREAM Data Container while creating the database.
You will see a folder named “$FSLOG” and a file “filestream.hdr” there. The folder “$FSLOG” is the FILESTREAM equivalent of the Database Transaction Log file. “filestream.hdr” contains important metadata information used by SQL Server internally. Make sure that you do not tamper with this file.

Creating a table with FILESTREAM columns

Once we have a FILESTREAM enabled database, we are ready to go ahead and create tables having FILESTREAM columns. A FILESTREAM column is a VARBINARY(MAX) column that has the FILESTREAM attribute enabled. Remember, FILESTREAM  is not a new DATA TYPE, it is a new attribute added to a VARBINARY(MAX) column.
CREATE TABLE [dbo].[Items](
   [ItemID] UNIQUEIDENTIFIER ROWGUIDCOL NOT NULL UNIQUE,
   [ItemNumber] VARCHAR(20),
   [ItemDescription] VARCHAR(50),
   [ItemImage] VARBINARY(MAX) FILESTREAM NULL
)
Note that every table that has a FILESTREAM column should have a UNIQUEIDENTIFIER column with ROWGUIDCOLand UNIQUE attributes.

Reviewing the FILESTREAM Data Container Changes

Let us go back to the FILESTREAM Data Container folder and see if we can detect any change since the last time we visited it. This time you will notice that a new folder is created in the root folder with a GUID value as its name. SQL Server will create a folder for each table that uses FILESTREAM enabled columns. Within this folder, a sub folder will be created for each FILESTREAM enabled column in the table.

Inserting FILESTREAM data

We have got the table created. Let us now add a couple of rows to the table we created. As you must have figured out by looking at the column names, this table is intended for storing product information.  Along with the item information (ItemNumber and ItemDescription) we will also store an image of the item. The image will be stored in the FILESTREAM enabled column.
Let us add ‘Microsoft Mouse’ as the first item to this table. I have a cute image of a Microsoft Mouse on my hard disk and let us load the content of the image file and store that to the ‘ItemImage’ column.
 For the purpose of this example, let us use OPENROWSET(BULK..) to load the content of the image file (jpg) from the disk to a VARBINARY(MAX) variable. Once the content of the image is loaded to the variable, we can store it to the FILESTREAM enabled column. Let us see the code that does it.
-- Declare a variable to store the image data
DECLARE @img AS VARBINARY(MAX)

-- Load the image data
SELECT @img = CAST(bulkcolumn AS VARBINARY(MAX))
      FROM OPENROWSET(
            BULK
            'C:\temp\MicrosoftMouse.jpg',
            SINGLE_BLOB ) AS x
           
-- Insert the data to the table          
INSERT INTO Items (ItemID, ItemNumber, ItemDescription, ItemImage)
SELECT NEWID(), 'MS1001','Microsoft Mouse', @img
Before you run the above code, make sure that you change the name of the file (“c:\temp\MicrosoftMoust.jpg”) to a valid image file name that exists in your hard disk.

Accessing FILESTREAM Data using TSQL

Even though the actual data of a FILESTREAM enabled column is stored in the NT File System, it will be completely transparent to the TSQL code. You can access the data in the FILESTREAM enabled column just like any other column of the given table. The following example queries all the information from the “Items” table which returns the FILESTREAM data too.
SELECT * FROM items
/*
ItemID           ItemNumber ItemDescription ItemImage
---------------- ---------- --------------- ------------
EE9A1CB8-3514... MS1001     Microsoft Mouse 0xFFD8FFE...
*/
Usually the TSQL code (stored procedure) does not really do any manipulation of the FILESTREAM data except for saving and retrieving it. It will be the client applications that actually use the FILESTREAM data. Let us look at a VB.NET client application that reads the image data that we just stored into the FILESTREAM data store and displays it in an image control. (To keep the source code listing minimal, I have not added any error handling code)
'Create a connection to the database
Dim ConStr As String
ConStr = "Data Source=JACOBXPS\katmaifs;Initial Catalog=NorthPole" & _
         ";Integrated Security=True"
Dim con As New SqlConnection(ConStr)
con.Open()

'Retrieve the FilePath() of the image file
Dim sqlCommand As New SqlCommand()
sqlCommand.Connection = con
sqlCommand.CommandText = "SELECT ItemImage FROM items " + _
                         "WHERE ItemNumber = 'MS1001'"
Dim buffer As Byte() = sqlCommand.ExecuteScalar()

'Bind the image data to an image control
Dim ms As MemoryStream = New MemoryStream(buffer)
Dim bmp As Bitmap = New Bitmap(ms)
ItemImage.Image = bmp

'Cleanup
con.Close()

Accessing FILESTREAM data with Managed API

Accessing FILESTREAM data using Win32 Streaming has a number of advantages over accessing it using TSQL. When accessing FILESTREAM data using TSQL, SQL Server reads the content of the FILESTREAM data file and serves it to the client. SQL Server memory is used for reading the content of the data file. Accessing FILESTREAM data using Win32 Streaming does not use SQL Server memory. In addition it allows the application to take advantage of the Streaming capabilities of the NT File System.
Though accessing FILESTREAM data using Win32 Streaming has a number of advantages, it is a bit complicated to use, compared to the syntax needed to access it from TSQL. Before a client application can access the FILESTREAM data, it needs to find out the logical path that uniquely identifies the given file in the FILESTREAM data store. This can be achieved by using the “PathName” method of a FILESTREAM column. Note that the PathName()function is Case Sensitive. The following example shows how to retrieve the PathName() associated with the FILESTREAM data of a column.
SELECT
      ItemNumber,
      ItemImage.PathName() AS FilePath
FROM Items
/*
ItemNumber FilePath
---------- ----------------------------------------------
MS1001     \\JACOBXPS\KATMAIFS\v1\NorthPole\dbo\Items\
           ItemImage\EE9A1CB8-3514-4115-8227-4E8F080E22E0
*/
The next step is to begin a transaction and obtain a transaction context. A client application can start a transaction by calling the ‘BeginTransaction’ method of the SqlConnection object. After starting a transaction, the transaction context can be obtained by running the following query.
SELECT GET_FILESTREAM_TRANSACTION_CONTEXT() AS TransactionContext
/*
TransactionContext
-----------------------------------
0xCB261797D1878D4A9F9562660124BBD8
*/
Once the transaction context to the FILESTREAM data file is obtained, the file can be accessed using the‘SqlFileStream’ class. Here is the complete listing of a basic VB.NET application that reads FILESTREAM data using the Managed API and displays the picture on an Image Control.  (To keep the code listing minimal, I have not added any error handling code)
‘Create a connection to the database
Dim ConStr As String
ConStr = "Data Source=JACOBXPS\katmaifs;Initial Catalog=NorthPole" & _
         ";Integrated Security=True"
Dim con As New SqlConnection(ConStr)
con.Open()

'Retrieve the FilePath() of the image file
Dim sqlCommand As New SqlCommand()
sqlCommand.Connection = con
sqlCommand.CommandText = "SELECT ItemImage.PathName() AS PathName " + _
                         "FROM items WHERE ItemNumber = 'MS1001'"
Dim filePath As String = sqlCommand.ExecuteScalar()

'Obtain a Transaction Context
Dim transaction As SqlTransaction = con.BeginTransaction("ItemTran")
sqlCommand.Transaction = transaction
sqlCommand.CommandText = "SELECT GET_FILESTREAM_TRANSACTION_CONTEXT()"
Dim txContext As Byte() = sqlCommand.ExecuteScalar()

'Open and read file using SqlFileStream Class
Dim sqlFileStream As New SqlFileStream(filePath, txContext, FileAccess.Read)
Dim buffer As Byte() = New Byte(sqlFileStream.Length) {}
sqlFileStream.Read(buffer, 0, buffer.Length)

'Bind the image data to an image control
Dim ms As MemoryStream = New MemoryStream(buffer)
Dim bmp As Bitmap = New Bitmap(ms)
ItemImage.Image = bmp

'Cleanup
sqlFileStream.Close()
sqlCommand.Transaction.Commit()
con.Close()

Updating FILESTREAM Data

FILESTREAM data may be modified using either TSQL or using the FILESTREAM API. As mentioned earlier, modifying FILESTREAM data using the Streaming API has a number of advantages over accessing it using TSQL.
Using TSQL to update one or more FILESTREAM columns is not different from updating regular columns. Though a FILESTREAM column can store more than 2 GB of data, it is not possible to access more than 2 GB of FILESTREAM data using TSQL, because 2 GB is the maximum size of any Large Value Type (VARBINARY, VARCHAR, NVARCHAR, TEXT, NTEXT) can store.
Modifying FILESTREAM data using streaming API is pretty much the same as what we saw in the previous example. Before accessing the data you need to access the PathName(), start a transaction and obtain a transaction context before modifying the data using the SqlFileStream class.

Deleting FILESTREAM Data

When a row is deleted from a table having FILESTREAM enabled columns, the record is removed from the table and the FILESTREAM data file is removed from the FILESTREAM Data Container. FILESTREAM data from the FILESTREAM data container is removed by the FILESTREAM garbage collector. Since this is done in a separate background thread, you may still see the deleted file in the FILESTREAM data container until the garbage collector runs again.

FILESTREAM Garbage Collector

SQL Server triggers the FILESTREAM Garbage Collector thread when a CHECKPOINT occurs. So, after deleting FILESTREAM data using TSQL you might notice that the physical file is not removed from the FILESTREAM data container right away. The file will remain in the FILESTREAM data container until the next CHECKPOINT occurs and the garbage collector runs. FILESTREAM operations generate minimal log in the TRN log file and hence it might take longer for a CHECKPOINT to occur if the database is not highly transactional. In such a case, if you want to trigger the garbage collector thread, you should issue an EXPLICIT CHECKPOINT.

FILESTREAM Feature Summary

With FILESTREAM, the SQL Server team not only added a  feature to handle unstructured data, but also made sure that it smoothly integrates with many of the existing features of SQL Server.
  • FILESTREAM feature is available with all versions of SQL Server 2008, including SQL Server Express.
  • SQL Server Express database has a 4 GB limitation; however this limitation does not apply to the FILESTREAM data stored in a SQL Server Express database.
  • FILESTREAM Columns can be replicated.
  • FILESTREAM enabled databases can be used with LOG Shipping
  • FILESTREAM columns can be used in Full Text Indexes
  • FILESTREAM works with all recovery models
  • FILESTREAM File Groups can be placed on compressed disk volumes
  • The maximum size of the file that can be stored into the FILESTREAM data storage is limited by the size of the disk volume only.

Restrictions on existing features

Though the FILESTREAM feature smoothly integrates with many of the existing features of SQL Server, it adds restrictions to or completely disables a few other important features of SQL Server.
  • A FILESTREAM enabled database cannot be used for mirroring. This is one of the key restrictions that I dislike. Mirroring is a very interesting feature and it cannot be used with FILESTREAM.
  • FILESTREAM data is not available in database snapshots. If you create database snapshots and run a “SELECT * FROM table” query on a table with FILESTREAM columns, you will get an error.  All queries that you run on a FILESTREAM enabled table of a database snapshot should exclude FILESTREAM columns.

FILESTREAM Limitations

The FILESTREAM implementation in SQL Server 2008 comes with a few limitations. The following limitations make complete sense to me and I have no complaints on them.
  • FILESTREAM columns cannot be used in Index Keys.
  • FILESTREAM columns cannot be used in the INCLUDED columns of a Non Clustered Index
  • FILESTREAM columns cannot be used in a Table Valued Parameter
  • FILESTREAM columns cannot be used in a memory table
  • FILESTREAM  columns cannot be used in a global or local temp table
  • Statistics cannot be created on FILESTREAM columns
  • Computed columns having reference to FILESTREAM columns cannot be indexed
  • When FILESTREAM Data is accessed through Win 32 APIs, only READ COMMITTED ISOLATION level is supported.
  • FILESTREAM data can be stored only on local disk volumes
However the following limitations are little restrictive and I really wish to have them removed in the future versions of SQL Server.
  • FILESTREAM data is not supported on Database Snapshots.  Well, that is acceptable, however what is the real pain is the error that we get if we run a “SELECT * FROM table” query on a FILESTREAM enabled table in a database snapshot. SQL Server should ideally return NULL values for FILESTREAM enabled columns, if it cannot create snapshots of FILESTREAM data. At present, it is a real pain to exclude all FILESTREAM enabled columns from all queries that runs on a Database Snapshot.
  • Transparent Data Encryption (TDE) does not encrypt FILESTREAM data. It would be interesting to have this restriction removed in the future.

FILESTREAM Feature - Points to Remember

Take note of the following points if you intend to use FILESTREAM in your application.
  • You cannot do database mirroring if you use FILESTREAM features
  • If you replicate FILESTREAM enabled columns, make sure that all subscribers are running on SQL Server 2008 or later versions.
  • If you intend to use LOG shipping, make sure that both primary and secondary servers are running on SQL Server 2008 or later versions.
  • If you are on a FAILOVER CLULSTERING environment, make sure that you place the FILESTREAM file groups in a shared disk and FILESTREAM should be enabled on each node.
  • You cannot access FILESTREAM data if you create database snapshots. If you try to access a FILESTREAM enabled column, SQL Server will raise an error.
  • SQL Server Instance should be configured with Integrated Security if Win 32 access to the FILESTREAM data is required

FILESTREAM Best Practices

  • Place each FILESTREAM data container in a separate volume
  • Use the correct RAID level depending upon the nature of the application (read intensive, write intensive), expected work load etc
  • Do periodical disk defragmentation
  • Decide diligently on whether or not to use a compressed disk volume
  • Disable 8.3 names in NTFS
  • Disable last access time tracking in NTFS
  • FILESTREAM data container should not be on a fragmented volume
  • Make sure that the data being stored is appropriate for FILESTREAM storage. FILESTREAM storage is only good if the size of the data is more than 1 MB (approx)
  • Avoid multiple small appends to the FILESTREAM file
  • If FILESTREAM files are large, avoid using TSQL access to the FILESTREAM data.
  • If reads require only the first few bytes, then consider using TSQL access using substring() function
  • If the entire file is needed Win 32 access is desirable
Read more »

Data Quality Services(DQS)

  • 10:24 PM
  • 0 comments
What is Data Quality Services(DQS)


DQS is a new feature in SQL Server "Denali" that provides us with a knowledge-driven data cleansing solution.

We deal with data and there is a high possibility that the data will be incorrect;may be the user has enter wrong data, the data transmission is corrupted etc. Also integrating those inconsistent data from various sources is also a problem and time consuming that will affect the business and the worst victims in such situations are the customers which on the other hand will affect the company from loss of credibility and revenue, customer dissatisfaction etc. Manual processing is not again a good choice as it is always inclined to have erroneous report however meticulously it has been measure. Automation will not give 100% result. Ultimately it will hamper the historical data and as a consequence will affect data analysis and reporting.

In order to rescue the business from such situations, DQS is the need of the day. It ensures high quality data,improves accuracy,data consistency and resolve problems cause by bad data entry in BI or data warehouse or OLTP systems.

It helps business user or a non database professional to create, maintain and execute their organization’s data quality operations with minimal setup or preparation time and with excellent quality.

It improves the data quality by creating a Knowledge Base(KB) about the data and then clean the data based on the knowledge in the knowledge base.

A Knowledge Base(KB) is a repository of three types of knowledge:

1. Out of the box knowledge

2. Knowledge generated by the DQS server

3. Knowledge generated by the user

This knowledge base once build , can server as a reusable stuff which can be continuously improve and then apply in multiple data-quality improvement processes.

KB identifies the incorrect data,proposes changes to the data,find data matches, mismatches and enables to perform data deduplication.It compares source data with the reference data(cloud-based) provided by data quality providers.

The data steward or IT professional verifies both the knowledge in the knowledge base and the changes to be made to the data, and executes the cleansing, deduplication, and reference data services.

The knowledge in the database stores all kind of knowledges applicable to a specific data source.They are stored in data domains which can even span and each of which is a semantic representation of a type of data in a data field.

A domain contains all kind of values like valid values, invalid values, and erroneous data.

Domain Knowledge(DK) consists of synonym associations, term relationships, validation and business rules,and matching policies. Eqipped with this KB, the IT professional/data steward/non-database user can makes a concrete decision about the data analysis and provides support as to whether to correct those data or not.

The DQS knowledge-driven solution uses two fundamental steps to cleanse data:

1. Builds a Knowledge base through the knowledge management process

2. Changes to be done (if needed for the Knowledge symantics to satisfy) in teh source data based on the knowledge in the KB.This is done through a data quality project.

What are the DQS Components

DOS consists of the

1. DQS Server.

2. DQS Client.

In addition to these, there is a transformation component call as DQS Cleansing Component in SSIS transformation toolbox that helps us in cleansing the data based on the knowledge base created.

The client and the server component are install as part of SQL Server setup program.(Denali CTP3)

DQS Server

The DQS server is implemented as two SQL Server catalogs that we can manage and monitor in the SQL Server Management Studio.They are

1. DQS_MAIN

2. DQS_PROJECT

DQS_MAIN includes DQS stored procedures, the DQS engine, and published knowledge bases.

DQS_PROJECT includes data that is required for knowledge base management and DQS project activities.

The source database that contains the data to be analyzed must also be in the same SQL Server instance as the DQS server.

DQS Client

It is a standalone application, designed for data stewards and DQS administrators that helps to perform knowledge management,domain management, matching policy creation, data cleansing, matching, monitoring, data quality projects, and administration in one user interface.

The client application can installed and run on the same computer as the DQS Server or remotely on a separate computer.



Read more »

Top Ten Feature Of Denali 'SQL Server 2012'

  • 10:20 PM
  • 0 comments
• SQL Server Developer Tools—One of the most obvious improvements in SQL Server Denali is the new development environment, SQL Server Developer Tools, coded-named Juneau. Juneau uses the Windows Presentation Foundation (WPF)–based Visual Studio 2010 shell, and it unifies development for Business Intelligence Development Studio (BIDS) and Visual Studio. One goal for Juneau is to make the development environment consistent for both SQL Azure and the on-premises version of SQL Server.



• Contained databases—Contained databases make it easy to move databases between different instances of SQL Server. With Denali, login credentials are included with contained databases. Users don't need logins for the SQL Server instance because all authentications are handled by the contained database. Contained databases have no configuration dependencies on the instance of SQL Server that they're hosted on and can be moved between on-premises SQL Server instances and SQL Azure.



• Project "Crescent"—The new data visualization tool, code-named Project "Crescent," is Closely integrated with SharePoint 2010 and Silverlight. Microsoft has called the Crescent feature "PowerPoint for your data." Crescent makes it easy for users to create great-looking data pages and dashboards by using data models that are built using PowerPivot or from tabular data from SQL Server Analysis Services.





• Data Quality Services—Valid data is critical for making effective business intelligence (BI) decisions. Data Quality Services lets you set up a knowledge base that defines your metadata rules. You can then run Data Quality Services projects to apply those rules to data stored in a SQL Server data source. The Data Quality Services projects cleanse the data and allow viewing of good, invalid, and corrected rows.





• User-defined server roles—An important security-related feature in Denali is the addition of user-defined severs roles. Earlier releases had fixed server roles that were predefined by Microsoft. These roles covered most situations, but they weren't as flexible or granular as some organizations wanted. The new user-defined server roles give organizations more control and customization ability over SQL Server's server roles.





• Change data capture (CDC) for Oracle—CDC lets you keep large tables in sync by initially moving a snapshot to a target server, then moving just the captured changes between the databases. With the SQL Server 2008 release, CDC was limited to SQL Server, but many organizations also have other database platforms they want to use CDC with. A big improvement in the Denali release is the addition of CDC for Oracle.





• T-SQL enhancements—Two of the most important T-SQL enhancements in Denali are the addition of the Sequence object and the window functions. Unlike the similar Identity column, Sequence lets you tie unique row identifiers across multiple tables. The new window functions apply to sets of rows using the new OVER clause. You can read more about window functions in "Window Functions (OVER Clause)—Help Make a Difference."





• Columnar store index—The columnar store index or, as it is sometimes called, the column-based query accelerator, uses the same high performance/high compression technology that Microsoft uses in PowerPivot, and it brings that technology into the database engine. Indexed data is stored according to the data of each column rather than by the rows, and only necessary columns are returned as query results for columnar indexes. Microsoft states this technology can provide up to 100 times improvement in query performance in some cases.





• Support for Windows Server Core—The ability to run SQL Server on Windows Server Core has been missing from previous releases of SQL Server. Server Core is designed for infrastructure applications such as SQL Server that provide back-end services but don't really need a GUI on the same server. Denali's support for Server Core enables leaner and more efficient SQL Server installations and at the same time reduces potential attack vectors and the need for patching.





• AlwaysOn—Without a doubt, the most important new feature in SQL Server Denali is the new SQL Server AlwaysOn feature. AlwaysOn is essentially the next evolution of database mirroring. AlwaysOn supports up to four replicas, the data in the replicas can be queried, and backups can be performed from the replicas. Although it's still early, AlwaysOn seems more complicated to set up than database mirroring because it requires Windows Failover Clustering, but the advantages appear to make it well worth the extra effort.

Read more »

Page Restore and Tail Log

  • 10:15 PM
  • 0 comments
Here's an interesting scenario that cropped up today. You have a database on a RAID array that failed and has zero'd out a page. How can you get the data back?


There are two ways to do it, depending on the database recovery model and version of SQL Server - single-page restore or manual insert/select - both of which rely on you having a backup of the database. You can use single-page restore if you're on SQL Server 2008 and the database is in Full or Bulk-Logged recovery mode, otherwise you need to use the manual method, and that will only work as long as you know the data being salvaged hasn't changed since the last backup.

Let's try them both. Here's a script to create a test database and make a backup of it:

-- Create the database.

USE master;

GO

CREATE DATABASE dbccpagetest;

GO

ALTER DATABASE dbccpagetest SET RECOVERY FULL;

GO

-- Create a table to play with.

USE dbccpagetest;

GO

CREATE TABLE sales (

salesID INT IDENTITY,

customerID INT DEFAULT CONVERT (INT, 100000 * RAND ()),

salesDate DATETIME DEFAULT GETDATE (),

salesAmount MONEY);

CREATE CLUSTERED INDEX salesCI ON sales (salesID);

GO

-- Populate the table

SET NOCOUNT ON;

GO

DECLARE @count INT

SELECT @count = 0

WHILE (@count < 5000)

BEGIN

INSERT INTO sales (salesAmount) VALUES (100 * RAND ());

SELECT @count = @count + 1

END;

GO

-- Take a full backup.

BACKUP DATABASE dbccpagetest TO DISK = 'C:\dbccpagetest.bak' WITH INIT;

GO









I'm going to simulate our scenario by shutting down the database and using a hex editor to zero out page 158 of the database. (This translates to byte offset 1294336 of the file being zero'd for 8192 bytes).

Now if I run checkdb, I get the following:

Msg 8909, Level 16, State 1, Line 1

Table error: Object ID 0, index ID -1, partition ID 0, alloc unit ID 0 (type Unknown), page ID (1:158) contains an incorrect page ID in its page header. The PageId in the page header = (0:0).

CHECKDB found 0 allocation errors and 1 consistency errors not associated with any single object.

Msg 8928, Level 16, State 1, Line 1

Object ID 2073058421, index ID 1, partition ID 72057594038386688, alloc unit ID 72057594042384384 (type In-row data): Page (1:158) could not be processed. See other errors for details.

CHECKDB found 0 allocation errors and 1 consistency errors in table 'sales' (object ID 2073058421).

CHECKDB found 0 allocation errors and 2 consistency errors in database 'dbccpagetest'.

repair_allow_data_loss is the minimum repair level for the errors found by DBCC CHECKDB (dbccpagetest).

What does the page look like?

DBCC TRACEON (3604);

GO

DBCC PAGE (dbccpagetest, 1, 158, 3);

GO





DBCC execution completed. If DBCC printed error messages, contact your system administrator.

PAGE: (0:0)

BUFFER:

BUF @0x02C0632C

bpage = 0x04C12000 bhash = 0x00000000 bpageno = (1:158)

bdbid = 9 breferences = 0 bUse1 = 37241

bstat = 0xc00009 blog = 0x89898989 bnext = 0x00000000

PAGE HEADER:

Page @0x04C12000

m_pageId = (0:0) m_headerVersion = 0 m_type = 0

m_typeFlagBits = 0x0 m_level = 0 m_flagBits = 0x200

m_objId (AllocUnitId.idObj) = 0 m_indexId (AllocUnitId.idInd) = 0 Metadata: AllocUnitId = 0

Metadata: PartitionId = 0 Metadata: IndexId = -1 Metadata: ObjectId = 0

m_prevPage = (0:0) m_nextPage = (0:0) pminlen = 0

m_slotCnt = 0 m_freeCnt = 0 m_freeData = 0

m_reservedCnt = 0 m_lsn = (0:0:0) m_xactReserved = 0

m_xdesId = (0:0) m_ghostRecCnt = 0 m_tornBits = 16777216

Allocation Status

GAM (1:2) = ALLOCATED SGAM (1:3) = NOT ALLOCATED

PFS (1:1) = 0x60 MIXED_EXT ALLOCATED 0_PCT_FULL DIFF (1:6) = NOT CHANGED

ML (1:7) = NOT MIN_LOGGED

Msg 2514, Level 16, State 5, Line 2

DBCC PAGE error: Invalid page type - dump style 3 not possible.

Note the error at the end of the output - DBCC PAGE can't do an in-depth dump because it doesn't know what page type the page is. Let's try a full page hex dump using dump style 2 instead:

DBCC PAGE (dbccpagetest, 1, 158, 2);

GO

PAGE: (0:0)



DATA:

Memory Dump @0x44F3C000

44F3C000: 00000000 00020000 00000000 00000000 †................

44F3C010: 00000000 00000000 00000000 00000000 †................



44F3DFE0: 00000000 00000000 00000000 00000000 †................

44F3DFF0: 00000000 00000000 00000000 00000000 †................

DBCC execution completed. If DBCC printed error messages, contact your system administrator.

It really is all zero. First we'll fix it using page restore.

USE master;

GO

RESTORE DATABASE dbccpagetest PAGE = '1:158' FROM DISK = 'C:\dbccpagetest.bak';

GO

Processed 1 pages for database 'dbccpagetest', file 'dbccpagetest' on file 1.

The roll forward start point is now at log sequence number (LSN) 32000000047000001. Additional roll forward past LSN 33000000001700001 is required to complete the restore sequence.

RESTORE DATABASE ... FILE= successfully processed 1 pages in 0.176 seconds (0.046 MB/sec).



Isn't that cool? You can restore up to 1000 single pages from a backup at a time. For VLDBs, this cuts the recovery time WAY down. Now we need to roll forward the log. We don't have any more log backups so we can finish the roll forward by backing up and restoring the tail of the log.







-- Need to complete roll forward. Backup the log tail...

BACKUP LOG dbccpagetest TO DISK = 'C:\dbccpagetest_log.bak' WITH INIT;

GO

-- ... and restore it again.

RESTORE LOG dbccpagetest FROM DISK = 'C:\dbccpagetest_log.bak';

GO



Processed 5 pages for database 'dbccpagetest', file 'dbccpagetest_log' on file 1.

BACKUP LOG successfully processed 5 pages in 0.146 seconds (0.248 MB/sec).

Processed 0 pages for database 'dbccpagetest', file 'dbccpagetest' on file 1.

RESTORE LOG successfully processed 0 pages in 0.004 seconds (0.000 MB/sec).

And now we should have a clean database:



DBCC CHECKDB (dbccpagetest) WITH NO_INFOMSGS;

GO

Command(s) completed successfully.

Easy. But what if we can't do a page restore? Assuming I've corrupted the database in exactly the same way again, the first thing is to do is make sure we can restore the backup and then see what data range is on that page:

RESTORE DATABASE dbccpagetest_copy FROM DISK = 'C:\dbccpagetest.bak' WITH

MOVE N'dbccpagetest' TO N'C:\dbccpagetest_copy.mdf',

MOVE N'dbccpagetest_log' TO N'C:\dbccpagetest_log.ldf',

REPLACE;

GO

DBCC PAGE (dbccpagetest_copy, 1, 158, 3);

GO

Processed 184 pages for database 'dbccpagetest_copy', file 'dbccpagetest' on file 1.

Processed 2 pages for database 'dbccpagetest_copy', file 'dbccpagetest_log' on file 1.

RESTORE DATABASE successfully processed 186 pages in 0.361 seconds (4.205 MB/sec).

PAGE: (1:158)

BUFFER:

BUF @0x02BE8D38

bpage = 0x03FB4000 bhash = 0x00000000 bpageno = (1:158)

bdbid = 10 breferences = 1 bUse1 = 38283

bstat = 0xc00009 blog = 0x159a2159 bnext = 0x00000000

PAGE HEADER:

Page @0x03FB4000

m_pageId = (1:158) m_headerVersion = 1 m_type = 1

m_typeFlagBits = 0x4 m_level = 0 m_flagBits = 0x8200

m_objId (AllocUnitId.idObj) = 68 m_indexId (AllocUnitId.idInd) = 256

Metadata: AllocUnitId = 72057594042384384

Metadata: PartitionId = 72057594038386688 Metadata: IndexId = 1

Metadata: ObjectId = 2073058421 m_prevPage = (1:157) m_nextPage = (1:159)

pminlen = 28 m_slotCnt = 245 m_freeCnt = 11

m_freeData = 7691 m_reservedCnt = 0 m_lsn = (24:453:8)

m_xactReserved = 0 m_xdesId = (0:0) m_ghostRecCnt = 0

m_tornBits = -1020457745

Allocation Status

GAM (1:2) = ALLOCATED SGAM (1:3) = NOT ALLOCATED

PFS (1:1) = 0x60 MIXED_EXT ALLOCATED 0_PCT_FULL DIFF (1:6) = NOT CHANGED

ML (1:7) = NOT MIN_LOGGED

Slot 0 Offset 0x60 Length 31

Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP

Memory Dump @0x4542C060

00000000: 10001c00 d5030000 5bd30000 3f771101 †........[...?w..

00000010: b9980000 baa10a00 00000000 0500e0††††...............

UNIQUIFIER = [NULL]

Slot 0 Column 1 Offset 0x4 Length 4

salesID = 981

Slot 0 Column 2 Offset 0x8 Length 4

customerID = 54107

Slot 0 Column 3 Offset 0xc Length 8

salesDate = Jan 17 2007 4:35PM

Slot 0 Column 4 Offset 0x14 Length 8

salesAmount = 69.68



Slot 244 Offset 0x1dec Length 31

Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP

Memory Dump @0x4542DDEC

00000000: 10001c00 c9040000 bfa10000 57771101 †............Ww..

00000010: b9980000 c6b80500 00000000 0500e0††††...............

UNIQUIFIER = [NULL]

Slot 244 Column 1 Offset 0x4 Length 4

salesID = 1225

Slot 244 Column 2 Offset 0x8 Length 4

customerID = 41407

Slot 244 Column 3 Offset 0xc Length 8

salesDate = Jan 17 2007 4:35PM

Slot 244 Column 4 Offset 0x14 Length 8

salesAmount = 37.50

DBCC execution completed. If DBCC printed error messages, contact your system administrator.

So we're looking at salesID range 981 to 1225 inclusive. Before we can copy the rows back to the damaged database, we need to get rid of the corrupt page. Repair should delete the page for us. First I'm going to take another backup though - just in case something goes wrong!

BACKUP DATABASE dbccpagetest TO DISK = 'C:\dbccpagetest_corrupt.bak' WITH INIT;

GO

ALTER DATABASE dbccpagetest SET SINGLE_USER;

GO

DBCC CHECKDB (dbccpagetest, REPAIR_ALLOW_DATA_LOSS) WITH NO_INFOMSGS;

GO

ALTER DATABASE dbccpagetest SET MULTI_USER;

GO

Processed 184 pages for database 'dbccpagetest', file 'dbccpagetest' on file 1.

Processed 4 pages for database 'dbccpagetest', file 'dbccpagetest_log' on file 1.

BACKUP DATABASE successfully processed 188 pages in 0.380 seconds (4.052 MB/sec).

Msg 8909, Level 16, State 1, Line 1

Table error: Object ID 0, index ID -1, partition ID 0, alloc unit ID 0 (type Unknown), page ID (1:158) contains an incorrect page ID in its page header. The PageId in the page header = (0:0).

The error has been repaired.

CHECKDB found 0 allocation errors and 1 consistency errors not associated with any single object.

CHECKDB fixed 0 allocation errors and 1 consistency errors not associated with any single object.

Repair: The Clustered index successfully rebuilt for the object "dbo.sales" in database "dbccpagetest".

Repair: The page (1:158) has been deallocated from object ID 2073058421, index ID 1, partition ID 72057594038386688, alloc unit ID 72057594042384384 (type In-row data).

Msg 8945, Level 16, State 1, Line 1

Table error: Object ID 2073058421, index ID 1 will be rebuilt.

The error has been repaired.

Msg 8928, Level 16, State 1, Line 1

Object ID 2073058421, index ID 1, partition ID 72057594038386688, alloc unit ID 72057594042384384 (type In-row data): Page (1:158) could not be processed. See other errors for details.

The error has been repaired.

Msg 8976, Level 16, State 1, Line 1

Table error: Object ID 2073058421, index ID 1, partition ID 72057594038386688, alloc unit ID 72057594042384384 (type In-row data). Page (1:158) was not seen in the scan although its parent (1:154) and previous (1:157) refer to it. Check any previous errors.

The error has been repaired.

Msg 8978, Level 16, State 1, Line 1

Table error: Object ID 2073058421, index ID 1, partition ID 72057594038386688, alloc unit ID 72057594042384384 (type In-row data). Page (1:159) is missing a reference from previous page (1:158). Possible chain linkage problem.

The error has been repaired.

CHECKDB found 0 allocation errors and 3 consistency errors in table 'sales' (object ID 2073058421).

CHECKDB fixed 0 allocation errors and 3 consistency errors in table 'sales' (object ID 2073058421).

CHECKDB found 0 allocation errors and 4 consistency errors in database 'dbccpagetest'.

CHECKDB fixed 0 allocation errors and 4 consistency errors in database 'dbccpagetest'.

We should check the row count to see that the count has dropped from the initial 5000 rows we inserted:

USE dbccpagetest;

GO

SELECT COUNT (*) FROM SALES;

GO

SELECT COUNT (*) FROM sales WHERE salesID > 980 AND salesID < 1226;

GO

And we're down to 4755 rows, as expected with zero rows in that range. All we need to do now is to copy the missing rows over from the restored copy. Remember, this will only work if you know that the data being salvaged hasn't changed since the backup was taken - otherwise you'll have old and new data mixed in the table which will play havoc with your business. Before we copy the rows, we know we're got an identity column we'd like to preserve so we set IDENTITY_INSERT on which tells the server not to generate new identity values for the inserted rows.

-- Make sure identity values survive.

SET IDENTITY_INSERT sales ON;

GO

-- Insert the missing rows.

SET NOCOUNT OFF;

GO

INSERT INTO sales (salesID, customerID, salesDate, salesAmount)

SELECT * FROM dbccpagetest_copy.dbo.sales AS R

WHERE R.salesID > 980 AND R.salesID < 1226;

GO

-- Restore identity behavior.

SET IDENTITY_INSERT sales OFF;

GO

(245 row(s) affected)

We copy over 245 rows and checking the row count again says we're back to 5000 rows.



Read more »

Understanding the Difference between Owners and Schemas in SQL Server

  • 11:17 PM
  • 0 comments

SQL Server 2005 introduces the concept of schemas as opposed to object owners found in previous versions. This article will explain the differences between the two and, hopefully, clear up some of the confusion that still exists about schemas.
Object owners
To understand the difference between owners and schema, let’s spend some time reviewing object ownership. When an object is created in SQL Server 2000 or earlier, the object must have an owner. Most of the time, the owner is “dbo”, also known as the database owner. It is possible that an object can be owned by any user account in the database. The way to determine the owner is by looking at the fully qualified object name which you can see using SQL Server Enterprise Manager or Management Studio when you are viewing a list of the tables. For example, the name of a table called orders owned by dbo is dbo.orders. If the table’s ownership is transferred to user abc, the table will now be namedabc.orders.
How does an object get its owner? It depends on the user who created it. It is also possible for someone in the db_owner role to create an object owned by any user in the database. By default the user account that creates the object (the account must have CREATE TABLE permission) will also own the object. Only user accounts in the db_owner role can create objects owned by dbo. Even then, under certain circumstances, the owner will end up being the actual user account instead of dbo. See Undestanding Object Ownership for an in depth discussion of this issue
Using dbo as the owner of all the database objects can simplify managing the objects. You will always have a dbo user in the database. Users in the database will be able to access any object owned by dbo without specifying the owner as long as the user has appropriate permission. If an object is owned by an account other than dbo, the ownership must be transferred to another user if the original account is to be deleted. For example, if a non-dbo database user called “ted” creates the sales table, it will be called ted.sales. In order for users other than Ted to see the table, it must be referred to by the fully qualified name. If Ted leaves the company or department and his account must be removed from the database, the ownership of the table must be transferred to another user account using the sp_changeobjectowner stored procedure before Ted’s account can be removed.
If the table has been used in applications or referred to in any definitions such as stored procedures, changing the owner will now break all the code. If the dbo had owned the table from the start, there would have been no problem removing Ted’s account. The code would not have to use the fully qualified name, though there is a slight performance gain in doing so and is considered a best practice.
Schemas
I like to think of schemas as containers to organize objects. You will see that the tables are organized by department or function, such as “HumanResources” or “Production”. This looks similar to the old owner concept, but has many advantages. First of all, since the objects are not tied to any user accounts, you do not have to worry about changing the owner of objects when an account is to be removed. Another advantage is that the schemas can be used to simplify managing permissions on tables and other objects. The schema has an owner, but the owner is not tied to the name. So, if an account owns a schema and the account must be removed from the database, the owner of the schema can be changed without breaking any code. If you do not wish to organize your database objects into schemas, the dbo schema is available.
Let’s say that the employees within the Widgets department are members of the same network security group, WidgetEmp. The managers of each department are members of an additional group, WidgetManagers. We create a schema called Widgets and many tables, views and stored procedures are contained in the Widgets schema. To control access to the objects, we could add the WidgetEmp and WidgetManagers network groups to the SQL Server and to the database. Because we are concerned about controlling access to tables, the WidgetEmp group has been given execute permission to all stored procedures in the Widget schema. The WidgetManagers group has also been given select permission to all the tables and views. The great thing about this is that you no longer have to remember to grant permission whenever a new stored proc, table or view is created as long as it is in the Widgets schema.
To grant execute permission to all stored procedures within a schema, follow these steps:
  • Using SQL Server Management Studio, expand Security then Schemas under the database.
  • Right-click on the schema name and choose Properties.
  • Select the permissions page and click Add to choose database users or roles.
  • Once the users or roles are selected, a list of permissions will fill the bottom box.
  • To grant execute permission to all stored procedures, check Grant next to the Execute item.
I have always wanted a database role that had execute permission on all stored procs. This would be similar to the db_datareader role. I don’t know why a role like this doesn’t exist, but at least now there is a simple work-around. Even if you are not taking advantages of schemas in your database, you can give execute permission to stored procedures in the dbo schema to achieve the same result.
One important thing to keep in mind if you want to take advantage of schemas is that the schema organization must be considered early on in the design of the database. Changing the schema design late in the game could cause many changes to code.
Upgrading your database
What happens if you upgrade a database from SQL Server 2000 to 2005? When a database is upgraded from 2000 to 2005, a schema for each user in the database is created. You may not even notice this until you attempt to remove one of the user accounts. At that point you will receive the error message “The database principal owns a schema in the database, and cannot be removed”. To solve this problem just delete the schema first as long as it is empty. If the schema is not empty, you will have to decide whether to delete the objects first or transfer the schema to another owner.
Conclusion
While the concept of schemas is confusing at first, it has many advantages once you figure it out. Just think of the schema as a container to organize objects and simplify granting permissions as opposed to the earlier notion of owner. Most importantly, the schema organization must be considered early in the design process to avoid problems with code later on. Finally, by granting Execute permission in a schema to an account or database role, we now have a way to make sure that users can always execute new stored procedures.

Read more »
 

Copyright © 2010 SQL Cached, All Rights Reserved. Design by DZignine