Info

You are currently browsing the archives for the SQL Server category.

Calendar
September 2010
S M T W T F S
« Aug    
 1234
567891011
12131415161718
19202122232425
2627282930  
Categories

Archive for the SQL Server Category

Alert for long-running SQL datbase backups

One of my daily tasks is to do a quick check of each SQL Server instance using Activity Monitor, sp_who2, or a DMV-based script.  Sometimes I get busy and forget to do this task.  Today I broke down and wrote a simple script that is executed by a SQL Agent job.  It runs at 8:00 AM, and just goes out to all the instances and checks to see if any backups are still running — if any are still running, an e-mail alert is raised.

The essence of the script follows.  You would might want to modify it to iterate through a list of instances.

IF EXISTS
(
SELECT * FROM instance.MASTER.sys.sysprocesses
WHERE cmd = ‘backup database’
AND program_name = ‘SQL Management’)
BEGIN
EXEC
msdb.dbo.sp_send_dbmail
@profile_name = ‘Master’,
@recipients = ‘mailbox@domain.com’,
@body = ‘Backup job is still running on instance’,
@subject = ‘Backup job is still running on instace’,
@importance =  ‘high’;
END

Learning SMO & Powershell

I created a small script to collect SQL Server file utilization data into a repository.  I’m collecting the space used by the files as well as the space used internally by SQL Server.  I’m doing this across all production databases and servers, so the T-SQL fileproperty function was not all that useful since it only works against the current database.  The solution was to use SMO in a PowerShell script to collect the data since it’s very easy to iterate across multiple servers and databases.  I’ll write up the solution at a later date, but for now I wanted to mention a minor fact that I learned today.

The SMO Database class has a Status property which returns at least two values, “Normal” and “Offline”.  You can use it to avoid trying to get info for offline databases.  For example:

if ( $db.status -eq “Normal”) { #exclude offline databases
#do something

}

Index to Filegroup mapping

Here is a trivial script to show where a particular index resides. It saves clicking around the SSMS GUI.


SELECT i.name, i.type_desc, i. is_primary_key, i.is_unique, s.name AS [Filegroup]
FROM sys.indexes i
INNER JOIN sys.data_spaces s
ON i.data_space_id = s.data_space_id
WHERE i.name IS NOT NULL
AND
i.name NOT IN (‘clust’, ‘clst’, ‘nc1′, ‘nc2′, ‘nc3′, ‘nc’, ‘cl’)
ORDER BY s.data_space_id, i.name

Quick and Dirty CSV import to SQL Server

You can use LogParser (a free, unsupported utility from Microsoft) to quickly import a CSV file into a SQL Server table using syntax like this:

logparser “SELECT * INTO MyTable FROM d:\MyFile.csv” -i:csv -o:SQL -server:MyServer -database:MyDatabase -createTable:ON

There are many other uses for LogParser.  Two of the most common are analyzing Windows Event Logs and IIS logs. 

Getting data file space usage

Here is a simple query to get space usage by data file:

 SELECT 
   
a.FILEID

   
[FILE_SIZE_MB] CONVERT(decimal(12,2),ROUND(a.size/128.000,2
)), 
   
[SPACE_USED_MB] CONVERT(decimal(12,2),ROUND(FILEPROPERTY(a.name,'SpaceUsed')/128.000,2
)), 
   
[FREE_SPACE_MB] CONVERT(decimal(12,2),ROUND((a.size-FILEPROPERTY(a.name,'SpaceUsed'))/128.000,2
)) , 
   
NAME LEFT(a.NAME,24
), 
   
