What’s swimming in your bufferpool?


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

Comments (3)

  1. jl999 says:

    Cool. One comment, though: Shouldn’t the ‘index page’ be ‘index_page’ in the WHERE clause?

  2. sqlperf says:

    Fixed. Thanks for pointing out.

  3. y2kbug says:

    any idea what would a comparable query would be against SQL2000? TIA