7 March 2015

Understanding SQL Server ColumnStore Indexes


Problem
The amount of data in data warehouses is growing rapidly. At the same time, the query performance against these same data warehouses is degrading. I heard SQL Server 2012 introduces a new way of creating/managing/storing indexes which improves the performance of these common data warehousing queries several fold, in some cases 10 to 100 times faster. So what is this new feature? How can you build it? How does it get stored by SQL Server and how does it improve the performance of common data warehousing queries?  Read this tip to learn more.


Solution
ColumnStore Indexes are the functionality which was introduced with SQL Server 2012 which intends to improve the performance of common data warehousing queries. This new functionality includes ColumnStore Indexes and Batch mode (vector based) query processing/execution capabilities. The later one is used by the query optimizer internally to process the request in batches when the query execution plan uses at least one ColumnStore Index. The processing of a batch at a time speeds up joins, filtering and aggregations (in comparison with row at a time processing) and better utilizes today's multicore/multi-processors hardware. The choice to use either batch mode query processing or traditional row mode query processing is determined by the query optimizer.

Understanding SQL Server ColumnStore Indexes

The syntax for creating a ColumnStore Index is not much different from creating traditional Row Store/B-Tree indexes, but the difference lies in the way data gets stored/accessed in the pages on disk. The traditional Row Store Index gets stored in a B-Tree structure and data from all the columns of the index (of the row) are stored continuously on the same page (applies to heap as well).  This type of index is good in cases (OLTP) where you use predicates to filter the data or scan data from all the columns of the indexes, but for OLAP systems it poses some problems such as:
  • In the case of a Row Store Index, data from all the columns of the rows are stored together on the same page and hence it has a small ratio of redundancy on each page (data from different columns normally would not be similar), meaning compression would not be beneficial.
  • In the case of a Row Store Index, data from all the columns of the rows are stored together on the same page and no matter if you are selecting all the columns of the index or only few, it pulls out pages containing data of all the columns of the index into memory and yielding a significantly higher IO ratio, especially in case of a fact table which has dozens of columns and only few of them are normally referenced in the query.
ColumnStore Indexes also store each column data in separate pages (column wise fashion) rather than the traditional Row Store Index, which stores data from all the columns of a row together contiguously (row wise fashion), this way when you query. If your query only selects a few columns of the index, it reads less pages as it needs to read data of selected columns only and improves the performance by minimizing the IO cost.
Compression can be more effective for a ColumnStore index as data from each column is stored separately and redundancy (repetitive values) of the data in each column in each page is high. This means highly compressed pages takes less IO to bring the data into memory and effectively reduce query response time, especially for subsequent query execution.
As data gets stored in column wise fashion, your query selecting only few columns will reference only pages that contain data of those columns, which would normally be 10%-20% in a typical data warehouse scenario. This means you are reducing the IO by 80%-90%.
Please note, ColumnStore Indexes might be good when scanning and aggregating data in large fact tables involving star schema joins, whereas Row Store Indexes may offer better query performance for very selective queries, such as queries that lookup a single row or a small range of rows. In addition, ColumnStore Indexes are created to accelerate common data warehouse queries and would not be suitable for OLTP workloads.
Row store versus columnstore indexes
Row Store Index values from all the columns of the rows are stored together on the same page as shown in the top portion of the image whereas with ColumnStore Indexes values from a single column (multiple rows) are stored together as shown on the bottom portion of the image. Image source.

Benefits of using SQL Server ColumnStore Indexes

There are several benefits of using ColumnStore indexes over Row Store Indexes as outlined below:
  • Faster query performance for common data warehouse queries as only required columns/pages in the query are fetched from disk
  • Data is stored in a highly compressed form (Vertipaq technology) to reduce the storage space
  • Frequently accessed columns (pages that contains data for these columns) remain in memory because a high ratio of compression is used in the pages and less pages are involved
  • Enhanced query processing/optimization and execution feature (new Batch Operator or batch mode processing) improves common data warehouse queries' performance

Limitations of SQL Server ColumnStore Indexes

