How can I disable autogrowth in SQL Server wide - sql-server

I have a database server that some databases with restricted users are in use in the database. I need to restrict users to can't change .MDF and .LDF autogrowth settings. Please guide me to restrict the users.
I think there is two way to get this access:
Disable autogrowth in databases
Limit the maximum size of MDF and LDF
But I couldn't find any option in Management Studio to do them server wide and also get access from users.
Thanks.

you can execute following ALTER DATABASE command which sets auto growth option to off for all databases using undocumented stored procedure sp_Msforeachdb
for single database (Parallel Data Warehouse instances only)
ALTER DATABASE [database_name] SET AUTOGROW = OFF
for all databases
EXEC sp_Msforeachdb "ALTER DATABASE [?] SET AUTOGROW = OFF"
Although this is not a server variable or instance settings, it might help you ease your task for updating all databases on the SQL Server instance
By excluding system databases and for all other databases, following T-SQL can be executed to get list of all database files and output commands prepared can be executed
select
'ALTER DATABASE [' + db_name(database_id) + '] MODIFY FILE ( NAME = N''' + name + ''', FILEGROWTH = 0)'
from sys.master_files
where database_id > 4
To prevent data files' autogrow property to be changed, I prepared below SQL Server DDL trigger once I used a DDL trigger for logging DROP table statements.
Following trigger will also prevent you to change this property, so if you need to update this property, you have to drop this trigger first.
CREATE TRIGGER prevent_filegrowth
ON ALL SERVER
FOR ALTER_DATABASE
AS
declare #SqlCommand nvarchar(max)
set #SqlCommand = ( SELECT EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)') );
if( isnull(charindex('FILEGROWTH', #SqlCommand), 0) > 0 )
begin
RAISERROR ('FILEGROWTH property cannot be altered', 16, 1)
ROLLBACK
end
GO
For more on DDL Triggers, please refer to Microsoft Docs

Related

Monitor when Database is created and receive an email

I created a trigger at the level of the server to control when a db is created.
I have this script that was working fine on SQL 2014, now we moved to SQL 2017, the script is working but I receive lot of emails
CREATE TRIGGER [ddl_trig_database]
ON ALL SERVER
FOR ALTER_DATABASE
AS
DECLARE #results NVARCHAR(max)
DECLARE #subjectText NVARCHAR(max)
DECLARE #databaseName NVARCHAR(255)
SET #subjectText = 'NEW DATABASE Created on ' + ##SERVERNAME + ' by ' + SUSER_SNAME()
SET #results = (SELECT EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)'))
SET #databaseName = (SELECT EVENTDATA().value('(/EVENT_INSTANCE/DatabaseName)[1]', 'VARCHAR(255)'))
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'EmailProfile',
#recipients = 'test#domain.com',
#body = #results,
#subject = #subjectText,
#exclude_query_output = 1 --Suppress 'Mail Queued' message
GO
I receive for example in different emails each of these lines:
ALTER DATABASE [testNewDB] SET DELAYED_DURABILITY = DISABLED
ALTER DATABASE [testNewDB] SET RECOVERY FULL
ALTER DATABASE [testNewDB] SET READ_WRITE
ALTER DATABASE [testNewDB] SET READ_COMMITTED_SNAPSHOT OFF
There are more so I believe the trigger is sending the info for each configuration parameter of the new db created, any idea how to receive only the info of the new DB created without all the rest?
You can replace ALTER_DATABASE with CREATE_DATABASE, but this will not catch a restore event because a restore does not generate a DLL event.
CREATE TRIGGER [ddl_trig_database]
ON ALL SERVER
FOR CREATE_DATABASE
AS
The following article covers a solution that will work around the missing DDL event:
DDL triggers enable us to audit DDL changes but there are a few
missing events, design decisions and installation complications. This
post explains and provides a full solution that includes auditing for
database restores (there is no DDL event for this) and an incremental
self install, which keeps the whole server audit configured for DDL
auditing.
https://www.sqlservercentral.com/forums/topic/sql-2008-ddl-auditing-a-full-self-installingupdating-solution-for-whole-server
The solution in the article for RESTORE events involves a job that runs to check for new databases:
SQL 2008 Audit RESTORE DATABASE
SQL Agent job which runs (in less than 1 second) every 1 minute to
copy new restore database auditing information from
msdb.dbo.restorehistory to dbadata.dbo.ServerAudit. If it finds that a
database restore has happened but has not been audited it
automatically runs the “Setup DDL Audit” job because there is a
possibility that the restored database is not configured for DDL
auditing as expected.

Change SQL mode from Single User to Multi-User for few or all bases

I have multiple databases to change mode from Single-User to Multi-User.
I can use this to change one database.
USE master;
GO
ALTER DATABASE CDN_Ceramika
SET MULTI_USER;
GO
Is it possible to change mode for few bases or any query, when mode will be change for Multi-User just when a mode is Single-User?
If you are new to database management I'd advise against using sys.sp_MSforeachdb. Despite being undocumented it's a very popular function among DBAs that know and quadruple-check what they're doing. This article explains some of its pitfalls.
It's generally safer to generate the command strings you want to execute with SQL, inspect them, fix any problems and execute the resulting script. Probably inside a transaction if appropriate.
As the article shows sp_MSforeachdb itself queries the sys.databases table. You can do the same, eg with :
select 'ALTER DATABASE [' + name + '] SET MULTI_USER;'
from sys.databases
where name not in ('master','tempdb','model','msdb')
To generate ALTER DATABASE for all the databases you want, whose names match the WHERE clause. You could also write :
select 'ALTER DATABASE [' + name + '] SET MULTI_USER;'
from sys.databases
where name not in ('master','tempdb','model','msdb')
and [user_access_desc] != 'MULTI_USER'
to exclude databases that are already in multi-user mode
You could use the undocumented system procedure sp_msforeachdb:
USE master;
EXEC sys.sp_MSforeachdb 'IF ''?'' NOT IN (''master'',''msdb'',''tempdb'',''model'') BEGIN
ALTER DATABASE ? SET MULTI_USER;
END;';
Right click on the database you wish to change, then click on Properties.
Click on Options and scroll down to the bottom, then set it as can be seen below:
Click OK and it will be set.

The specified schema name "sys" either does not exist or you do not have permission to use it

I needed Msforeach_table stored procedure which depends upon sys.MSforeach_worker (System) stored procedure.
I am following this source code to create stored procedure MSforeach_worker
The syntax here is for dbo and not for sys so I have changed it to sys.MSforeach_worker from dbo.MSforeach_worker
When I try to create in my Databases, i get this error
The specified schema name "sys" either does not exist or you do not
have permission to use it
And when I try to create it in master db, I get
CREATE PROCEDURE permission denied in database 'master'
I am confused where should I run this script to create System stored procedure in my SQL server.
I have googled but could not find solution to my problem.
First, don't use undocumented system stored procedures. These are not supported.
Second, if these undocumented procs don't already exist, you must be using Azure SQL Database. Azure SQL Database has a significantly different architecture with regards to separation of master and user databases. Rather than trying to port the procs, I suggest you create your own proc with the functionality you need. Below is an example.
CREATE PROC dbo.usp_ForEachTable
#SQL nvarchar(MAX)
AS
DECLARE
#SQLBatch nvarchar(MAX)
, #TableName nvarchar(261);
DECLARE tables CURSOR LOCAL FAST_FORWARD FOR
SELECT QUOTENAME(OBJECT_SCHEMA_NAME(object_id)) + '.' + QUOTENAME(name)
FROM sys.tables
WHERE is_ms_shipped = 0;
OPEN tables;
WHILE 1 = 1
BEGIN
FETCH NEXT FROM tables INTO #TableName;
IF ##FETCH_STATUS = -1 BREAK;
SET #SQLBatch = REPLACE(#SQL, N'?', #TableName);
EXEC sp_executesql #SQLBatch;
END;
CLOSE tables;
DEALLOCATE tables;
GO

How to adjust Compatibility Level after database restore?

We have a few SQL servers. with different version i.e. 2005, 2008, 2012, 2014. (we plan to move away from 2005 soon).
Many times our DBA will simply backup and restore a "template" client database to create a "new" database from the restored template.
Problem is the compatibility level sometimes is 80 (or 90) after the restore.
our new SQL scripts require at least level of 90 for new SQL features.
So, I wrote a script that will check the master database compatibility level and adjust the target client database on that server.
DECLARE #sys_compatibility_level tinyint, #db_compatibility_level tinyint;
SELECT #sys_compatibility_level = compatibility_level
FROM sys.databases
WHERE name = 'master';
SELECT #db_compatibility_level = compatibility_level
FROM sys.databases
WHERE name = DB_NAME();
DECLARE #db_name nvarchar(128) = DB_NAME();
IF #db_compatibility_level < #sys_compatibility_level
BEGIN
-- EXEC dbo.sp_dbcmptlevel #dbname=#db_name, #new_cmptlevel=#sys_compatibility_level -- deprecated
EXEC('ALTER DATABASE ' + #db_name + ' SET COMPATIBILITY_LEVEL = ' + #sys_compatibility_level)
END
My question, is this approach correct? should I check the master db or maybe the modeldb? are there any drawbacks from blindly setting the client db to that of the master/model?
since you are restoring databases,they retain the old compatabilty level..Newly created databases would inherit model database compatabilty level..
So change restored databases compatabilty level to the one you wish,not based on model/master..
change model database compatabilty level to one you choose,so new ones would inherit

Dropping SQL Server database: handling concurrent connections

During my integration tests, I try to drop database using:
USE master
ALTER DATABASE TestXyz SET SINGLE_USER WITH ROLLBACK IMMEDIATE
DROP DATABASE TestXyz
However, quite often (given the number of tests) one of the application background processes manages to get between SET SINGLE_USER and DROP DATABASE, which makes it single user of the database and breaks the DROP.
I can not use RESTRICTED_USER, as the application currently has db_owner permission (due to a large amount of legacy code, some of which requires it, so it will not be changed just for the tests).
I can not use OFFLINE as it does not delete database files from the disk.
How would you solve this problem?
OK plan b... iterate a drop of connections and rename the DB to get it away from the applications domain. Then drop it. To handle iterating through connections a try catch on the rename will hopefully allow it to run until it is able to drop the connection. Example code below creates a DB TestDB; renames it to testdb2 in the while loop before dropping it after the loop has succeeded.
-- Setup a scratch Db for testing
create database testdb
go
use testdb
while exists (select name from sys.databases where name = 'testdb')
Begin
DECLARE #DbName nvarchar(50) SET #DbName = N'testdb'
DECLARE #EXECSQL varchar(max) SET #EXECSQL = ''
SELECT #EXECSQL = #EXECSQL + 'Kill ' + Convert(varchar, SPId) + ';'
FROM MASTER..SysProcesses
WHERE DBId = DB_ID(#DbName) AND SPId <> ##SPId
EXEC(#EXECSQL)
Begin try
EXEC sp_renamedb 'testdb', 'testdb2'
end try
Begin Catch
print 'failed to rename'
End Catch
end
drop database testdb2
Try this once:
Stop application services and run your query.
Stop application services and restart SQL Server Services and then run your query.
I have finally solved it using the following approach:
ALTER LOGIN MyAppUser DISABLE
ALTER DATABASE TestXyz SET SINGLE_USER WITH ROLLBACK IMMEDIATE
DROP DATABASE TestXyz
ALTER LOGIN MyAppUser ENABLE
Since I can use different login for test database management process, this allows me to block application from accessing the DB. (The reason for SINGLE_USER here is just to kick already connected users. I haven't checked if ALTER LOGIN already does that, but I assume it does not).
Alternative option is to delete MyAppUser from the database before dropping it, however I thought about it only now and do not have code for it.

Resources