Thursday 9 January 2014

Application Pool Spin-up Times

With reference to: http://ddkonline.blogspot.co.uk/2010/05/fix-sharepoint-very-slow-to-start-after.html

These steps seem to improve spool-up time following GAC deployments, after making the changes a server restart (or at least an IISRESET, restart Timer, restart Administration) can't hurt. Not sure I'd recommend doing this on a production system.

Add this to your hosts file:


 127.0.0.1 crl.microsoft.com  

Stick the following in a .vbs file and execute under CMD as an administrator (prevents all user accounts (presumably that have a 'profile') on the server from attempting to retrieve the CRL from Microsoft):

 const HKEY_USERS = &H80000003   
 strComputer = "."   
 Set objReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" _   
 & strComputer & "\root\default:StdRegProv")   
 strKeyPath = ""   
 objReg.EnumKey HKEY_USERS, strKeyPath, arrSubKeys   
 strKeyPath = "\Software\Microsoft\Windows\CurrentVersion\WinTrust\Trust Providers\Software Publishing"   
 For Each subkey In arrSubKeys   
  objReg.SetDWORDValue HKEY_USERS, subkey & strKeyPath, "State", 146944   
 Next   

Finally, update the 'machine.config' files in C:\Windows\Microsoft.NET\ (search for them, one per .NET version per CPU arch):


 <configuration>  
 <runtime>  
 <generatePublisherEvidence enabled="false"/>  
 </runtime>  
 </configuration>  

Thursday 2 January 2014

SharePoint & SQL - Keeping an eye on DB and logfile size

Following on from the previous post, it is probably not a bad idea to keep an eye on what your DB and log files are doing size and growth-wise - anticipating size for a development environment is going to be tricky and you (I) may get it wrong...

To keep tabs on things, the script below will fire an email off to all specified recipients (provided Database Mail is configured of course) that lists all files, status and size. We stick this in a maintenance plan and run it once a night. If any files are growing unexpectedly then they can be re-sized accordingly.

DECLARE @Recipients VARCHAR(MAX) = 'a@a.com;b@b.com'
DECLARE @Subject VARCHAR(MAX) = 'HOSTNAME (ROLE) Database Report'
DECLARE @FooterMessage VARCHAR(MAX) = 'This email was generated by a maintenance plan located on HOSTNAME (INSTANCENAME)'
DECLARE @Commands TABLE (
                
[ID] INT IDENTITY,
                
[Command] VARCHAR(MAX)
    )
INSERT INTO
        
@Commands ([Command])
    
SELECT
    
'use [' + [name] + ']; select [name], [type_desc], [physical_name], [state_desc], [size] / 128 from sys.database_files;' AS [Command]
    
FROM
            
sys.databases
DECLARE @NextCommandID INT
SELECT
@NextCommandID = MIN([ID])
    
FROM @Commands
DECLARE @Results TABLE (
                
[ID] INT IDENTITY,
                
[FileName] VARCHAR(MAX),
                
[FileType] VARCHAR(4),
                
[FilePath] VARCHAR(MAX),
                
[Status] VARCHAR(MAX),
                
[Size (MB)] INT
    
)
WHILE @NextCommandID IS NOT NULL
    
BEGIN
    DECLARE
@NextCommand VARCHAR(MAX)
    
SELECT @NextCommand = [Command]
        
FROM @Commands
        
WHERE [ID] = @NextCommandID
    
INSERT INTO @Results ([FileName], [FileType], [FilePath], [Status],    [Size (MB)])
        
EXEC(@NextCommand)
    
DELETE
        FROM
@Commands
        
WHERE [ID] = @NextCommandID
    
SELECT @NextCommandID = MIN([ID])
        
FROM @Commands
    
END
DECLARE
@HtmlResult VARCHAR(MAX)
    
SET @HtmlResult = '<table cellpadding="0" cellspacing="0"><tr><th>Filename</th><th>Type</th><th>Path</th><th>Status</th><th>Size (MB)</th></tr>'
DECLARE @NextResultID INT
SELECT
@NextResultID = MIN([ID])
    
FROM @Results
WHILE @NextResultID IS NOT NULL
    
BEGIN
    SET
@HtmlResult = @HtmlResult +
        (
        
SELECT
            
'<tr><td>' + [FileName] +
            
'</td><td>' + [FileType] +
            
'</td><td>' + [FilePath] +
            
'</td><td>' + [Status] +
            
'</td><td>' + CAST([Size (MB)] AS VARCHAR) + '</td></tr>'
            
FROM
            
@Results
            
WHERE
                    
[ID] = @NextResultID)
    
