SQL Server 2008 Data File Size


Sql Server Consultant

Sql Server Consultant – Steve Abraham

SQL Server Consultant ~ Steve Abraham provides tips for capturing size and state of data files for SQL Server databases.

If you are looking to capture the size and state of all data files for all of your SQL Server databases on a given instance, the script below should do the trick.

usemaster
GO
SELECT
    d.name                                  AS DatabaseName,
    mf.type_desc                            AS FileType,
    mf.name                                 ASFileName,
    mf.physical_name                        AS DatafilePhysicalName,
    mf.state_desc                           AS DatafileState,
    CONVERT(NVARCHAR(25), mf.size / 128)    AS DatafileCurrentSize,
    CASE mf.max_size
        WHEN-1 THEN‘Unlimited’
        ELSECONVERT(NVARCHAR(25), mf.max_size / 128)+‘ MB’
    END                                     AS DatafileMaxSize,
    CASE mf.is_percent_growth
        WHEN 1 THENCONVERT(NVARCHAR(3), mf.growth)+‘ Percent’
        ELSECONVERT(NVARCHAR(25), mf.growth / 128)+‘ MB’
    END                                     AS DatafileGrowth,
    mf.is_media_read_only                   AS IsMediaReadOnly,
    mf.is_read_only                         AS IsFileReadOnly,
    mf.is_sparse                            AS IsFileSparse
FROM
    sys.master_filesAS mf
    INNERJOIN
    sys.databasesAS d
    ON
    mf.database_id = d.database_id
ORDERBY
    DatabaseName,
    FileType DESC,
    FileName
GO

Please feel free to ping me with any questions or requests.  Smile

Index Statistics and AUTO_UPDATE_STATISTICS


I recently worked with a client that uses a SQL Server 2008 data warehouse and was having performance issues while loading data.  There were a number of issues to address, but one of the issues surrounded table statistics – more specifically, how and when they were to be maintained.

AUTO_UPDATE_STATISTICS

The first issue was the question about the load performance impact of auto stats.  My client’s concern was that if this option was enabled that SQL Server would waste resources computing statistics over and over again while data was being loaded into the tables.  The good news is that SQL Server does not compute statistics as data is loading into a table.  The auto stats does not compute statistics until they are needed.

Take for example the following:

use master
GO
 
–Disable row counting
SET NOCOUNT ON
GO
 
–Drop the DemoDatabase if it exists
IF EXISTS (SELECT * FROM sys.databases WHERE name = ‘DemoDatabase’)
BEGIN
    ALTER DATABASE DemoDatabase SET SINGLE_USER WITH ROLLBACK IMMEDIATE
    DROP DATABASE DemoDatabase
END
GO
 
–Create the DemoDatabase
CREATE DATABASE DemoDatabase
GO
 
–Make sure auto-stats is enabled
ALTER DATABASE DemoDatabase SET AUTO_UPDATE_STATISTICS ON
GO
 
–Change database context
use DemoDatabase
GO
 
–Create a test table
CREATE TABLE dbo.TestTable
(
    ClusterColumn INT NOT NULL IDENTITY(1, 1),
    NonClusterColumn INT NOT NULL
)
GO
 
–Create a clustered index on the test table
CREATE UNIQUE CLUSTERED INDEX PK_TestTable ON dbo.TestTable
(
    ClusterColumn
)
GO
 
–Create a non-clustered index on the test table
CREATE NONCLUSTERED INDEX IX_NonClusterColumn ON dbo.TestTable
(
    NonClusterColumn
)
GO
 
/*Check the last update date for the statistics on each table
NOTE: This will be NULL as the statistics will not *exist* yet*/
SELECT
    STATS_DATE(OBJECT_ID(‘dbo.TestTable’), INDEXPROPERTY(OBJECT_ID(‘dbo.TestTable’), ‘PK_TestTable’, ‘IndexID’))        AS ClusterLastUpdate,
    STATS_DATE(OBJECT_ID(‘dbo.TestTable’), INDEXPROPERTY(OBJECT_ID(‘dbo.TestTable’), ‘IX_NonClusterColumn’, ‘IndexID’))    AS NonClusterLastUpdate
GO
 
–Load some data into the table
DECLARE @I INT = 0
WHILE @I < 1000
BEGIN
    INSERT INTO dbo.TestTable (NonClusterColumn) VALUES(@I)
    SET @I += 1
END
GO
 
/*Check the last update date for the statistics on each table
NOTE: This will be still be NULL as the statistics have not been
required yet and as such have not been created by auto stats*/
SELECT
    STATS_DATE(OBJECT_ID(‘dbo.TestTable’), INDEXPROPERTY(OBJECT_ID(‘dbo.TestTable’), ‘PK_TestTable’, ‘IndexID’))        AS ClusterLastUpdate,
    STATS_DATE(OBJECT_ID(‘dbo.TestTable’), INDEXPROPERTY(OBJECT_ID(‘dbo.TestTable’), ‘IX_NonClusterColumn’, ‘IndexID’))    AS NonClusterLastUpdate