There are several limitations of using SQL Server ColumnStore indexes over Row Store indexes including:
  • A table with a ColumnStore Index cannot be updated
  • ColumnStore index creation takes more time (1.5 times almost) than creating a B-tree index (on same set of columns) because the data is compressed
  • A table can have only one ColumnStore Index and hence you should consider including all columns or at least all those frequently used columns of the table in the index
  • A ColumnStore Index can only be non cluster and non unique index; you cannot specify ASC/DESC or INCLUDE clauses
  • Not all data types (binary, varbinary, image, text, ntext, varchar(max), nvarchar(max), etc.) are supported
  • The definition of a ColumnStore Index cannot be changed with the ALTER INDEX command, you need to drop and create the index or disable it then rebuild it
  • You can create a ColumnStore index on a table which has compression enabled, but you cannot specify the compression setting for the column store index
  • A ColumnStore Index cannot be created on view
  • A ColumnStore Index cannot be created on table which uses features like ReplicationChange TrackingChange Data Capture and Filestream

Loading data into a SQL Server table with a ColumnStore Index

As I said before, a table with ColumnStore Index is not updatable, so you will need to work out a way to update it. Luckily we have couple of options, for example, dropping/disabling index, loading data and rebuilding index again or load the data in a table, create ColumnStore Index on the table and then switch in that table in the main table, if the main table is partitioned.

Creating a SQL Server ColumnStore Index

First of all, you can have only one column store index on each table. This index should be a non clustered index that should ideally include all the columns of the table.  This is generally the best practice because all of the columns can be accessed independently from one another. The general syntax for creating ColumnStore Indexes has been provided below, but keep in mind you can also create ColumnStore Indexes using the Object Explorer in SSMS:
CREATE NONCLUSTERED COLUMNSTORE INDEX <IndexName> 
ON <TableName>
(
 Col1,
 Col2,
 ....
 ....
 Coln
)
GO
I am going to use the FactInternetSales fact table from the AdventureWorksDW2008R2 database for this demonstration. Please note, this table is not that large to demonstrate the performance gains possible with ColumnStore Indexes, but the idea is to start working with ColumnStore Indexes to understand how the query optimizer uses it for better performance and how to identify batch mode processing in the query plan. In the script below, I am creating a ColumnStore Index on the FactInternetSales table and including all of the frequently used columns from that table in the index. As I said before, you can choose to include all columns from the table and as the data gets stored in highly compressed form. 
USE AdventureWorksDW2008R2
GO
CREATE NONCLUSTERED COLUMNSTORE INDEX CSI_FactInternetSales
ON dbo.FactInternetSales 
(
 ProductKey,
 OrderDateKey,
 DueDateKey,
 ShipDateKey,
 CustomerKey,
 PromotionKey,
 CurrencyKey,
 SalesTerritoryKey,
 SalesOrderNumber,
 SalesOrderLineNumber,
 TotalProductCost,
 SalesAmount
)
GO
Now its time to run some queries against the fact table on which we created the ColumnStore Index to see how the query optimizer uses it and how it improves the query performance. I have provided two sample queries below.  For the first one, the query optimizer will by default use the column store index since all of the required columns' data is available. The second query is same as the first one, but this time I am instructing query optimizer to ignore the ColumnStore Index with the OPTION clause as highlighted below and use the row store index instead (in this case cluster index):
SELECT F.SalesOrderNumber, F.OrderDateKey, F.CustomerKey, F.ProductKey, F.SalesAmount
FROM dbo.FactInternetSales AS F
INNER JOIN dbo.DimProduct AS D1 ON F.ProductKey = D1.ProductKey
INNER JOIN dbo.DimCustomer AS D2 ON F.CustomerKey = D2.CustomerKey


SELECT F.SalesOrderNumber, F.OrderDateKey, F.CustomerKey, F.ProductKey, F.SalesAmount
FROM dbo.FactInternetSales AS F
INNER JOIN dbo.DimProduct AS D1 ON F.ProductKey = D1.ProductKey
INNER JOIN dbo.DimCustomer AS D2 ON F.CustomerKey = D2.CustomerKey
OPTION (IGNORE_NONCLUSTERED_COLUMNSTORE_INDEX)
GO
Below are the execution plans for the two queries. As you can see for the first query, the query optimizer uses the ColumnStore Index Scan operator (a brand new operator introduced in this release) whereas the second query uses Clustered Index Scan operator (as we asked explicitly to ignore column store index). Now look at the total cost of each query relative to the other one.  Even though both the queries are the same (and returns the same set of data to the client) the first one, which uses column store index, has 14% of the cost relative to the batch whereas the second one, which does not use column store index and uses cluster index instead, has 86% of the cost relative to the batch:
Here are the execution plans of the above two queries showing the performance of the ColumnStore index surpasses the Row Store index

