📜 ⬆️ ⬇️

AUTO_CLOSE

If SQL Server existed at the time of the Inquisition, then for the inclusion of some options on the production servers would have to be punished with a hot iron. But if we discard the lyrics, then we’ll look at why we don’t need to turn on AUTO_CLOSE and what the use of this option may cause

Actually, like any interesting life stories, it all began with a routine task.

The other day I had to look into the Error Log on a test server. In the second minute of waiting, SSMS pretty poplohlo from the abundance of messages that kept the magazine, and I decided to see how much the logs weigh using xp_enumerrorlogs :
')
DECLARE @t TABLE (lod_id INT PRIMARY KEY, last_log SMALLDATETIME, size INT) INSERT INTO @t EXEC sys.xp_enumerrorlogs SELECT lod_id, last_log, size_mb = size / 1048576. FROM @t 

 lod_id last_log size_mb -------- --------------------- --------------- 0 2016-01-05 08:46:00 567.05288505 1 2015-12-31 12:53:00 1370.39249420 2 2015-12-18 11:32:00 768.46394729 3 2015-12-02 13:54:00 220.20050621 4 2015-12-02 13:16:00 24.04152870 5 2015-11-16 13:37:00 80.07946205 6 2015-10-22 12:13:00 109.33527946 

As a rule, I try not to deal with the log size on test servers, because every time SQL Server starts, the log files change cyclically: the current errorlog is renamed to errorlog.1 , an empty errorlog file is created and the oldest errorlog.6 is deleted.

In the case when it is necessary to clear the logs, sp_cycle_errorlog can come to the rescue . But before clearing the journals, I still wanted to understand that they contained such interesting things.

Made a read from the current log using the xp_readerrorlog stored procedure:

 EXEC sys.xp_readerrorlog 

And then my peripheral vision caught the eye of numerous messages:

 Starting up database '...'. 

On the one hand, there is nothing wrong with that. Each time SQL Server starts, it opens the data files and checks the boot page:

 Starting up database '...'. CHECKDB for database '...' finished without errors on ... (local time). 

But after I filtered by the desired post, the sample results made me think:

 DECLARE @t TABLE (log_date SMALLDATETIME, spid VARCHAR(50), msg NVARCHAR(4000)) INSERT INTO @t EXEC sys.xp_readerrorlog 0, 1, N'Starting up database' SELECT msg, COUNT_BIG(1) FROM @t GROUP BY msg HAVING COUNT_BIG(1) > 1 ORDER BY 2 DESC 

 ------------------------------------------------------ -------------------- Starting up database 'AUTOTEST_DESCRIBER'. 127723 Starting up database 'MANUAL_DESCRIBER'. 12913 Starting up database 'AdventureWorks2012'. 12901 

A large number of such messages may occur due to the inclusion of the AUTO_CLOSE option .

According to the documentation, when the AUTO_CLOSE option is enabled, the database will automatically close and release all the resources it occupies when the last user connection using this database ceases to exist. When you re-apply the database will automatically re-open ... and so on to infinity.

Once upon a time I read that at the physical level, the AUTO_CLOSE operation for older versions of SQL Server was a completely synchronous process that could cause large delays with constant reopening of the database files. Starting with SQL Server 2005 , AUTO_CLOSE became asynchronous and some of the problems were gone. And what's left? Just enough to not use this option ...

To optimize performance, SQL Server performs page changes in the buffer cache and does not write these pages to disk after each modification. Instead, SQL Server periodically creates a checkpoint on which it writes the current pages that have been modified in memory, along with the transaction log information from memory to disk. When you close the database, CHECKPOINT is automatically executed. Accordingly, with constant DB closures, the disk load can greatly increase.

Also, each time the database is closed, its procedural cache is cleared. Accordingly, when the database reopens, you will have to generate execution plans for the new one. But what is even sadder ... when closing, the buffer cache is also cleared, which increases the disk load when executing queries.

Microsoft is solidary with me and also does not recommend including AUTO_CLOSE :

There is a possibility for your team to go ahead and you’ll be able to complete the database after each connection. AUTO_CLOSE also flushes the procedure cache after each connection.

However, there are a couple of nuances. If you are using SQL Server 2000 or any Express edition, then when creating a new database, the AUTO_CLOSE option will implicitly turn on:

 USE [master] GO IF DB_ID('test') IS NOT NULL DROP DATABASE [test] GO CREATE DATABASE [test] GO SELECT is_auto_close_on FROM sys.databases WHERE database_id = DB_ID('test') 

 is_auto_close_on ---------------- 1 

Bravo Microsoft ! Standing ovations ...

Although, if you look at it from the other side, this behavior is quite understandable for SQL Server Express , because within this edition there is a limit on the size of the RAM used - no more than 1 GB.

But for the future, if you suddenly need to deploy the database using a script, it is better to be safe and explicitly disable AUTO_CLOSE :

 ALTER DATABASE [test] SET AUTO_CLOSE OFF 

In the course of work, I noticed another interesting point - when accessing some functions or system views, all databases with the AUTO_CLOSE option enabled will open:

 USE [master] GO IF DB_ID('p1') IS NOT NULL DROP DATABASE [p1] GO CREATE DATABASE [p1] GO ALTER DATABASE [p1] SET AUTO_CLOSE ON GO IF DB_ID('p2') IS NOT NULL DROP DATABASE [p2] GO CREATE DATABASE [p2] GO ALTER DATABASE [p2] SET AUTO_CLOSE ON GO EXEC sys.xp_readerrorlog 0, 1, N'Starting up database ''p' GO 

 LogDate ProcessInfo Text ----------------------- ------------ ---------------------------------- 2016-01-25 17:36:40.310 spid53 Starting up database 'p1'. 2016-01-25 17:36:41.980 spid53 Starting up database 'p2'. 

We refer to p1 :

 WAITFOR DELAY '00:03' GO SELECT DB_ID('p1') GO EXEC sys.xp_readerrorlog 0, 1, N'Starting up database ''p' 

But p2 also wakes up "for the company":

 LogDate ProcessInfo Text ----------------------- ------------ ---------------------------------- 2016-01-25 17:36:40.310 spid53 Starting up database 'p1'. 2016-01-25 17:36:41.980 spid53 Starting up database 'p2'. 2016-01-25 17:39:17.440 spid52 Starting up database 'p1'. 2016-01-25 17:39:17.550 spid52 Starting up database 'p2'. 

And finally, we got to the bottom of the truth. On the server, various users actively accessed metadata ... this made the databases wake up with AUTO_CLOSE enabled, which in turn implicitly caused the log to grow.

Preventive measures, by the way, came out very simple:

 DECLARE @SQL NVARCHAR(MAX) SELECT @SQL = ( SELECT ' ALTER DATABASE ' + QUOTENAME(name) + ' SET AUTO_CLOSE OFF WITH NO_WAIT;' FROM sys.databases WHERE is_auto_close_on = 1 FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') EXEC sys.sp_executesql @SQL 

Everything was tested on Microsoft SQL Server 2012 (SP3) (KB3072779) - 11.0.6020.0 (X64).

If you want to share this article with an English-speaking audience:
Enabling AUTO_CLOSE is a bad idea?

Source: https://habr.com/ru/post/275873/


All Articles