Showing posts with label SQL Server. Show all posts
Showing posts with label SQL Server. Show all posts

July 27, 2023

Autogrow All Files, Manually

SQL Server has a setting which will grow all database files in a filegroup any time that one file grows.  This setting is great for databases that are new, or otherwise can have the setting enabled.

However exclusive access is required, therefore it's not practical to enable this setting on some databases.  You could entertain using single user mode or connecting via the DAC, but the downtime might not be worth it.  Remember, resizing files manually does pause I/O, but it's less intrusive than no connections at all.

If downtime is a concern, consider enabling the Instant File Initialization setting for your SQL Service before running this.  However, if you don't want to enable that, running this more frequently could result in shorter, less noticed pauses in I/O.

This script was built to be run as a SQL Agent job.

August 21, 2013

SQL Restore fails to load file

This is pretty rare.  SQL 2008 R2 installed then uninstalled.  SQL 2005 installed.  Red-Gate's SQL Backup installed and try to do a database restore fails with the error: "SQL Backup exit code: 1010, SQL error code: 3201".

It's because the sqlvdi.dll file from 2008 is still on the server.

Use the SQL Backup Simulator tool from MSDN to determine what versions are on the server and what version is in memory.  To replace the incorrect versions, stop SQL Services (if in memory) and copy/paste from a known good server (if available).  Register the dll using regsvr32.  Backups are back in business!

April 25, 2013

SQL Maintenance Plan Cleanup Fails

I originally compiled this list for setting up Maintenance Cleanup Tasks in SQL Server 2005.  I had maintenance cleanup tasks failing and found a combination that worked for me.  Some might not make any sense at all, but after a week I was game to try anything:
  • no "." in front of "bak" or "trn"
  • use a \ at the end of the path (this is the one that got me working)
  • use * for the extension
  • switch between caps & lower case (BAK vs bak vs Bak)
  • switch on first level folders
  • the task checks the files to verify that they are backup files... so empty test files may not work.
If all else fails, use a scheduled task and a powershell script.

August 28, 2012

SQL Index maintenance


I don't know where these scripts originated... I've tried to search it out to give appropriate credit, but it's on MSDN blogs, TechNet blogs, SQLServerCentral, and other sql related sites.  I first came across them on the Dynamics Communities site.  If I learn of the origin I will come back and include it.  For now, I'm including it here for my own reference.  Consider changing the recovery mode to simple temporarily if there are going to be massive changes.


USE [DATABASE]
--Check Fragmentation
SELECT s.DATABASE_ID,
       s.OBJECT_ID,
       s.INDEX_ID,
       b.NAME,
       s.AVG_FRAGMENTATION_IN_PERCENT
FROM   sys.DM_DB_INDEX_PHYSICAL_STATS (DB_ID(), NULL, NULL, NULL, NULL) AS s
       INNER JOIN sys.INDEXES AS b
               ON s.OBJECT_ID = b.OBJECT_ID
                  AND s.INDEX_ID = b.INDEX_ID
WHERE  s.DATABASE_ID = DB_ID()
ORDER  BY s.AVG_FRAGMENTATION_IN_PERCENT DESC
 
/**Fragmentation is also covered in the Performance Analyzer for Microsoft
   Dynamics AX (also known as DynamicsPerf). When running an sp_capturestats,
   pass the parameter @INDEX_PHYSICAL_STATS =’Y’. Note that this places a
   heavier load on SQL when capturing, so you should consider executing this
   during non-peak hours. Once the index fragmentation statistics have been
   captured you can view them with this script.
**/
 
USE [DATABASE]
SELECT DATABASE_NAME,
       TABLE_NAME,
       INDEX_NAME,
       AVG_FRAGMENTATION_IN_PERCENT,
       FRAGMENT_COUNT
FROM   INDEX_STATS_CURR_VW
ORDER  BY AVG_FRAGMENTATION_IN_PERCENT DESC 
 
--This script will reorganize or rebuild indexes based on the fragmentation.  It's set at 30% in this script.
 
-- Ensure a USE  statement has been executed first.
USE [DATABASE]
SET nocount ON;
 
DECLARE @objectid INT;
DECLARE @indexid INT;
DECLARE @partitioncount BIGINT;
DECLARE @schemaname NVARCHAR(130);
DECLARE @objectname NVARCHAR(130);
DECLARE @indexname NVARCHAR(130);
DECLARE @partitionnum BIGINT;
DECLARE @partitions BIGINT;
DECLARE @frag FLOAT;
DECLARE @command NVARCHAR(4000);
-- Conditionally select tables and indexes from the sys.dm_db_index_physical_stats function and convert object and index IDs to names.
 
SELECT OBJECT_ID                    AS objectid,
       INDEX_ID                     AS indexid,
       PARTITION_NUMBER             AS partitionnum,
       AVG_FRAGMENTATION_IN_PERCENT AS frag
INTO   #work_to_do
 
FROM   sys.DM_DB_INDEX_PHYSICAL_STATS (DB_ID(), NULL, NULL, NULL, 'LIMITED')
WHERE  AVG_FRAGMENTATION_IN_PERCENT > 10.0
       AND INDEX_ID > 0;
 
-- Declare the cursor for the list of partitions to be processed.
DECLARE partitions CURSOR FOR
  SELECT *
  FROM   #work_to_do;

-- Open the cursor.
OPEN partitions;

