10

My question is how does SQL Server handle a query that needs to pull more volume of data into the buffer cache than there is space available? This query would contain multiple joins, so the result set does not exist in this format already on disk, and it would need to compile the results. But even after the compilation, it still requires more space than is available in the buffer cache.

I will give an example. Suppose you have a SQL Server instance that has 6GB total of Buffer Cache space available. I run a query with multiple joins that reads 7GB of data, how is SQL Server able to respond to this request? Does it temporarily store the data in tempdb? Does it fail? Does it do something that just reads data from disk and compiles segments at a time?

In addition, what happens if I am trying to return 7GB of total data, does that change how SQL Server handles it?

I am already aware of several ways to address this, I am just curious how SQL Server handles this request internally when it runs as stated.

Also, I am sure this information exists somewhere, but I have been unsuccessful in finding it.

  • 1
    In layman's terms SQL Server will store the work tables and results of its own internal processing in tempdb. The pages are read from disk when needed. Pages will remain in memory until they are forced out, or when SQL is ready to commit them to disk. This is when you run a large query tempdb will grow. I have seen queries bring a system to its knees because tempdb was allowed to grow unchecked and consumed all remaining space on the drive. I know this isn't 100% accurate, just trying to explain it simply. The part that uses the data isn't the part that manages the location of that data – datagod Jan 27 '17 at 17:37
12

Pages are read into memory as required, if there is no free memory available, the oldest unmodified page is replaced with the incoming page.

This means if you execute a query that requires more data than can fit in memory, many pages will live a very short life in memory, resulting in a lot of I/O.

You can see this effect by looking at the "Page Life Expectancy" counter in Windows Performance Monitor. Look at https://sqlperformance.com/2014/10/sql-performance/knee-jerk-page-life-expectancy for some great details about that counter.

In the comments, you asked specifically what happens when the results of the query is larger than available buffer space. Take the simplest example, select * from some_very_big_table; - assume the table is 32GB, and max server memory (MB) is configured at 24GB. All 32GB of table data will be read into pages in the page buffer one at a time, latched, formatted into network packets, and sent across the wire. This happens page-by-page; you could have 300 such queries running at the same time, and assuming there was no blocking happening, the data for each query would be read into page buffer space, a page at a time, and put onto the wire as fast as the client can request and consume the data. Once all the data from each page has been sent onto the wire, the page becomes unlatched, and will very quickly be replaced by some other page from disk.

In the case of a more complex query, say for instance aggregating results from several tables, pages will be pulled into memory exactly as above as they are required by the query processor. If the query processor needs temporary work space to calculate results, it will know that upfront when it compiles a plan for the query, and will request work space (memory) from SQLOS. SQLOS will at some point (assuming it doesn't time out), grant that memory to the query processor, at which point query processing will resume. If the query processor makes a mistake in its estimate of how much memory to ask for from SQLOS, it may need to perform a "spill to disk" operation, where data is temporarily written into tempdb in an intermediate form. The pages that have been written to tempdb will be unlatched once they are written to tempdb to make room for other pages to be read into memory. Eventually the query process will return to the data stored in tempdb, paging that in using latching, into pages in the buffer that are marked free.

I'm undoubtedly missing a load of very technical details in the above summary, but I think that captures the essence of how SQL Server can process more data than can fit in memory.

  • Out of curiosity, what kind of query is pulling 7GB of data? I hope this is a batch process. – datagod Jan 27 '17 at 17:40
  • Probably not many and you are right it would hopefully be a batch process. I was just curious to see how SQL would handle that request – Dustin Jan 27 '17 at 18:57
5

I can't speak to what exactly your query would do in this scenario but SQL Server has several options depending on how much is needed.

  • Data can "spill" to TempDB, this would be using your disk
  • Old pages can be pushed out of your buffer cache
  • SQL Server can load some pages to buffer cache, use them, then rotate new pages in

The best way to find out what would happen is to create the scenario in a dev environment and find out.

2

My question is how does SQL Server handle a query that needs to pull more volume of data into the buffer cache then there is space available

To answer this specific part let me tell you how this is managed. The pages are of size 8KB. When you run a query requesting large data set and which requires numerous pages to be brought into memory SQL Server will not bring all pages in one go. It will locate the specific pages and bring one by one single 8KB pages into memory read the data out from it and give you the result and this will go on now suppose it faces situation where memory is less in that case old pages will be flushed to the disk like @Max pointed out. As you guessed correctly this low memory can slow things as some time would be spent in removing old pages. This is where checkpoint and Lazywriter comes into picture. Lazywriter is their to make sure some free memory is always there to bring new pages to the disk. When low free buffer is encountered it is triggered and creates free spaces to being new pages.

EDIT

I get that, but the part that baffles me a bit is what happens if you are joining \filtering data and those results exceed the size of the cache.

The memory for joining and filtering are decided even before the query runs and suppose there is really a memory crunch and the memory required to run operation is not available SQL Server processor will grant "required memory" which is

Required memory: Minimum memory needed to run sort and hash join. It is called required because a query would not start without this memory available. SQL server uses this memory to create internal data structures to handle sort and hash join.

So at least the query will start running but during runtime its quite likely the intermediate result is spilled to Tempdb making it slow. I strongly suggest you read Understanding Query Memory Grant

  • I get that, but the part that baffles me a bit is what happens if you are joining \filtering data and those results exceed the size of the cache. The data would need to be compiled to produce the return set, but the return set is greater then the size of the cache. Does is still internally cycle pages through the cache until it produces the end result? My thinking would be that it would write the results to tempdb since it exceeded the cache and then read from disk that, but do not know if that is the case – Dustin Jan 27 '17 at 17:08
  • 2
    @Dustin Edited my answer, please check – Shanky Jan 27 '17 at 17:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.