DELETE
        FROM
@Results
        
WHERE [ID] = @NextResultID
    
SELECT @NextResultID = MIN([ID])
        
FROM @Results
    
END
SET
@HtmlResult = '<html><head><style>body { font-family: sans-serif; font-size: 10px; } th { text-align: left; } th, td { border: 1px solid #555 }</style></head><body>' + @HtmlResult + '</table><p>' + @FooterMessage + '</p></body></html>'
EXEC msdb.dbo.sp_send_dbmail
    
@recipients = @Recipients,
    
@body = @HtmlResult,
    
@body_format = 'HTML',
    
@subject = @Subject;

SharePoint & SQL - Tidying up a messy shared development SQL instance

Came across a bit of a messy SQL instance for our SharePoint dev. environments recently.

Here is a bit of optimisation... (DISCLAIMER: This is mainly for my reference, consult someone in the know before attempting ANY of it!)

General notes:

  • Create one tempdb DB file for each CPU core available
  • Provided the server is dedicated to one SQL instance, I assign the maximum memory usage as the total physical memory less 2GB for the OS (So, an 8GB machine would have up to 6GB assignable to SQL)

The script below will do the following:

  • Set all databases to simple recovery (we do full backups and are not interested in transactional backups)
  • Shrink all database and log files down to 1MB (where possible)
  • Set the autogrowth of each database and log file to 512MB
  • Set the size of each database and log file to 512MB (where possible)
Following execution of the script, any outliers to the 512MB size / autogrowth should be manually configured. Content and UsageApplication DBs are a good example of this and should be sized accordingly. I am currently trying 5GB for UsageApplicaton DBs (you could alternatively reduce the retention in central admin) and 1GB for Content DBs (we don't deal with large amounts of content in our line of work).

File sizes and autogrowth rates can be set by right-clicking a DB > Properties > Files

After everything is configured, stop the SQL service and defrag the relevant disks for good measure. This should result in a relatively healthy / happy SQL environment and keep your SharePoint development systems running nicely.



DECLARE @Databases TABLE ([ID] INT IDENTITY, [name] VARCHAR(MAX))INSERT INTO @Databases ([name])
    
SELECT [name]
    
FROM sys.databasesDECLARE @DatabaseID INT
SELECT
@DatabaseID = MIN([ID])
    
FROM @DatabasesDECLARE @DatabaseFiles TABLE ([ID] INT IDENTITY, [name] VARCHAR(MAX), [filename] VARCHAR(MAX))WHILE @DatabaseID IS NOT NULL
    
BEGIN
    DECLARE
@DatabaseName VARCHAR(MAX)
    
SELECT @DatabaseName = [name]
        
FROM @Databases
        
WHERE [ID] = @DatabaseID
    
INSERT INTO @DatabaseFiles ([name], [filename])
        
EXEC('use [' + @DatabaseName + ']; select ''' + @DatabaseName + ''', [name] from sys.database_files')
    
EXEC('alter database [' + @DatabaseName + '] set recovery simple;')
    
DELETE
        FROM
@Databases
        
WHERE [ID] = @DatabaseID
    
SELECT @DatabaseID = MIN([ID])
        
FROM @Databases
    
END
DECLARE
@DatabaseFileID INT
SELECT
@DatabaseFileID = MIN([ID])
    
FROM @DatabaseFilesWHILE @DatabaseFileID IS NOT NULL
    
BEGIN
    DECLARE
@DatabaseFileName VARCHAR(MAX)
    
SELECT @DatabaseName = [name], @DatabaseFileName = [filename]
        
FROM @DatabaseFiles
        
WHERE [ID] = @DatabaseFileID
    
EXEC('use [' + @DatabaseName + ']; dbcc SHRINKFILE ([' + @DatabaseFileName + '], 1);')
    
EXEC('ALTER DATABASE [' + @DatabaseName + '] MODIFY FILE ( NAME = ''' + @DatabaseFileName + ''', FILEGROWTH = 524288KB)')
    
EXEC('ALTER DATABASE [' + @DatabaseName + '] MODIFY FILE ( NAME = ''' + @DatabaseFileName + ''', SIZE = 524288KB)')
    
DELETE
        FROM
@DatabaseFiles
        
WHERE [ID] = @DatabaseFileID
    
SELECT @DatabaseFileID = MIN([ID])
        
FROM @DatabaseFiles
    
END