As I said before, SQL Server has one more operation specifically for ColumnStore Indexes and this is evident when you hover your mouse over the ColumnStore Index Scan icon in the above execution plan. It will display details about this operator as shown below, notice the estimated I/O Cost for this operator and compare it with the one for Clustered Index Scan of the second query:
SQL Server ColumnStore index scan from the execution plan
We all know that the slowest part of a query execution is cost of IO (Input/Output), so the idea behind column store index, to reduce the IO cost by storing the data in column form, retrieving only those pages which contain data from the selected columns in the query and compressing the data on the page so that the total number of required pages can be reduced to a minimum. If you look at the image below, this is the IO statistics of the above two queries, the first query which uses ColumnStore Index has significantly less IO in comparison to the second query, which does not use column store index (instead it uses row store/clustered index):
IO Statistics for the two queries indicating the ColumnStore Index is more effecient than the Row Store Index
Now let's turn our attention to using aggregation. The two queries below are re-writes of the above queries, but this time I am using SUM function for summing up total sales for each day. The first query will use ColumnStore Index whereas the second query uses row store index (clustered) as we have specifically indicated to not use column store index by the query optimizer for the second query as highlighted:
SELECT F.OrderDateKey, SUM(F.SalesAmount) AS TotalSales
FROM dbo.FactInternetSales AS F
INNER JOIN dbo.DimProduct AS D1 ON F.ProductKey = D1.ProductKey
INNER JOIN dbo.DimCustomer AS D2 ON F.CustomerKey = D2.CustomerKey
GROUP BY F.OrderDateKey


SELECT F.OrderDateKey,SUM(F.SalesAmount) AS TotalSales
FROM dbo.FactInternetSales AS F
INNER JOIN dbo.DimProduct AS D1 ON F.ProductKey = D1.ProductKey
INNER JOIN dbo.DimCustomer AS D2 ON F.CustomerKey = D2.CustomerKey
GROUP BY F.OrderDateKey
OPTION (IGNORE_NONCLUSTERED_COLUMNSTORE_INDEX)
GO
This time, the execution plan of the first query indicates that it uses the ColumnStore Index rather than the Row Store Index of the second query and hence the cost of the first query is 26% relative to the batch and the cost of the second query is 74% relative to the batch.  Once again the ColumnStore Index performance exceeds the traditional Row Store Indexes.
The execution plan of the first query uses the CcolumnStore Index and is more effecient than the Row Store Index in the second query

Please note the following items about ColumnStore Indexes

  • Example shown above is based on a table which has far less records as compared to production data warehouses. The expectation is that the performance improvement would be much higher than the example above for common data warehouse queries where a large amount of data scanning, data filtering and aggregation is involved. One study of an aggregation query on a 1 TB fact table with 1.44 billion records resulted in a 16 times improvement in CPU cycle and 455 times improvement in elapsed time if the query uses the ColumnStore Index.  For more information click here.
Please refer MSSQL Tips blog

6 March 2015

Changing Collation After Installation of SQL Server

A simple way to correct the collations in a few steps is outlined in this tip. It is recommended to create a backup of all databases (including system databases) before take administrative actions on a SQL Server instance. It is important to ensure that there is no fixed collation logic in columns or inside stored procedures, triggers, etc., otherwise the command below may report problems.

Step 1 - Determine the SQL Server Collation

Let's confirm the current SQL Server instance collation and all it databases including system databases collation before taking actions.

SQL Server Instance Collation























SQL Server Master Database Collation























SQL Server DBTest Database Collation




















The server has the "Latin1_General_CI_AS" collation and we'll change it to "SQL_Latin1_General_CP1_CI_AI" for this test.

Step 3 - Open a Command Prompt and Navigate to the Binn Directory

Now we have to open a command prompt with administrative privileges and go to the BINN directory of Microsoft SQL Server, following the example below:















This picture shows the SQL Server Binn directory and "sqlservr.exe" that will be used in this test.

Step 4 - Apply a New SQL Server Collation

