Question

I need to find out how much cache is used, and if there is free cache available.

Background:

Queries on a production server take a lot of time when the server is under heavy load. I suspect that the available cache is too small to serve a high number of different queries.

Was it helpful?

Solution

Ensure you've set the max server memory (mb) and min server memory (mb) options via sys.sp_configure appropriately for your server. See my question to determine what those numbers should be.

Check Page Life Expectancy to see if your buffer pool is too small. Depending on the size of your buffer pool, a commonly mentioned number is 300 seconds (5 minutes), but this will vary depending on your needs. This code should work well enough:

DECLARE @Version NVARCHAR(255);
DECLARE @VersionINT INT;
SET @Version = CONVERT(NVARCHAR(255),SERVERPROPERTY('ProductVersion'));
SET @VersionINT = CONVERT(INT, SUBSTRING(@Version,1 ,CHARINDEX('.',@Version)-1));
DECLARE @cmd NVARCHAR(4000);
SET @cmd = '';
IF @VersionINT >= 9
BEGIN
    SET @cmd = 
'SET NOCOUNT ON;

DECLARE @SecondsSinceRestart INT;
DECLARE @cpu_count INT;
DECLARE @physical_memory_kb INT;
DECLARE @committed_target_kb INT;
DECLARE @committed_kb INT;

DECLARE @BootTime DATETIME;
DECLARE @output TABLE
(
    RowNum INT NOT NULL IDENTITY(1,1)
    , [output] VARCHAR(1000) NULL
);
INSERT INTO @output ([output])
EXEC sys.xp_cmdshell @command = ''wmic os get lastbootuptime'';

;WITH c AS (
    SELECT Year = SUBSTRING(o.output, 1, 4)
        , Month = SUBSTRING(o.output, 5, 2)
        , Day = SUBSTRING(o.output, 7, 2)
        , Hour = SUBSTRING(o.output, 9, 2)
        , Minute = SUBSTRING(o.output, 11, 2)
        , Second = SUBSTRING(o.output, 13, 2)
    FROM @output o
    WHERE o.RowNum = 2
)
SELECT @BootTime = CONVERT(DATETIME, c.Year + ''-'' + c.Month + ''-'' + c.Day + ''T'' + c.Hour + '':'' + c.Minute + '':'' + c.Second, 126)
FROM c;

SET @SecondsSinceRestart = DATEDIFF(SECOND, @BootTime, GETDATE());

';
IF @VersionINT = 11
SET @cmd = @cmd + '
SELECT @cpu_count = cpu_count
        , @physical_memory_kb = physical_memory_kb
        , @committed_target_kb = committed_target_kb
        , @committed_kb = committed_kb
FROM sys.dm_os_sys_info dosi
'
ELSE
SET @cmd = @cmd + '
SELECT @cpu_count = cpu_count
        , @physical_memory_kb = physical_memory_in_bytes / 1024
        , @committed_target_kb = bpool_commit_target * 8
        , @committed_kb = bpool_committed * 8
FROM sys.dm_os_sys_info dosi
';

SET @cmd = @cmd + '
;WITH c AS (
    SELECT ServerName = @@SERVERNAME
        , pc.object_name
        , pc.counter_name
        , pc.instance_name
        , pc.cntr_value
        , BootTime = @BootTime
        , SecondsSinceRestart = @SecondsSinceRestart
        , cpu_count = @cpu_count
        , physical_memory_kb = @physical_memory_kb
        , committed_target_kb = @committed_target_kb
        , committed_kb = @committed_kb
    FROM sys.dm_os_performance_counters pc
    WHERE pc.object_name = ''MSSQL$'' + CONVERT(VARCHAR(255), SERVERPROPERTY(''InstanceName'')) + '':Buffer Node                                                                                                        ''
    AND pc.counter_name = ''Page life expectancy                                                                                                            ''
    AND pc.instance_name IS NOT NULL
)
SELECT RunNum = 7 
    , c.ServerName
    , c.counter_name
    , c.object_name
    , c.instance_name
    , c.cntr_value
    , c.SecondsSinceRestart
    , c.BootTime
    , Ratio = c.cntr_value / CONVERT(DECIMAL(10,0), c.SecondsSinceRestart)
    , cpu_count
    , physical_memory_kb
    , committed_target_kb
    , committed_kb
    , ServerVersion = SERVERPROPERTY(''ProductVersion'')
FROM c;';
    EXEC sys.sp_executesql @cmd;
END

You can see what objects are occupying memory using the code shown in a recent blog post I wrote over at SQLServerScience.com.

Licensed under: CC-BY-SA with attribution
Not affiliated with dba.stackexchange
scroll top