Category: SQL

Could not open file E:\TempDB\tempdb.mdf for file number 1. OS error: 32(The process cannot access the file because it is being used by another process.)

Recently we faced an issue that SQL Server was not coming up online in one of our environment.

We found below error messages in Windows application event logs:

Open failed: Could not open file E:\TempDB\tempdb.mdf for file number 1. OS error: 32(The process cannot access the file because it is being used by another process.).
Unable to open the physical file "E:\TempDB\tempdb.mdf". Operating system error 32: "32(The process cannot access the file because it is being used by another process.)".
CREATE DATABASE failed. Some file names listed could not be created.

As we have a clear message, while SQL Service starts, it was not able to create the TEMPDB as the mdf file is being used by another process.
When it happens, it will not start the SQL Service even we manually start it through services.msc. However, we identified, the service will come online once we restart the server.

We started our investigation verifying whether more than one instances are pointing to the same directory for TEMPDB files. Though we have multiple instances on the environment, we made it sure those instances are configured separately and properly. Once we confirmed the SQL Server configuration, we took our attention to other services especially with AntiVirus services. We found that there is Mcafee software running, but unfortunately, we could not find any reference on ProcessExplorer as well. However, we decided to stop the McAfee and see if the issue is related to the AnitVirus scan. Now, it is almost more than two weeks and we did not experience the issue.

Takeaway, if you find similar issue, Instead of disabling or stopping the services related Antivirus, we can exclude certain files associated with SQL Server from the scan.

Here are few directories that can be excluded from anti-virus scanning tool:

1. C:\Windows\System32\LogFiles
2. C:\Windows\System64\LogFiles
3. C:\windows\System32\GroupPolicy\
4. C:\windows\temp
5. C:\windows\SoftwareDistribution\Datastore
6. C:\windows\SoftwareDistribution\Datastore\Logs
7. C:\\Temporary ASP.NET Files
8. C:\Users\\AppData\Local\Temp
9. C:\Users\Default\AppData\Local\Temp
10. C:\ProgramData\Microsoft\SQL Server
11. C:\Program Files\Microsoft SQL Server
12. Exclude SQL Server Data Files (*.MDF, *.LDF, *.NDF)
13. Exclude SQL Server Backup Files (*.TRN, *.BAK)
14. Exclude Full-Text Catalog Files (*.SLS)
15. Exclude sqlmangr.exe
16. Exclude sqlservr.exe

Please give your feedback if this post helps you!!!

Memory optimized Temporary table in SQL Server

Today, we will quickly see how do we create memory optimized temporary table in SQL Server and how to use it efficiently.

I would recommend to read previous blogs before we continue further:
In-Memory OLTP and Memory Optimized data filegroup in SQL Server 2014
In-Memory OLTP: Compatibility Check for Datatypes in SQL Server
In-Memory OLTP: Compatibility Check for SQL Server and Database

Before we start the technical aspect, let us be clear why do we need memory optimized temp tables in SQL Server. Temp tables are very powerful objects in SQL server which is created in TEMPDB. These tables are, as name mentioned, created for a short live may be a for a batch scope, procedure scope etc. With in the scope, we can use the temp tables multiple times. So, many developers would use these objects to populate the data as required for thier operations and use these objects instead of querying the original physical table. Not to wonder, now days, the usage of temp tables are more and many is thinking its a free tool 🙂 .

But, on flip side, as we create huge number of tables, there is also a performance imapct in the system. There is only one database “TempDB” per instance where SQL Server would need to create these temp objects and do the oprations. So, it is observed there are some serious performance issues with tempDB at times. I am not covering tempdb performance issuesin this blog, but introduce memory optimized temp tables introduced in SQL Server 2014 which we can efficiently replace with normal temp objects to avoid performance issues.

Lets get into Techinical now –

Here is a sample example of creating a physical table and a procedure.


Create Table T1 (PeopleID int Primary key, CourseID int)

Insert into T1 values(1,100),(2,100),(3,200),(4,200),(5,200),(6,300)
GO
Create procedure usp_Normalproc @CourseID int
As
Begin
	
	Create Table #TempTable(PeopleID int, CourseID int)

	Insert into #TempTable (PeopleID,CourseID)
		Select PeopleID,CourseID From T1 where CourseID=@CourseID
	
	Select * From #TempTable
End

Exec usp_Normalproc 100

Now, lets look at how we convert this temp table usage to memory optimized temp object in the procedure.

First, Lets create a memory optimized table as below:


Create Table TempTable(PeopleID int, CourseID int,
SpidFilter  SMALLINT    NOT NULL   DEFAULT (@@spid),  
INDEX ix_SpidFiler NONCLUSTERED (SpidFilter),  
 CONSTRAINT CHK_TempTable_SpidFilter  CHECK ( SpidFilter = @@spid ),)
 WITH  
        (MEMORY_OPTIMIZED = ON,  
            DURABILITY = SCHEMA_ONLY);

SpidFilter – is a new column introduced as part of conversion to identify the rows for the session created. This has been indexed for performance.
CHK_TempTable_SpidFilter – This a constraint to make sure the spid has been populated

