Can’t Start SQL Server Due to Insufficient Memory

SQL Server loves memory and will take as much as you give it. Sometimes you may want to limit the amount of memory it can have. To do this, go into management studio, right click on the server, select properties, and select the memory tab. To limit the amount of memory it can have, set a value for Maximum Server Memory (in MB).

If you aren’t careful, you can set a value that is too low and SQL Server won’t be able to run. I recently did this on my local copy and had a hard time changing the setting again to a higher value as everything expects that SQL Server is running, and that you can simply change the configuration.

In my case, I had set the value to 128 MB and SQL Server kept showing an “insufficient memory” error in the windows event log and wouldn’t start.

If you find yourself in a similar predicament, here is how to get it working again.

Open a command prompt as an administrator. Find the install path of your version of the SQL Server engine. In my case it was “C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\Binn”.

Change to the directory:

Cd “C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\Binn”

Next, we want to start SQL Server with minimal configuration. This will start SQL Server in a minimal state and allow you to connect in management studio. To do this use the following:

Sqlservr.exe -f -s <instancename>

Open the server properties window and bump up the max memory limit.

Close the command prompt window to shut down SQL Server. Finally, go to SQL Server Configuration Manager and start the service like normal.

You should now be able to run the service as usual and connect.

Advertisement

View Running Queries by CPU Time

If you have ever done performance tuning you know it can be a bit of an art and you need your detective hat on. I was recently working on a server that was performing poorly. After looking at resource monitor it was clear that the CPU usage was unusually high. As it turns out SQL Server was utilizing most of the CPU. The hunt was on. I grabbed my magnifying glass and followed the trail. While I could run sp_who2 to find some relevant info, I instead ran the query below. sys.dm_exec_requests returns information about each request that is executing within SQL Server. sys.dm_exec_sql_text returns the text of the SQL batch that is identified by the specified sql_handle.

-- check for queries running. sort by cpu time
SELECT a.session_id, db_name(a.database_id) as db_name, a.start_time, a.command, a.status, a.cpu_time, a.total_elapsed_time, a.reads, a.writes, b.text as query
FROM sys.dm_exec_requests a
OUTER APPLY sys.dm_exec_sql_text(a.sql_handle) b
WHERE a.session_id > 50 -- filter out background tasks
and a.session_id <> @@spid -- filter out this query session
order by a.cpu_time desc

This query shows open queries sorted in descending order by CPU time. I was able to nab a few culprits in the act. I copied the queries to new windows and checked the execution plans. After some intense interrogation it was clear that several tables needed an index and the sub-queries should be turned into joins. Updates were put in place, and the CPU usage went way down. Case closed!

SSRS Divide by Zero

In SSRS you often have calculated fields that do division. To avoid having divide by zero errors, you may need to use IIF statements in the expression:
=IIF(Fields!column2.Value = 0, 0, Fields!column1.Value/Fields!column2.Value)
which means if the denominator is 0, show 0, otherwise show the calculated value.

Now for reasons unknown this only works if you are using integers. If you are using decimal values, then you will need to do some more work. The best approach I’ve seen is here, where Robert Bruckner provides a nice solution.

You would go to Report -> Report Properties -> Code and insert the following:

Public Function Divide(ByVal first As Double, ByVal second As Double) As Double
If second = 0 Then
Return 0
Else
Return first / second
End If
End Function

Now you can do the following in your expression:
=IIF(Fields!column2.Value = 0, 0, Code.Divide(Fields!column1.Value, Fields!column2.Value))

Property Owner is not available for Database

If a database becomes orphaned and has no database owner, you will get the following error message when you try to view the database properties in SSMS:

Cannot show requested dialog. (SqlMgmt)
Property Owner is not available for Database ‘[database]’. This property may not exist for this object, or may not be retrievable due to insufficient access rights.
(Microsoft.SqlServer.Smo)

