Latest Backups with TSQL

After rebooting a SQL Server, for whatever reason, it is always good to confirm that the system is running good.  There are many things that I check, one of which is to confirm that backups are running.

You can always go to the server browse to the various directories holding backups, and check on the latest files.  This can be difficult for servers with many databases.

Here is my quick check to confirm which backups are running on SQL Server. The query below gives you the 20 most recent backups that have been run.

SELECT TOP 20 database_name,
              type,
              backup_start_date,
              backup_finish_date,
              compressed_backup_size,
              backup_size
FROM   msdb.dbo.backupset
ORDER  BY backup_set_id DESC; 

In order to get the exact results you are looking for it may require you to add a where clause to filter on specific databases, or to expand the number of results in the TOP statement.

I hope that you find this as useful as I do.

Determining free disk space with TSQL

Working on a new report for the SQL Server Health reports, I needed to display the amount of free disk space on a SQL Server.

EXEC MASTER..Xp_fixeddrives;

Which was useful if I just wanted to look, but I needed to use the results in a query, and I didn’t want to put the results into a temp table, so here is how I decided to do it, using table variables.

 

DECLARE @disk_space TABLE(drive CHAR(1) NOT NULL, free INTEGER NOT NULL)
INSERT INTO @disk_space
EXEC MASTER..Xp_fixeddrives;

SELECT drive,
CAST(free* 10 / 1024 AS FLOAT) / 10 AS gbfree
FROM @disk_space
ORDER BY gbfree ASC;

With this, I am now about to query the @disk_space table variable and join it with other tables in the database.

New – SQL Server Health report

Over the last couple of weeks I have taken a couple of the common queries that I use to analyze the health of a SQL Server and built them out into a SQL Server 2008 SSRS report.

I have decided to make this report available to anyone who want to run it.

The SQL Server Health report is available to download.  Try it out and let me know what you think.

MSG 128, Level 15, State 1 – not permitted in this context

Default Values and Computed Columns

In SQL Server 2008, I was presented with the following error when attempting to create a table that has a default value that references other columns in the same table.

Msg 128, Level 15, State 1, Line 6 The name "Subtotal" is not permitted in this context. Valid expressions are constants,  constant expressions, and (in some contexts) variables. Column names are not permitted.

 

The following CREATE TABLE throws the error.


CREATE TABLE orders (
[OrderId] INT IDENTITY,
[Subtotal] FLOAT,
[Tax] FLOAT,
[GrandTotal] FLOAT DEFAULT (subtotal + tax)
);

After looking it over, I realized that there are at least 2 other ways to fix this error.

  1. Use a computed column.
    • Advantages:  Easy to code, easy to follow, less disk space, less memory.
    • Disadvantages:  Slower because their values are recalculated every time they are referenced in a query.
  2. Use a PERSISTED computed Column
    • Advantages:  Easy to code, easy to follow.
    • Disadvantages:  Slows the insert or update.  Takes up more disk space.
  3. Use a trigger
    • Advantage: when the other columns are updated, the [GrandTotal] column gets updated.
    • Disadvantages: Triggers are often overlooked.  Slows the insert or update of that table.  Takes up more disk space and more memory.
Here is how I would do it if it wanted to keep things simple, using a computed column:


CREATE TABLE orders (
[OrderId] INT IDENTITY,
[Subtotal] FLOAT,
[Tax] FLOAT,
[GrandTotal] AS (subtotal + tax)  -- this is a computed column
);

INSERT INTO orders (subtotal, tax)
VALUES (10.30, 1.4),
(100.79, 18.2);

SELECT * FROM orders;

 

Which will produce the following output.

OrderId     Subtotal               Tax                    GrandTotal
----------- ---------------------- ---------------------- ----------------------
1           10.3                   1.4                    11.7
2           100.79                 18.2                   118.99

(2 row(s) affected)

The one additional thing I would do is add the PERSISTED parameter to the computed column.