-- Loop through the partitions.
WHILE ( 1 = 1 )
  BEGIN;
      FETCH next FROM partitions INTO @objectid, @indexid, @partitionnum, @frag;
      IF @@FETCH_STATUS < 0
        BREAK;
      SELECT @objectname = QUOTENAME(o.NAME),
             @schemaname = QUOTENAME(s.NAME)
      FROM   sys.OBJECTS AS o
             JOIN sys.SCHEMAS AS s
               ON s.SCHEMA_ID = o.SCHEMA_ID
      WHERE  o.OBJECT_ID = @objectid;
      SELECT @indexname = QUOTENAME(NAME)
      FROM   sys.INDEXES
      WHERE  OBJECT_ID = @objectid
             AND INDEX_ID = @indexid;
      SELECT @partitioncount = COUNT (*)
      FROM   sys.PARTITIONS
      WHERE  OBJECT_ID = @objectid
             AND INDEX_ID = @indexid;
 
      -- 30 is an arbitrary decision point at which to switch between reorganizing and rebuilding.
 
      IF @frag < 30.0
        SET @command = N'ALTER INDEX ' + @indexname + N' ON '
                       + @schemaname + N'.' + @objectname + N' REORGANIZE';
      IF @frag >= 30.0
        SET @command = N'ALTER INDEX ' + @indexname + N' ON '
                       + @schemaname + N'.' + @objectname
                       + N' REBUILD WITH( MAXDOP = 8)';
 --Enterprise version:  + N' REBUILD WITH(ONLINE = ON, MAXDOP = 8)';
      IF @partitioncount > 1
        SET @command = @command + N' PARTITION='
                       + CAST(@partitionnum AS NVARCHAR(10));
      EXEC (@command);
      PRINT N'Executed: ' + @command; 
  END;

-- Close and deallocate the cursor.
CLOSE partitions;
DEALLOCATE partitions;
 
-- Drop the temporary table.
DROP TABLE #work_to_do;
 
GO

SQL Profiler and PerfMon

When looking for slow queries using SQL Profiler these are the events and columns I like to collect:
  • Stored Procedures / RPC:Completed
  • Stored Procedures / SP:StmtCompleted
  • TSQL / SQL:BatchCompleted
  • TSQL / SQL:BatchStarting  (sometimes)
I've seen Performance / ShowplanXML recommended, but haven't really dug into it yet... be sure to select the BinaryData column for this column.

Columns:
  • Event Class (auto-selected)
  • Duration
  • TextData
  • SPID
  • Reads
  • RowCounts
  • Writes
  • StartTime
  • EndTime
  • ObjectName (useful to know context)
  • EventSequence (sometimes helpful for context)
Other Columns to consider:
  • CPU
  • IntegerData
  • DatabaseName
  • LoginName
  • ApplicationName (not always populated)
  • BinaryData (for ShowplanXML)
Thanks to Brad McGehee's blog (here) for ShowplanXML events along with ApplicationName and EventSequence columns.

Once the Events & Columns are selected and organized I'll setup Column filters:
  • Duration greater than or equal to a number, i.e. 1000 = 1 second in SQL 2008 Profiler.
  • Database equals or not equals (if applicable).

Use PerfMon to check general performance with these key events:
  • Memory – Available MBytes
  • Paging File – % Usage
  • Physical Disk – Avg. Disk sec/Read
  • Physical Disk – Avg. Disk sec/Write
  • Physical Disk – Disk Reads/sec
  • Physical Disk – Disk Writes/sec
  • Processor – % Processor Time
  • SQLServer: Buffer Manager – Buffer cache hit ratio
  • SQLServer: Buffer Manager – Page life expectancy
  • SQLServer: General Statistics – User Connections
  • SQLServer: Memory Manager – Memory Grants Pending
  • SQLServer: SQL Statistics – Batch Requests/sec
  • SQLServer: SQL Statistics – Compilations/sec
  • SQLServer: SQL Statistics – Recompilations/sec
  • System – Processor Queue Length

July 06, 2012

Command line SQL backups on SQL Express


SQL Express doesn't have the same capability as the Standard edition.  So, Maintenance Tasks cannot be used to backup databases.  There are a couple options:

If the database names are known, backups can be run using sqlcmd from the command line or scheduled task:
sqlcmd -S [. or servername][\instance] -Q "BACKUP DATABASE [dbname] TO DISK='[path\file.bak]'"

If the database names are not known or could change over time and you don't want remember to update your script, Microsoft published a TechNet article (KB 2019698) containing a script which creates a stored procedure that can be run using sqlcmd.

Note, the copyright info will need to be commented out in the script.  Also, there are also some "smart" quotes in the batch file contents instead of straight quotes which cause it to fail.

To restore, a similar sqlcmd can be run:
sqlcmd -S [. or servername][\instance] -Q "RESTORE DATABASE [dbname] FROM DISK='[path\file.bak]'"

If you happen to be moving a database to a new server, this TechNet article (KB 918992) explains how to transfer SQL users between servers while retaining SPID and password information.

May 01, 2012

SQL Blocking Alert

Here's how to setup an alert for blocking in SQL:
By default, the blocking is set to 5 (the minimum), if it's 0 it's disabled.  As I understand it, it will report an error for any blocks that last as many seconds as specified.  So if it's set to 5, it'll generate an alert when a block lasts for more than 5 seconds.

This MSDN article (http://msdn.microsoft.com/en-us/library/ms181150.aspx) explains how to change the setting.  To check the setting, query the master database:  select * from sys.configurations where name like 'blocked process threshold'.

This thread explains how to setup the alert (http://social.msdn.microsoft.com/Forums/en-US/sqldatabaseengine/thread/945cab5d-b8eb-4c15-93ff-b4ddbba1f7f2?prof=required).  The step I missed when setting up the alert is selecting the Object "SQL Server:General Statistics" Counter "Processes blocked".  Set the desired response and it's ready to go.

I'm now waiting to verify that my alert is functioning properly.