FILENAME LEFT(a.FILENAME,55

   
FROM dbo.sysfiles a 

Useful Multipliers

Multiply SQL database pages by 0.0078125 to get space in Megabytes
Multiply SQL database pages by 0.00000762939453125 to get space in Gigabytes

Here are a couple of examples of where this is useful:

This query uses a DMV to return TempDB utilization by object category such as user, internal, and version store:

SELECT
SUM(user_object_reserved_page_count)*0.0078125 as usr_obj_mb,
SUM
(internal_object_reserved_page_count)*0.0078125 as internal_obj_mb,
SUM(
version_store_reserved_page_count)*0.0078125  as version_store_mb,
SUM
(unallocated_extent_page_count)*0.0078125 as freespace_mb,
SUM
(mixed_extent_page_count)*0.0078125 as mixedextent_mb
FROM
sys.dm_db_file_space_usage 

The next query returns space utilization , in Megabytes, by filegroup:

select name, filename, cast(size * 0.0078125 as int)as size_mb
from sysfiles
ORDER
BY FILENAME
compute
sum(cast(size * 0.0078125 as int))

One-off backups in SQL Server 2005

I am frequently asked to refresh development databases with production data.  The usual way to do this is to  back up the production database and then restore over the development database.  SQL Server 2005 has a new backup option, “WITH COPY_ONLY”.   This option allows you to perform a full backup without truncating the log and breaking the log chain.  The COPY_ONLY option is not supported in the SQL Server Management Studio (SSMS) GUI, so you have to perform the backup via a script.

It’s important to note that a backup that is created with the COPY_ONLY option cannot be restored with the SSMS GUI.  Instead you have to restore via a script.

SQL Server 2008 supports the COPY_ONLY option in the SSMS GUI.

SQL Server “Max Server Memory” Config Value

I learned an interesting tidbit while reading Inside Microsoft SQL Server 2005: Query Tuning and Optimization.  The Max Server Memory configuration value applies to the cache buffer pool and not SQL Server as a whole.  Here is a link to an MSDN article that explains it:  http://msdn.microsoft.com/en-us/library/ms180797.aspx

This book goes on to discuss how to detect, measure, and remedy various forms memory pressure.  I followed some of the examples in the book and came up with these statistics on one server:

memory_stats1.html

One thing that is kind of interesting about these statistics is that it clearly shows that the configured server memory is significantly less than the memory used by sqlserver.exe.

Shrinking all log files

I’m not a big proponent of shrinking files. There are a lot of postings on DBA forums citing why this practice should be avoided. However we have a development server with a lot of databases, and the log files need to be shrunk on a pretty regular basis.

I wrote a little query to dynamically build the list of databases and logical filenames and then run DBCC SHRINKFILE to shrink all the log files. Here’s the script:

SET nocount ON;
CREATE TABLE #tempFileInfo
(
  dbName VARCHAR(256),
  logicalName VARCHAR(256),
)

DECLARE @DBName VARCHAR(256)
DECLARE @SQL VARCHAR(MAX)

DECLARE CursorDB CURSOR FOR
SELECT [name] FROM sys.databases WHERE database_id > 4 AND state_desc = ‘ONLINE’
OPEN CursorDB

FETCH NEXT FROM CursorDB INTO @DBName
WHILE @@FETCH_STATUS = 0
  BEGIN
    SET @DBName = ‘[’ + @DBName + ‘]’
    SET @SQL = ’select ‘ + CHAR(39) + @DBName + CHAR(39) + ‘, [name] from ‘ + @DBName + ‘.sys.sysfiles WHERE filename LIKE ‘+ CHAR(39) + ‘%ldf’ +CHAR(39)
    –print @SQL
    INSERT INTO #tempFileInfo
    EXEC (@SQL)
    FETCH NEXT FROM CursorDB INTO @DBName
  END
CLOSE CursorDB
DEALLOCATE CursorDB

SET @SQL = ”
SELECT @SQL=COALESCE(@SQL,”)+ ‘USE ‘ + dbName + ‘ DBCC SHRINKFILE(’ + CHAR(39) + logicalName + CHAR(39) + ‘, 1); ‘
FROM #tempFileInfo

PRINT @SQL
EXEC(@SQL)

DROP TABLE #tempFileInfo

Stripping the time component from a datetime value

Here is a very simple and elegant way to strip the time component from a datetime value:

CAST(FLOOR(CAST(@date AS float)) AS datetime)

Written as a function:

CREATE FUNCTION BareDate
(
– Add the parameters for the function here
@date datetime
)
RETURNS datetime
AS
BEGIN
RETURN
CAST(FLOOR(CAST(@date AS float)) AS datetime)
END
GO

When we pass in the value ‘2008-02-12 13:25:33.3′, it returns the value 2008-02-12 00:00:00.000

Other ways of stripping the time component:

SELECT DATEADD(dd,(DATEDIFF(dd,0,backup_start_date)),0)

or:

SELECT CAST(DATEDIFF(dd,0,backup_start_date) AS Datetime)Using the convert has performance issues.  I’ll have to come up with numbers for all these: or

SELECT CONVERT(Datetime, CONVERT(NCHAR(10), backup_start_date, 121))

Partition Misalignment can Cause Poor Performance

Here is an interesting Microsoft Knowledgebase article titled Disk performance may be slower than expected when you use multiple disks in Windows Server 2003, in Windows XP, and in Windows 2000.

It explains how a partition misalignment can cause significant I/O by causing reads and writes to straddle track boundaries. The fix is to use the diskpart.exe utility to create an alignment offset when you first create the partition.

This is similar to what you do with SAN storage to align the starting offset to “significant” boundaries. See the 3/31/08 post for more details.

Basic Database Inventory Script

/*
Name: Inventory.sql
Description: Second stab at inventory using systables
Author: Bennett Scharf
Compatibility: SQL Server 2005
*/
USE master
CREATE TABLE #tempresults
(
[name] sysname,
db_size NVARCHAR(13),
[owner] sysname,
[dbid] smallint,
created NVARCHAR(11),
[status] NVARCHAR(600),
compatibility_level tinyint
)
CREATE TABLE #tempresults2
(
database_name NVARCHAR(128),
backup_start_date datetime
)
INSERT INTO #tempresults
EXEC sp_helpdb
INSERT INTO #tempresults2
SELECT database_name, backup_start_date
FROM msdb.dbo.backupset AS b1
WHERE backup_start_date =
(
SELECT MAX(backup_start_date)
FROM msdb.dbo.backupset AS b2
WHERE b1.database_name = b2.database_name
AND type = ‘D’
)
SELECT db.name, tr.db_size, db.compatibility_level,is_auto_shrink_on,
state_desc, recovery_model_desc, page_verify_option_desc,
tr2.backup_start_date AS ‘last backup’
FROM sys.databases db
JOIN #tempresults tr
ON db.name =tr.name
LEFT OUTER JOIN #tempresults2 tr2
ON db.name = tr2.database_name
WHERE db.database_id >4 –This clause will exclude system DBs,master, model, msdb, and tempdb
ORDER BY db.name
DROP TABLE #tempresults
DROP TABLE #tempresults2

Query to get last database backup dates

Here’s a simple query to find the last backup dates:

 

SELECT backup_start_date, database_name
FROM msdb.dbo.backupset AS b1
WHERE backup_start_date =
(
SELECT MAX(backup_start_date)
FROM msdb.dbo.backupset AS b2
WHERE b1.database_name = b2.database_name
AND type = ‘D’
)

SQL Server Best Practices Analyzer (BPA)

A new version of the SQL Server 2005 Best Practices Analyzer (BPA) is here.

On a related note, the BPA reported several operating system issues that I was unaware of, including an issue where SQL Server’s working set gets paged to disk during large file copies. More info and a link to the Technet article discussing this issue can be found here.

First stab at a database inventory script

Compatible with sql server 2k5:

USE master
CREATE TABLE #tempresults
(

[name] sysname,
db_size NVARCHAR(13),
[owner] sysname,
[dbid] smallint,
created NVARCHAR(11),
[status] NVARCHAR(600),
compatibility_level tinyint

)
INSERT INTO #tempresults
EXEC sp_helpdb
SELECT db.name, tr.db_size, db.compatibility_level,is_auto_shrink_on, state_desc, recovery_model_desc, page_verify_option_desc

FROM sys.databases db
JOIN #tempresults tr
ON db.name =tr.name

WHERE dbid >4 –This clause will exclude system DBs,master, model, msdb, and tempdb
ORDER BY db.name
DROP TABLE #tempresults

Code Prettifier

I found an easy way to render code snippets in HTML. It is called the Simple Talk Code Prettifier. In addition to rendering, it also converts SQL keywords to uppercase and gives you proper indentation.  Also supports VB.  http://www.simple-talk.com/prettifier/default.php

By the way, the Simple Talk blog http://www.simple-talk.com is pretty cool.  My puny effort here pales by comparison.

Searching for a column name in a SQL database

Here are a couple of different ways to search for a column name within a SQL Server database:

– using information_schema views (preferred method)

SELECT sc.table_name
  
FROM information_schema.columns sc
  
INNER JOIN information_schema.tables st
    
ON sc.table_name = st.table_name
  
WHERE st.table_type = ‘base table’
  
AND sc.column_name = ‘ColumnToFind’
  
ORDER BY sc.table_name

– old school
SELECT name
  
FROM sysobjects
  
WHERE id IN
  
(
     
SELECT id
       
FROM syscolumns
       
WHERE name = ‘ColumnToFind’ )
        AND
xtype = ‘U’
       
ORDER BY name

Changing database modes via systables

Script to change SQL Server database modes via systables. This lets you set modes, such as EMERGENCY, that cannot be set via the sp_dboption stored procedure.

– change database mode via systables
USE Master
GO
– Determine the original database status
SELECT [Name], DBID, Status
 
FROM master.dbo.sysdatabases
GO
– Enable system changes
sp_configure ‘allow updates’,1
GO
RECONFIGURE WITH OVERRIDE
GO
– Update the database status
UPDATE master.dbo.sysdatabases
  
SET Status = 16
    
WHERE [Name] = ‘DatabaseNameGoesHere’
GO
– Disable system changes
sp_configure ‘allow updates’,0
GO
RECONFIGURE WITH OVERRIDE
GO
– Determine the final database status
SELECT [Name], DBID, Status
  
FROM master.dbo.sysdatabases
GO

/*Modes

1 = autoclose; set with sp_dboption.
4 = select into/bulkcopy; set with sp_dboption.
8 = trunc. log on chkpt; set with sp_dboption.
16 = torn page detection, set with sp_dboption.
32 = loading.
64 = pre recovery.
128 = recovering.
256 = not recovered.
512 = offline; set with sp_dboption.
1024 = read only; set with sp_dboption.
2048 = dbo use only; set with sp_dboption.
4096 = single user; set with sp_dboption.
32768 = emergency mode.
4194304 = autoshrink.
1073741824 = cleanly shutdown.

Note that these are bit values. For example, 24 = 8+16, so 24 means that truncate log on checkpoint AND torn page detection
are both set.
*/

 

Script to Return Space Used for All Tables in a Database

Here’s a handy script to return space used by table:  spaceused.html

Troubleshooting SQL Server with Filemon

Today I came across an interesting problem while changing the SQL server service to run on a non-administrative domain account. Previously the service was configured to log in as localsystem, which has full rights locally, but no domain rights. With this change, the service would start and then terminate. Here is a SQL error log snippet:

2007-02-13 15:05:01.29 spid5 Clearing tempdb database.
2007-02-13 15:05:01.58 spid5 Encountered an unexpected error while checking the sector size for file ‘k:\mssql\MSSQL\data\tempdb.mdf’. Check the SQL Server error log for more information.
2007-02-13 15:05:01.62 spid11 Starting up database ‘Student’.
2007-02-13 15:05:01.72 spid10 Starting up database ‘Diners’.
2007-02-13 15:05:01.80 spid9 Starting up database ‘distribution’.
2007-02-13 15:05:02.10 spid8 Starting up database ‘Inventory’.
2007-02-13 15:05:02.72 spid11 Starting up database ‘NorthwindReportData’.
2007-02-13 15:05:02.80 spid10 Starting up database ‘TSQLDB’.
2007-02-13 15:05:02.83 spid9 Starting up database ‘SSEMDB’.
2007-02-13 15:05:03.57 spid5 CREATE DATABASE failed. Some file names listed could not be created. Check previous errors.
2007-02-13 15:05:03.57 spid5 WARNING: problem activating all tempdb files. See previous errors. Restart server with -f to correct the situation.

Making the service account a member of the administrators group, fixed the problem, but of course this is not a good idea. I decided to use the SysInternals File Monitor, filemon.exe, to see if I could find the cause of the problem. What I found was that mssql.exe was trying to access the root of the volume where the SQL data files exist and was getting an access denied error. The fix was to grant the service account list access to the root of that volume. With that change, the sqlserver.exe service came up and stayed up. I also found a Technet article that points to the same solution for a similar problem: PRB: Error 5177 May Be Raised When Creating Databases

By the way, SysInternals was recently acquired by Microsoft and Mark Russinovich is now a Microsoft Employee. It appears that the great SysInternals utilities continue to be maintained.

|