GO
 
–Execute a query that needs statistics
SELECT
    COUNT(*)
FROM
    dbo.TestTable
WHERE
    NonClusterColumn BETWEEN 100 AND 200
GO
 
/*Check the last update date for the statistics on each table
NOTE: statistics exist now for the non-clustered index because
they were needed to execute the previous select query but still
don’t exist for the clustered index as it was not needed to execute this query*/
SELECT
    STATS_DATE(OBJECT_ID(‘dbo.TestTable’), INDEXPROPERTY(OBJECT_ID(‘dbo.TestTable’), ‘PK_TestTable’, ‘IndexID’))        AS ClusterLastUpdate,
    STATS_DATE(OBJECT_ID(‘dbo.TestTable’), INDEXPROPERTY(OBJECT_ID(‘dbo.TestTable’), ‘IX_NonClusterColumn’, ‘IndexID’))    AS NonClusterLastUpdate
GO

 

Rebuilding Indexes

Another point that was brought up during these discussions was whether it is necessary to update statistics for an index after the index is rebuilt.  The answer is no.  Rebuilding an index will automatically update your statistics even if AUTO_UPDATE_STATISTICS is set to off.  This does not hold true however for reorganizing (defragmenting) an index.  Only index rebuilds.

Long Running Task Progress Report


There are many operations that take a long time to execute in SQL Server including the following:

 

ALTER INDEX REORGANIZE
AUTO_SHRINK option with ALTER DATABASE
BACKUP DATABASE
DBCC CHECKDB
DBCC CHECKFILEGROUP
DBCC CHECKTABLE
DBCC INDEXDEFRAG
DBCC SHRINKDATABASE
DBCC SHRINKFILE
RECOVERY
RESTORE DATABASE
ROLLBACK
TDE ENCRYPTION

If you are interested the progress made on any one of the above tasks, you can execute the following query:

 

/*
    Author:        Steve Abraham
    Date:        12/7/2011
    Purpose:    List estimated completion times for processes that report progress
*/
 
use master
GO
 
SELECT
    command                                                        AS CommandType,
    [text]                                                        AS CommandText,
    start_time                                                    AS StartTime,
    DATEADD(MILLISECOND, estimated_completion_time, GETDATE())    AS EstimatedCompletionTime,
    percent_complete                                            AS PercentComplete,
    CONVERT(TIME, CONVERT(CHAR(4), DATEDIFF(s, start_time, GETDATE()) / 3600) + ‘:’ + CONVERT(CHAR(4), DATEDIFF(s, start_time, GETDATE()) % 3600 / 60) + ‘:’ + CONVERT(CHAR(4), DATEDIFF(s, start_time, GETDATE()) % 60))    AS RunningTime,
    CONVERT(TIME, CONVERT(CHAR(4), estimated_completion_time / 3600000) + ‘:’ + CONVERT(CHAR(4), estimated_completion_time % 3600000 / 60000) + ‘:’ + CONVERT(CHAR(4), estimated_completion_time % 60000 / 1000))            AS RemainingTime,
    r.wait_type        AS WaitType,
    r.wait_resource    AS WaitResource,
    CONVERT(TIME, CONVERT(CHAR(4), wait_time / 3600000) + ‘:’ + CONVERT(CHAR(4), wait_time % 3600000 / 60000) + ‘:’ + CONVERT(CHAR(4), wait_time % 60000 / 1000))    AS WaitTime
FROM
    sys.dm_exec_requests AS r
    CROSS APPLY
    sys.dm_exec_sql_text(r.sql_handle) s
WHERE
    percent_complete > 0
GO

This will return a result set with the following values:

 

  • CommandType
  • CommandText
  • StartTime
  • EstimatedCompletionTime
  • PercentComplete
  • RunningTime
  • RemainingTime
  • WaitType
  • WaitResource
  • WaitTime

I hope you find this useful.  Please feel free to ping me with any questions.

New Paging Functionality in SQL Server Denali


 

Introducing OFFSET

 

There is new functionality in SQL Server Denali to streamline and simplify returning “Pages” of data to an application.

In SQL Server 2008 and 2005, your code would likely look like this:

use AdventureWorks
GO
 
–Define the common table expression that filters the results
–and applies a row number
WITH CTE AS
(
SELECT
*,
ROW_NUMBER() OVER (ORDER BY OrderDate) AS RowNumber
FROM
Sales.SalesOrderHeader
WHERE
OrderDate BETWEEN ’2004-02-01′ AND ’2004-02-28′
)
 
–Select the page of data
SELECT
*
FROM
CTE
WHERE
RowNumber BETWEEN 11 AND 20
GO

 

SQL Server “Denali” introduces the OFFSET keyword.  The code above is now translated into the following:

use AdventureWorks
GO
 
SELECT
    *
FROM
    Sales.SalesOrderHeader