Execute the command below. A lot of information will appears and no user action is required, just close the prompt window after the execution ends.  The parameter "-s" is only necessary if more than one SQL Server instance exists on the target machine.
sqlservr -m -T4022 -T3659 -s"SQLEXP2014" -q"SQL_Latin1_General_CP1_CI_AI"
Parameters used:
[-m] single user admin mode
[-T] trace flag turned on at startup
[-s] sql server instance name
[-q] new collation to be applied

























































































Please refer MSSQL Tips blog.

Covering Index Performance

Query
I was recently involved in troubleshooting data warehouse queries for one of my customers who had an ETL package running longer than usual. The package was quite simple – it was inserting a large number of rows from a staging table into a large table containing hundreds of millions of rows. The initial investigation revealed that the package's OLEDB destination adapter was responsible for most of the execution time. The destination table had a number of indexes, some of them larger than 200 GB and the execution plan for the bulk inserts has showed that index updates were significantly contributing to the slowness of the inserts. 
The total execution costs for a few large non clustered indexes had more than a 40% share in the entire execution plan. We've considered disabling the largest indexes, however it turned out they were heavily used by some daily reports and disabling them could lead to significant performance impact on those reports.
Disabling large indexes prior to ETL and enabling them afterwards also was not an option, because the index rebuild required significant time and reports on those indexes needed to be run immediately after the ETL package. So, I started looking into ways to reduce index sizes, assuming that smaller indexes would require less index updates and therefore better performance for data insert and update transactions.

Solution 

Fully covering and partially covering SQL Server indexes

A closer examination has showed that even though the largest indexes had only a few key fields, they contained a high number of columns in their INCLUDED columns logic, apparently some developers created them in order to satisfy queries with large SELECT lists. For those of you who are not familiar with covering indexes, I'd recommend readingthis article by Joe Webb.
The biggest benefit of covering index is that when it contains all the fields required by query, it may greatly improve query performance and best results are often achieved by placing fields required in filter or join criteria into the index key and placing fields required in the SELECT list into the INCLUDE part of the covering index. As you can see from the sample execution plan below, the index IDX_Employees_Covering provides all the fields included in the SELECT list and therefore completely satisfies the query:
Query:
SELECT FirstName, LastName, Birthdate, DepartmentId, PositionId, 
ManagerId, Salary, Address, City, State, HiredDate
from Employees 
where DepartmentId between 10 and 70 
AND PositionId between 10 and 80
Index:
CREATE NONCLUSTERED INDEX IDX_Employees_Covering ON Employees (DepartmentId,PositionId) 
INCLUDE (FirstName,LastName,Birthdate,ManagerId,Salary,Address,City,State,HiredDate)
Figure1. Execution plan for fully covering index:





















However, in some cases a fully covering index may become partially covering, due to table/query enhancements. As you can see from the example below for the same query, index IDX_Employees_PartiallyCovering doesn't provide all the required fields and SQL Server is forced to use an additional operator, a Key Lookup in order to bring missing columns (City, HiredDate, State in this example) from the clustered index:
Index:
CREATE NONCLUSTERED INDEX IDX_Employees_PartiallyCovering 
ON Employees DepartmentId PositionId 
INCLUDE FirstName LastName Birthdate ManagerId 
Figure2. Execution plan for partially covering index:








Index optimization

In the above mentioned problem my goal was to optimize the existing indexes without compromising the performance of read queries. So, I've found all the queries from the query cache which had reference to large indexes and analyzed their execution plans, using this query described by Jonathan Kehayias in this article.  This analysis has revealed that none of the large covering indexes were fully satisfying queries, in other words they had Lookup operators in their execution plans. So I thought of removing some of the columns from the INCLUDE part of the index would not change the query since a Lookup operator had to bring more fields in anyway as shown below.
Execution plans for partially covering indexes:
















I've removed most of the fields from the INCLUDE part of the covering indexes without touching the main index and index sizes have dropped up to 40%.  As a result, query performance improvements have exceeded all my expectations- the execution costs of related SELECT queries have dropped and they ran faster. Moreover, we've gained more than 45% improvement on data warehouse bulk insert transactions. Below I've tried to reproduce the problem and provide a comparison between various indexing options.

Please refer MSSQL Tips blog

9 February 2015

COPY_ONLY Backups with SQL Server

There was different scenario in Copy_only backup.