You can use the following code to see orphaned databases.
SELECT databases.NAME AS DB_Name, server_Principals.NAME AS User_Name
FROM sys.[databases]
LEFT OUTER JOIN sys.[server_principals]
ON [databases].owner_sid = [server_principals].sid

To assign a new owner:
EXEC sp_changedbowner 'newuser'

If you get the following error message:

Msg 15110, Level 16, State 1, Line 1
The proposed new database owner is already a user or aliased in the database
.

Open up the user’s Login Properties window under Security\Logins and uncheck the Map checkbox for the database and click OK. Basically the code won’t assign them as the new owner because it thinks they are already associated with that database. Now run the sp_changedbowner command again and it will work.

Failed Job Steps That Didn’t Notify An Operator

I often use jobs that have numerous steps. One example would be a job that has some initial prep work, multiple steps that run similar code on separate databases for multiple stores, and then finally some cleanup steps. I break the job down to individual steps per store so that if one of the steps fails, they all don’t fail. To do this, go to the advanced tab of the job step properties and set the ‘On failure action:‘ to ‘Go to the next step’. This allows the job to continue processing if there is an error on one of the steps. However, now it raises the question of how do we know if a step failed within a job? Unfortunately Microsoft doesn’t have built in failure notification for steps like they do with the overall job. You can view the job’s history and see if a step failed by the yellow icon, but that is not practical to check every day especially if you have multiple jobs setup this way. A better solution is to use the code below which shows jobs that recently had failed steps and did not notify an operator. It can be handy to setup in a SSRS report to keep an eye on all of your jobs that had failed steps.

-- FAILED JOB STEPS THAT DIDN'T NOTIFY AN OPERATOR VIA EMAIL
USE msdb
GO

DECLARE @DateStringToday VARCHAR(8);
DECLARE @DateStringYesterday VARCHAR(8);

SET @DateStringToday = convert(varchar, getdate(), 112);
SET @DateStringYesterday = convert(varchar, getdate()-1, 112);

SELECT
job_name = sj.name,
sj.enabled,
sjh.step_id,
sjh.step_name,
sjh.sql_message_id,
sjh.sql_severity,
sjh.message,
sjh.run_status,
sjh.run_date,
sjh.run_time,
sjh.run_duration,
operator_emailed = so.name

FROM msdb.dbo.sysjobhistory as sjh
INNER JOIN msdb.dbo.sysjobs_view sj ON sj.job_id = sjh.job_id
LEFT OUTER JOIN msdb.dbo.sysoperators so ON (sjh.operator_id_emailed = so.id)

WHERE sjh.run_status = 0
AND sjh.run_date IN(@DateStringToday, @DateStringYesterday) -- show today and yesterday
AND sj.enabled = 1 -- make sure it's enabled
AND sj.category_id != '101' -- remove SSRS report process jobs
AND so.name IS NULL -- show jobs that didn't already email an operator

ORDER BY sjh.run_date DESC, sjh.run_time DESC

Moving SQL 2000 Logins to SQL 2005

If you backup a database on one server and restore it to another, you can have the problem where the database has logins associated to it, but the instance does not. One problem, is that the database has a unique SID associated with the login name. If you create a new instance login with the same name, it will generate a different SID than the database one. I’ve read that if you are using 2005 and above, you simply create the new login for the instance and run the following to sync up the SID’s.
USE YourDatabaseName
GO
EXEC sp_change_users_login 'Update_One', 'UserName', 'UserName'
EXEC sp_change_users_login 'Auto_Fix', 'UserName'

However, in my case I was moving a database from SQL 2000 to SQL 2005 and these did not work.
The Update_One produced:
Msg 15063, Level 16, State 1, Procedure sp_change_users_login, Line 143
The login already has an account under a different user name.

What I had to do was:
1. Restore the database to the new server (SQL 2005)
2. Do NOT create a new login yet.
3. Run the following to find the unique SID associated to the database user account. Next we create a
new instance login with the same SID as the database account.