WHERE
    OrderDate BETWEEN ’2004-02-01′ AND ’2004-02-28′
ORDER BY
    OrderDate OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY
GO

 

The OFFSET command is actually an argument to the ORDER BY clause.  To use it, you simply specify the OFFSET argument, followed by the first row you want returned, then the keyword ROW (or ROWS – there is no difference), then the key words FETCH NEXT followed by the number of rows to return and finally the keyword ROW (or ROWS) and the key word ONLY.

You can also return all of the records starting from a given OFFSET by omitting the “FETCH NEXT N ROWS ONLY” argument as shown below:

use AdventureWorks
GO
 
SELECT
    *
FROM
    Sales.SalesOrderHeader
ORDER BY
    OrderDate OFFSET 10 ROWS
GO

 

You can also use scalar sub-queries to specify the OFFSET or FETCH NEXT arguments.  For example, the following query will return the last 1000 rows in the table sorted by OrderDate.

use AdventureWorks
GO
 
SELECT
    *
FROM
    Sales.SalesOrderHeader
ORDER BY
    OrderDate OFFSET
    (SELECT (COUNT(SalesOrderId) - 1000) FROM Sales.SalesOrderHeader) ROWS
GO

 

 

 

Performance of OFFSET vs. CTE

 

The query plans for each of these are very similar:

image

image

The difference in the cost of each plan is also miniscule

Original Method 0.634015
New Method 0.633909

 

Memory

 

The interesting difference between the two plans is in the memory grant.  In the above scenario, the common table expression version requested a memory grant of 16k vs. 1k for the OFFSET version.  I realize that these are small numbers, but we are dealing with a very small dataset.  What would happen if we dropped the WHERE clause and then grew the table several times?  The result is that the common table expression version increased its memory grant request from 16k to 212 MB while the OFFSET version still only requests 1k.

What does this mean in terms of actual performance?  The first and most obvious consideration is consuming more memory than what’s available and spilling your temporary results to disk.  This can obviously impact performance as disk I/O is perhaps the most expensive operation available.  The second consideration is waiting for the memory grant itself.  On heavily loaded systems you may end up with blocked processes waiting for memory to be granted.  I will cover this in more detail in another post, but for now, if you are so inclined, you can check out the DMVs sys.dm_exec_query_resource_semaphores, sys.dm_exec_query_memory_grants and sys.dm_os_wait_stats for more information on the specifics.

 

Summary

 

While the old standby methods of returning chunks of data in previous versions of SQL Server still work, the OFFSET argument of the ORDER BY clause offers much more optimized and streamlined way of achieving the same results.

Fast Track Denali 3 Key Features of Microsoft’s – Newest Version of SQL Server


I’ll be speaking tonight at the Tampa Bay SQL User Group on 3 key new technologies introduced in Microsoft’s SQL Server v.Next – Denali.

In this session, we will explore the new Columnstore index type, how it differs from other index types, the scenarios in which to use Columnstore indexes and some of the best practices surrounding them. We will also dive into the concept of sequences – how they are similar yet significantly different from identity columns, how to use them as well as some of their limitations. Last but not least, we will cover the new paging functionality and how to get the most out it.

If you are in the Tampa Bay area come out tonight and join us.  We’ll be meeting in our new location:

Juvenile Welfare Board
14155 58th Street North
Clearwater, FL 33760

There will be food and drinks provided tonight courtesy of TEK Systems.  To RSVP, please visit https://www.clicktoattend.com/invitation.aspx?code=157057 or email Pam Shaw the chapter leader at pshaw1129@live.com.

I’ll see you there!

How to: list all primary keys in a database


I recently had the following question posted to this site:

Hello,

I’d think this is a simple question/problem.  I want to get the primary key name for each table in my schema.  By doing so, it will make my search easier when looking at the database.  I have schema X with many tables.  I want to know the primary key to each table and return it in a report form.  So, basically my question is, “Give me the column name of each primary key of each table in schema X.”  Is there a simple SQL statement to do this?

Thank you.

The following query allows you to view all primary keys for all user tables in the current database.  You can tweak it to return results for a given schema or any other set of parameters.

SELECT
S.name AS SchemaName,
O.name AS TableName,
IX.name AS IndexName,
IC.column_id AS ColumnId,
C.name AS ColumnName
FROM
sys.indexes AS IX
INNER JOIN
sys.index_columns AS IC
ON
IX.object_id = IC.object_id AND IX.index_id = IC.index_id
INNER JOIN
sys.columns AS C
ON
IC.object_id = C.object_id AND IC.column_id = C.column_id
INNER JOIN
sys.objects AS O
ON
C.object_id = O.object_id
INNER JOIN
sys.schemas AS S
ON
O.schema_id = S.schema_id
WHERE
IX.is_primary_key = 1
AND
O.type_desc = ‘USER_TABLE’
ORDER BY
SchemaName,
TableName,
IndexName,
ColumnId
GO

Please send me any questions you have about SQL Server and I’d be glad to answer them here.  Smile