Starting with SQL Server 2005, a new backup option has been added that allows you to take full and transaction log backups in between your regularly scheduled backups without affecting the LSNs and therefore the sequence of files that would need to be restored.  Since Differential backups backup all data pages since the last full backup, these types of backups do not affect the LSNs and there is no difference when using the COPY_ONLY feature.
This new option is called COPY_ONLY.  To use this option you would write your backup command as follows:



BACKUP LOG AdventureWorks TO DISK='C:\AdventureWorks_log1.TRN' WITH COPY_ONLY
Now when we go to do a restore using the most recent full backup file along with all of the transaction logs except this COPY_ONLY version, the restore still works as planned.

Full and Transaction Log Backups

Here is a simple way of testing this out with just full and transaction log backups.  You can run the following backup commands and then the restore commands
-- step 1 USE master
GO
BACKUP DATABASE AdventureWorks TO DISK='c:\AdventureWorks_full.BAK' WITH INIT
BACKUP LOG AdventureWorks TO DISK='c:\AdventureWorks_log1.TRN' WITH INIT
BACKUP LOG AdventureWorks TO DISK='c:\AdventureWorks_log2.TRN' WITH INIT

--step 2 RESTORE DATABASE AdventureWorks FROM DISK='C:\AdventureWorks_full.BAK' WITH NORECOVERY, REPLACE
--RESTORE LOG AdventureWorks FROM DISK='C:\AdventureWorks_log1.TRN' WITH NORECOVERY
RESTORE LOG AdventureWorks FROM DISK='C:\AdventureWorks_log2.TRN' WITH RECOVERY
At this point your restore will fail and the database will be in a LOADING mode. 
To test the same process out, but this time using the COPY_ONLY option, you can run the commands below.
-- step 1 USE master
GO
BACKUP DATABASE AdventureWorks TO DISK='c:\AdventureWorks_full.BAK' WITH INIT
BACKUP LOG AdventureWorks TO DISK='c:\AdventureWorks_log1.TRN' WITH INITCOPY_ONLY
BACKUP LOG AdventureWorks TO DISK='c:\AdventureWorks_log2.TRN' WITH INIT

--step 2 RESTORE DATABASE AdventureWorks FROM DISK='C:\AdventureWorks_full.BAK' WITH NORECOVERY, REPLACE
--RESTORE LOG AdventureWorks FROM DISK='C:\AdventureWorks_log1.TRN' RESTORE LOG AdventureWorks FROM DISK='C:\AdventureWorks_log2.TRN' WITH RECOVERY
As you can see the restore process worked this time even though we had a backup that was not used for the restore process.

Full, Differential and Transaction Log Backups

Here is another way of testing full, differential and transaction log backups. 
--step 1  USE master
GO
BACKUP DATABASE AdventureWorks TO DISK='c:\AdventureWorks_full.BAK' WITH INIT
BACKUP LOG AdventureWorks TO DISK='c:\AdventureWorks_log1.TRN' WITH INIT
BACKUP DATABASE AdventureWorks TO DISK='c:\AdventureWorks_diff.BAK' WITH INITDIFFERENTIAL
BACKUP LOG AdventureWorks TO DISK='c:\AdventureWorks_log2.TRN' WITH INIT
--run special full backup BACKUP DATABASE AdventureWorks TO DISK='c:\AdventureWorks_full2.BAK' WITH INIT
--resume normal backup process BACKUP DATABASE AdventureWorks TO DISK='c:\AdventureWorks_diff2.BAK' WITH INITDIFFERENTIAL
BACKUP LOG AdventureWorks TO DISK='c:\AdventureWorks_log3.TRN' WITH INIT

