When doing a performance investigation a useful thing to do is look at what data is present in the buffer pool.  This can be used to analyze impact of running a query on the state of data pages in buffer pool. By collecting the pre and post picture of buffer pool, you can see the cost of running a query in terms of physical IOs that happened. You may argue that this can be done by looking at statistics IO output; however if you are running a series of queries and want to see a consolidated data and not data about individual queries, this query is a great help.

 

The contents of the buffer pool can also reveal which pages are accessed most frequently by your applications and often reflect the actual I/O that is happening.  How can frequently access pages in memory also cause disk I/O?   When lots of different objects are accessed overtime the proportion of data in the buffer pool reflects the frequency of access. This happens because data pages of infrequently accessed objects get kicked out of main memory over time. 

 

If you are not familiar with the buffer pool, it contains several types of objects such as data pages and plans.  For more information on the buffer pool see Buffer Management  http://msdn2.microsoft.com/en-us/library/aa337525.aspx

 

The following query can be used to look at the contents of the buffer pool -

 

select

       count(*)as cached_pages_count,

       obj.name as objectname,

       ind.name as indexname,

       obj.index_id as indexid

from sys.dm_os_buffer_descriptors as bd

    inner join

    (

        select       object_id as objectid,

                           object_name(object_id) as name,

                           index_id,allocation_unit_id

        from sys.allocation_units as au

            inner join sys.partitions as p

                on au.container_id = p.hobt_id

                    and (au.type = 1 or au.type = 3)

        union all

        select       object_id as objectid,

                           object_name(object_id) as name,

                           index_id,allocation_unit_id

        from sys.allocation_units as au

            inner join sys.partitions as p

                on au.container_id = p.partition_id

                    and au.type = 2

    ) as obj

        on bd.allocation_unit_id = obj.allocation_unit_id

left outer join sys.indexes ind 

  on  obj.objectid = ind.object_id

 and  obj.index_id = ind.index_id

where bd.database_id = db_id()

  and bd.page_type in ('data_page', 'index_page')

group by obj.name, ind.name, obj.index_id

order by cached_pages_count desc

 

An example of what it returns –

 

1.       Run following command to remove all clean data pages from the buffer pool –  (DO NOT TRY THIS COMMAND ON PRODUCTION MACHINES)

 

DBCC DROPCLEANBUFFERS

 

Running buffer pool analysis query had following results –

 

cached_pages_count ObjectName         IndexName              IndexId

------------------ ------------------ ---------------------- -----------

15                 sysobjvalues       clst                   1

3                  sysallocunits      clust                  1

2                  syshobtcolumns     clust                  1

2                  sysrowsetcolumns   clust                  1

2                  sysrowsets         clust                  1

2                  sysschobjs         clst                   1

 

2.       Run the following query on AdventureWorks database –

 

select * from Person.Address

where city like 'Bothell'

 

This is going to read from disk the data pages needed to execute the query. Run the buffer pool analysis query again to see the change. 

 

cached_pages_count ObjectName         IndexName              IndexId

------------------ ------------------ ---------------------- -----------

278                Address            PK_Address_AddressID   1

15                 sysobjvalues       clst                   1

4                  sysmultiobjrefs    clst                   1

3                  sysallocunits      clust                  1

2                  syshobtcolumns     clust                  1

2                  sysrowsetcolumns   clust                  1

 

As you can see now there are data pages in buffer pool from the Address table. Additionally since only clustered index pages for Address table are present, no other indexes were used in the query.

 

Another tool which can help in this case is DBCC MEMORYSTATUS output. The advantage of the query in the entry is nice result set which can be stored in a temp table.

 

 

Authors:

Tony Voellm

Gaurav Bindlish