-- Look up the SID from the database
USE YourDatabaseName
GO

SELECT D.name AS [DB_LoginName], D.sid AS [DB_SID], S.name AS [Server_LoginName], S.sid AS [Server_SID]
FROM sys.database_principals AS D LEFT OUTER JOIN sys.server_principals AS S ON D.name = S.name

-- Next, take that SID and put it in here to create the login account
CREATE LOGIN UserName WITH PASSWORD = 'Password', SID = 0xB0A2667BAEDE1B4AB93EAA0F9525DD21

You can re-run the SELECT query to verify that they are indeed the same.

Renaming SQL Server

When you setup a server for replication you may find unexpectedly that SQL complains about your server name. The most likely reason is that the SQL Server name doesn’t match your machine name.
Run the following command to take a look:
SELECT @@SERVERNAME, SERVERPROPERTY(‘ServerName’)

The results should be identical. If they are different, you will need to rename your SQL Server name to match the machine name. To do this use the following:

use master
go
-- Remove old Server Name
exec sp_dropserver ‘OLDNAME’
GO
-- Add New Server Name
exec sp_addserver ‘NEWNAME’,’LOCAL’

You then need to restart SQL Server. Now open a new query and run the following again:
SELECT @@SERVERNAME, SERVERPROPERTY(‘ServerName’)
They should now be the same.

Fixing Torn Pages

Recently I was approached to help fix an accounting server problem. Now keep in mind I wasn’t managing this server and hadn’t touched it before. The DB was on SQL Server 2000. After attempting to reindex some tables it was apparent there were some serious issues. Looking in the server’s Event Viewer, the Application Log showed the following:

Error: 823, Severity: 24, State: 2 I/O error (torn page) detected during read at offset 0x00000z030b0000 in file ‘D:\dbFileName.MDF’

This means there were some corruption issues. Reading a lot of posts on the web, people said it wasn’t possible to fix and should just restore from the last backup. Now suppose there wasn’t a good backup to restore from… let’s just PRETEND that could happen. :/

Here is what I did to FIX the server. There were 944 tables on their database. I detached the DB and copied it to a SQL 2005 server and re-attached. In management studio I did a properties on the DB and went to options. I changed the Compatibility level to SQL Server 2005 (90). Then right clicked the DB, Reports, Standard Reports, Disk Usage by Top Tables. This gave me a report of the tables most used. Turns out There were only about 25 tables with a significant amount of data.

I then did a DBCC CHECKTABLE (“tablename”) on the top 25 and found out which ones had issues. I had 21 that needed to be fixed. Now off of to fix them.

Back on the SQL 2000 server I right clicked on the DB, All Tasks, Generate SQL Script, Options, and checked everything, General Tab, Preview. I copied this to a separate text file and saved it for later.

I renamed the corrupt database to something else. I did this by detaching the DB, and reattached using a new name. I then took my DB script and ran select portions to recreate the shell for the clean DB with the original name. I right clicked the corrupt database and selected All Tasks, export data. The trick is to copy all the data and objects from the old database to the new one. On the specify Table Copy or Query screen choose the 3rd option of Copy objects and data between SQL Server databases. This will take all the data and indexes and put it into the new database. After everything is copied and verified, you can eventually detach the corrupt DB and delete the files.

It’s been a week now and the accounting system is working great.

What causes torn page errors?
If the TORN_PAGE_DETECTION option is turned on, it flips a bit for each 512-byte sector written to disk. This allows SQL Server to detect incomplete I/O operations caused by power failures or other system outages. A torn page can occur if the system crashes between the time the operating system writes the first 512-byte sector to the disk and the completion of the I/O operation. If the actual value read from disk is different than what’s stored in the page header, it results in a torn page error.

If you are using SQL 2005 you can run the following query which shows pages suspected as being bad with an 823 or 824 error:

USE msdb
GO
SELECT * FROM dbo.suspect_pages