--step 2  RESTORE DATABASE AdventureWorks FROM DISK='C:\AdventureWorks_full.BAK' WITH NORECOVERYREPLACE  RESTORE DATABASE AdventureWorks FROM DISK='C:\AdventureWorks_diff2.BAK' WITH NORECOVERY
RESTORE LOG AdventureWorks FROM DISK='C:\AdventureWorks_log3.TRN' WITH RECOVERY
If we try to restore our original full backup, our latest full backup and any transaction log backup after the differential we get this error.
Msg 3136, Level 16, State 1, Line 1
This differential backup cannot be restored because the database has not been restored to the correct earlier state.
Msg 3013, Level 16, State 1, Line 1
RESTORE DATABASE is terminating abnormally.
If we rerun the process, but this time use the COPY_ONLY option for our special full backup, the restore process works as planned.
--step 1 USE master
GO
BACKUP DATABASE AdventureWorks TO DISK='c:\AdventureWorks_full.BAK' WITH INIT
BACKUP LOG AdventureWorks TO DISK='c:\AdventureWorks_log1.TRN' WITH INIT
BACKUP DATABASE AdventureWorks TO DISK='c:\AdventureWorks_diff.BAK' WITH INITDIFFERENTIAL
BACKUP LOG AdventureWorks TO DISK='c:\AdventureWorks_log2.TRN' WITH INIT
--run special full backup BACKUP DATABASE AdventureWorks TO DISK='c:\AdventureWorks_full2.BAK' WITH INITCOPY_ONLY
--resume normal backup process BACKUP DATABASE AdventureWorks TO DISK='c:\AdventureWorks_diff2.BAK' WITH INITDIFFERENTIAL
BACKUP LOG AdventureWorks TO DISK='c:\AdventureWorks_log3.TRN' WITH INIT

--step 2  RESTORE DATABASE AdventureWorks FROM DISK='C:\AdventureWorks_full.BAK' WITH NORECOVERYREPLACE  RESTORE DATABASE AdventureWorks FROM DISK='C:\AdventureWorks_diff2.BAK' WITH NORECOVERY
RESTORE LOG AdventureWorks FROM DISK='C:\AdventureWorks_log3.TRN' WITH RECOVERY

20 January 2014

During startup of warm standby database, its standby file ('.tuf') was inaccessible to the RESTORE statement. The operating system error was '2(The system cannot find the file specified.)'. Diagnose the operating system error, correct the problem, and retry startup. (Microsoft SQL Server, Error: 3441)



I tried to simulate this on my test machine which had log shipping configured. Below are the steps which I followed -
1. Deleted the TUF file which was available in the secondary server.
2. The delete operation was successful.
3. Checked log shipping status and found that the health is ‘Good’
4. Both primary and secondary databases are synced and both have got same set of data. Row by row,Col by Col.

Note - Ideally deleting the TUF file should also cause issues to log shipping secondary restores, however my simulation did not faced that behavior.
All looks good, and you might be wondering that deleting a TUF file is easy and it’s not going to hurt me much!!!
Now, let’s assume that we lost our primary database server due to Memory burn(Short circuit) and we are in need of the Secondary database.
The RTO and RPO matrix is quite okay and we are allowed to bring the secondary database up within 30 minutes. Walk in the park right? We just have to bring the database up, the users/jobs/other objects are already taken care and just the database needs to be up.
Let’s write this simple 6 word TSQL to bring our database up.
 
RESTORE DATABASE [Test] WITH RECOVERY
Test is my test database which is available in the secondary server and its primary copy was the one which was residing on the server which just went for a trip(Memory burn!)
As soon as we execute this command with a big smile assuming that the database will be up, we will get this message -
Msg 3013, Level 16, State 1, Line 1 RESTORE DATABASE is terminating abnormally. Msg 3441, Level 17, State 1, Line 1 During startup of warm standby database ‘Test’ (database ID 6), its standby file (‘C:\Program Files\Microsoft SQL Server\MSSQL11.SERVER2012B\MSSQL\DATA\Test_20120112191506.tuf’) was inaccessible to the RESTORE statement. The operating system error was ’2(The system cannot find the file specified.)’. Diagnose the operating system error, correct the problem, and retry startup.

What does it mean – It simply means that you have done a good job by deleting the TUF file and now please bring it back.
TUF file is required for the Stand by database to recover and we will not be able to bring the database up without the same.
As the simulation was in a very controlled environment, I brought back the TUF file and ran the restore command once again.

RESTORE DATABASE [Test] WITH RECOVERY
 
RESTORE DATABASE successfully processed 0 pages in 0.908 seconds (0.000 MB/sec).

The database was recovered and was accepting new connections.
Conclusion – TUF file is a very important part of recovery of a stand by database and we have to educate server ops team or anyone who is responsible for cleaning up files and make sure that this is un-touched.
Do you have any ways to recover a stand by database in log shipping secondary without TUF file.If Yes,then please share your experience in the comments section of this post.
Thanks for reading.

3 January 2014

Permissions of Fixed Database Roles

Fixed database roles can be mapped to the more detailed permissions that are included in SQL Server 2005. The following table describes the mapping of the fixed database roles to permissions.