CREATE TABLE orders (
[OrderId] INT IDENTITY,
[Subtotal] FLOAT,
[Tax] FLOAT,
-- persist the calculation
[GrandTotal] AS (subtotal + tax)  PERSISTED
);

INSERT INTO orders (subtotal, tax)
VALUES (10.30, 1.4),
(100.79, 18.2);

SELECT * FROM orders;

Which will produce the following output.

OrderId     Subtotal               Tax                    GrandTotal
----------- ---------------------- ---------------------- ----------------------
1           10.3                   1.4                    11.7
2           100.79                 18.2                   118.99

(2 row(s) affected)

SQL Server 2008 R2 Compatibility Levels

There was no change to the compatibility levels between SQL Server 2008 and SQL Server 2008 R2.

SQL Server can run in a number of different compatibility levels, but how do you change it and how do you set it. These compatibility levels reflect the version of SQL server.

  • 60 = SQL Server 6.0
  • 65 = SQL Server 6.5
  • 70 = SQL Server 7.0
  • 80 = SQL Server 2000
  • 90 = SQL Server 2005
  • 100 = SQL Server 2008 and SQL Server 2008 R2

Changing the compatibility level in SQL Server may change the behavior of specific of the functionality of the SQL Server. Be sure to research and test before changing compatibility levels.

Here is a sample script that will show you the current compatibility level, set it to 100, then show you the current level after it has been set.

Sp_dbcmptlevel dbname
GO
Sp_dbcmptlevel dbname, 100
GO
Sp_dbcmptlevel dbname
GO

This TSQL will generate the following output:

The current compatibility level is 90.
The current compatibility level is 100.

Once you change the compatibility level, you will want to be sure that your system still runs correctly.

Query SQL Server 2008 Total Memory Usage

The quick and easy way to determine how much memory your SQL Server is using is to look at the Task Manager on the server and find “sqlservr.exe” in the process list, and look at the “Mem Usage” column.

But what if you are not on the server, or if you want to grab this information programmatically from an application, it is not so obvious.  After 15 different Google queries, and many articles saying to just use DBCC MEMORYSTATUS, I finally tracked it down.

The problem with DBCC MEMORYSTATUS, is that it returns nearly 500 values about every aspect of memory possible on the SQL Server.

I finally discovered that if I take all of the output from DBCC MEMORYSTATUS, and insert it into a temporary table, I can then query for the one line of information that I need.  The total memory used, that matches what the task manager shows is called “Working Set”.   The following query returns the same memory usage numbers as the task manager shows.

CREATE TABLE #tmp
( row_id INT IDENTITY PRIMARY KEY,
name VARCHAR(100),
VALUE BIGINT );

INSERT INTO #tmp EXEC ( 'DBCC memorystatus' );

SELECT TOP 1 name, VALUE / 1024 'KBUsed'
FROM #tmp
WHERE Rtrim(Ltrim(name)) = 'Working Set';

DROP TABLE #tmp;

 

From here I was able to call this from my C# code as follows:  (conn is of type SqlConnection and was already open and connected).

// get the total memory used by the SQL Server
SQLStatement = @"CREATE TABLE #tmp
( row_id INT IDENTITY PRIMARY KEY, name VARCHAR(100), value BIGINT );
INSERT INTO #tmp EXEC ( 'DBCC MEMORYSTATUS' );
SELECT top 1 value / 1024 'KBUsed'
FROM #tmp
WHERE RTRIM(LTRIM(name)) = 'Working Set';
DROP TABLE #tmp;";

SQLDataAdapter = new SqlDataAdapter(SQLStatement, conn);
dtResult = new DataTable();

SQLDataAdapter.Fill(dtResult);

foreach (DataRow drRow in dtResult.Rows)
{
tbServerMemory.Text = drRow["KBUsed"].ToString();
}
SQLDataAdapter.Dispose();

This gives you a quick way to check the amount of memory being used by the SQL Server without being on the server or using the Task Manager.