As next step, We need to create a function as below which is used to filter data for session.


CREATE FUNCTION dbo.fn_SpidFilter(@SpidFilter smallint)  
    RETURNS TABLE  
    WITH SCHEMABINDING , NATIVE_COMPILATION  
AS  
    RETURN  
        SELECT 1 AS fn_SpidFilter  
            WHERE @SpidFilter = @@spid; 

Finally, we will create a security policy to filter the records from the temptable as per the session id its being used.


CREATE SECURITY POLICY dbo.TempTable_SpidFilter_Policy  
    ADD FILTER PREDICATE dbo.fn_SpidFilter(SpidFilter)  
    ON dbo.TempTable  
    WITH (STATE = ON);  

Once we set up memory optimzed table and filters, its time to change the procedure as below:


Alter procedure usp_MO_proc @CourseID int
As
Begin
	
	--Create Table #TempTable(PeopleID int, CourseID int)

	Insert into TempTable (PeopleID,CourseID)
		Select PeopleID,CourseID From T1 where CourseID=@CourseID
	
	Select * From TempTable

	Delete From TempTable 
End

It is very important to delete the data from the memory optimized table. On failing, this will create multiple records into memory optimized table if we re-run the procedure within the same session(please note that its very likely during testing).

Hope you enjoyed this blog, looking for your valuable feedback on the same.

SQL Server detected a logical consistency-based I/O error: incorrect checksum

Recently, we encountered an issue with a restored database stating the below error message:

Msg 824, Level 24, State 2, Line 28
SQL Server detected a logical consistency-based I/O error: incorrect checksum (expected: 0xafbb455a; actual: 0xaf9a455a).
It occurred during a read of page (1:310732) in database ID 161 at offset 0x00000097b98000 in file ‘F:\DATA1\database.MDF’.
Additional messages in the SQL Server error log or system event log may provide more detail.
This is a severe error condition that threatens database integrity and must be corrected immediately.
Complete a full database consistency check (DBCC CHECKDB).
This error can be caused by many factors; for more information, see SQL Server Books Online.

As the error message is pretty straight forward, a clear issue with some consistency (I/O error). And this has been even confirmed by running a DBCC CHECKDB. To resolve the issue, we decided to go with REPAIR_ALLOW_DATA_LOSS option as this is a lower environment issue. I personally do not recommend to use this option for production databases as there is a chance of data loss.


alter database <database>  SET single_user with rollback immediate 
dbcc checkdb('<database>',REPAIR_ALLOW_DATA_LOSS)
alter database <database>  SET multi_user with rollback immediate 

Before we do this option, just curious to understand the object being corrupted from the error message.

Using DM_DB_DATABASE_PAGE_ALLOCATIONS

The below code will give you information on the objects. Please note the below is supported only from SQL 2012 and later versions. For earlier version, you need to use DBCC PAGE commands.


SELECT DB_NAME(susp.database_id) DatabaseName,
OBJECT_SCHEMA_NAME(ind.object_id, ind.database_id) ObjectSchemaName,
OBJECT_NAME(ind.object_id, ind.database_id) ObjectName
FROM msdb.dbo.suspect_pages susp
CROSS APPLY SYS.DM_DB_DATABASE_PAGE_ALLOCATIONS(susp.database_id,null,null,null,null) ind
WHERE allocated_page_file_id = susp.file_id
AND allocated_page_page_id = susp.page_id

Later, we identified the issue is associated with backup and we took a fresh backup of the database and restored. It worked like a treat!!!

How to remove space in a column names of table in SQL Server

Here is a script to rename the column names to avoid the space(s) in the column name.


create table test_table([column test space] int)

select * From test_table

--Script to do the change in column name

Declare @SQL nvarchar(MAX)=''
Set @SQL =(
select ';EXEC sp_rename '''+ B.name+'.'+a.name +''', '''
+replace(a.name,' ','') +''', ''COLUMN'''  
from sys.columns A
Inner join sys.tables B on A.object_id = B.object_id and  
OBJECTPROPERTY(b.object_id, N'IsUserTable') = 1
where 
 system_type_id in 
(select system_type_id From sys.types ) and charindex(' ',a.name)!=0
FOR XML path(''))

print @SQL
/*exec( @SQL) This has been commented, verify the results and execute*/
--check the column names
select * From test_table
--Cleanup the table
Drop table test_table

ALTER DATABASE failed because a lock could not be placed on database ‘dbname’. Try again later.

Problem statement

As a DBA, you will be facing the error message “ALTER DATABASE failed because a lock could not be placed on database ‘dbname’. Try again later.” often for certain actions like taking database offline/setting single user etc.

Analysis

This is due to other processes locking your current operations.

Resolution

1. Find out the query which is blocking the current operation using the below query
Live monitoring query

2. Kill the process and take the database in SINGLE_USER

KILL 191 --session id from the first query related to the database
USE MASTER
ALTER DATABASE DB905 SET SINGLE_USER WITH ROLLBACK IMMEDIATE

3. Take the database offline

ALTER DATABASE db905 SET OFFLINE WITH ROLLBACK IMMEDIATE