Fixed database role Database-level permission Server-level permission
db_accessadmin Granted: ALTER ANY USER, CREATE SCHEMAGranted: VIEW ANY DATABASE
db_accessadmin Granted with GRANT option: CONNECT

db_backupoperator Granted: BACKUP DATABASE, BACKUP LOG, CHECKPOINTGranted: VIEW ANY DATABASE
db_datareader Granted: SELECTGranted: VIEW ANY DATABASE
db_datawriter Granted: DELETE, INSERT, UPDATEGranted: VIEW ANY DATABASE
db_ddladmin Granted: ALTER ANY ASSEMBLY, ALTER ANY ASYMMETRIC KEY, ALTER ANY CERTIFICATE, ALTER ANY CONTRACT, ALTER ANY DATABASE DDL TRIGGER, ALTER ANY DATABASE EVENT, NOTIFICATION, ALTER ANY DATASPACE, ALTER ANY FULLTEXT CATALOG, ALTER ANY MESSAGE TYPE, ALTER ANY REMOTE SERVICE BINDING, ALTER ANY ROUTE, ALTER ANY SCHEMA, ALTER ANY SERVICE, ALTER ANY SYMMETRIC KEY, CHECKPOINT, CREATE AGGREGATE, CREATE DEFAULT, CREATE FUNCTION, CREATE PROCEDURE, CREATE QUEUE, CREATE RULE, CREATE SYNONYM, CREATE TABLE, CREATE TYPE, CREATE VIEW, CREATE XML SCHEMA COLLECTION, REFERENCESGranted: VIEW ANY DATABASE
db_denydatareader Denied: SELECTGranted: VIEW ANY DATABASE
db_denydatawriter Denied: DELETE, INSERT, UPDATE

db_owner Granted with GRANT option: CONTROLGranted: VIEW ANY DATABASE
db_securityadmin Granted: ALTER ANY APPLICATION ROLE, ALTER ANY ROLE, CREATE SCHEMA, VIEW DEFINITIONGranted: VIEW ANY DATABASE
dbm_monitor Granted: VIEW most recent status in Database Mirroring Monitor
The dbm_monitor fixed database role is created in the msdb database when the first database is registered in Database Mirroring Monitor. The new dbm_monitor role has no members until a system administrator assigns users to the role.
ms189612.note(en-US,SQL.90).gifImportant:
Granted: VIEW ANY DATABASE

2 January 2014

Event ID: 7000 The SQL Server...service failed to start due to the following error: Access is denied.

Event ID: 7000 The SQL Server...service failed to start due to the following error: Access is denied.

Two months back, I worked through a new install of SQLServer 2012 with SP1 on Microsoft Windows Server 2012 Standard on a VMware virtual machine.  During the install everything went smoothly, however once complete I noticed the services were stopped and there were errors in the OS system log:


Log Name:      System
Source:        Service Control Manager
Date:          4/11/2013 12:50:41 PM
Event ID:      7000
Task Category: None
Level:         Error
Keywords:      Classic
User:          N/A
Computer:      ...
Description:
The SQL Server (MSSQLSERVER) service failed to start due to the following error: 
Access is denied.







I turned to my best friend, in situations like this: www.google.com.  Unfortunately this didn't get me very far; it took a bit more digging.  I gathered more errors from the Application log, the System log, and the bootstrap summary (%programfiles%\Microsoft SQL Server\110\Setup Bootstrap\Log\Summary.txt): 
  • Attempted to perform an unauthorized operation
  • error: 40 - Could not open a connection to SQL Server
I also notice that if I attempted to change the "log on as" user in SQL server Configuration Manager again I received an "access is denied" error.  This occurred even if I attempted to use a system user.

It was googling more detailed error messages from the bootstrap summary log that lead me to the solution.  

Apparently, when you build Windows Server 2012 on VMware we need to disable the HotAdd/HotPlug capability.  Who knew?

This was a difficult one to track down, but thanks to SQL Server Central forumsMSDN forums and the community I now have a new item on my build checklist.

One of the things that really helped quickly get through multiple install attempts was using an install config file.  This allowed me to run through the install over and over without having to click through the install each time.  There's a really good article on how to setup an unattended install here: SQL Server 2008 R2 – Unattended Silent Install (Works the same in 2012).

Happy Installs!