Friday, February 8, 2008

Today's Client Question: Temp File Size

Q: Why does DB_PROPERTY ( 'TempTablePages' ) say that only 16K of space is used when our SQL Anywhere Version 9 temporary file has grown to 9G in size? Even Foxhound doesn't get the number right, it says the "Temp File" is only 4M.

A: All the numbers are correct, but some are more correct than others; it depends on what you're looking for.

Some background: The temporary file is created when the server starts, is deleted when it shuts down, and in between it grows in size but never shrinks. In your case, at some point since the server started it needed 9G of space, and that might indicate a problem... perhaps one or more runaway queries. Be warned: the server will most likely crash if the temporary file grows to fill the disk.

The DB_PROPERTY ( 'TempTablePages' ) value tells you how much temporary file space is currently used for temporary tables. Note the phrase "currently used" instead of "maximum space required". Also, "temporary tables" is not the only use for the temporary file; a runaway query might use huge amounts of temporary file space even when no temporary tables exist at all.

You can calculate the SUM() of all CONNECTION_PROPERTY ( 'TempFilePages' ) values to see a bigger picture: the total amount of space currently used in the temporary file. Here is a runaway query that uses a lot of temporary file space, followed by a query that shows the difference between TempTablePages and TempFilePages:

SELECT COUNT(*)
FROM ( SELECT *
FROM SYSTABLE CROSS JOIN SYSCOLUMN
UNION
SELECT *
FROM SYSTABLE CROSS JOIN SYSCOLUMN ) AS fat;

SELECT CAST ( TempFilePages * PageSize / 1024.0 AS BIGINT )
AS TempFilePagesK,
CAST ( TempTablePages * PageSize / 1024.0 AS BIGINT )
AS TempTablePagesK
FROM ( SELECT SUM ( CAST ( CONNECTION_PROPERTY ( 'TempFilePages',
sa_conn_info.Number )
AS DECIMAL ( 15, 6 ) ) ) AS TempFilePages,
CAST ( DB_PROPERTY ( 'TempTablePages' )
AS DECIMAL ( 15, 6 ) ) AS TempTablePages,
CAST ( DB_PROPERTY ( 'PageSize' )
AS DECIMAL ( 15, 6 ) ) AS PageSize
FROM sa_conn_info() ) AS properties;
In your case, that is where the 4M figure is coming from; Foxhound computes the SUM() for you. It's a bigger number than the 16K, but it's still the "currently used" number, not the temporary file size.

In the case of the SELECT COUNT(*) above, Figure 1 shows how the SUM() of TempFilePages grows and shrinks:

Figure 1: Foxhound Temp File History

Figure 2 shows the connection-level detail when the peak Temp File value of 226M was reached: one connection was using all the space to do the SELECT COUNT(*).

Figure 2: Foxhound Connection Detail


Figure 3 shows that after SELECT COUNT(*) finished, most of the temporary file is free space.

Figure 3: Foxhound DBSPACE Detail


You can run your own query to show the actual temporary file size, which is the "high water mark" for temporary file usage:

SELECT CAST ( temp_file_pages * page_size / 1024.0 / 1024.0
AS BIGINT ) AS TempFileK
FROM ( SELECT CAST ( DB_EXTENDED_PROPERTY ( 'FileSize', 'temp' )
AS DECIMAL ( 15, 6 ) ) AS temp_file_pages,
CAST ( DB_PROPERTY ( 'PageSize' )
AS DECIMAL ( 15, 6 ) ) AS page_size ) AS sizes;
What Can Be Done About Temp File Usage?

SQL Anywhere Version 9 introduced the following database-level option to keep runaway queries from crashing the server:
SET OPTION PUBLIC.TEMP_SPACE_LIMIT_CHECK = 'ON';
Version 10 extended the idea (and here's another reason to upgrade to V10): You can specify different limits on the amount of temporary space allocated to different connections.

For example, if you have a lot of high-speed low-overhead OLTP connections, you can give them a low limit on temporary space to prevent fat queries from affecting response and throughput:
SET TEMPORARY OPTION MAX_TEMP_SPACE = '1M'; -- small
At the same time, if you have some connections doing important OLAP queries, you might want to give them a high limit so that they will be able to get their work done:
SET TEMPORARY OPTION MAX_TEMP_SPACE = '10G'; -- large
Some notes: The MAX_TEMP_SPACE option is available at the connection level even though the V10 help implies it is available only at the "PUBLIC" database level. Also, the MAX_TEMP_SPACE option only works if you also have TEMP_SPACE_LIMIT_CHECK set 'ON'.

Add to Technorati Favorites

4 comments:

Erik said...

WOW...I know this is old, but I think that there is a small issue with your 'High Water Mark' query. It appears to me that it is returning the file size in MB, not Kb because it divides by 1024 twice.

I think it should be like this instead...

SELECT CAST ( temp_file_pages * page_size / 1024.0
AS BIGINT ) AS TempFileK
FROM ( SELECT CAST ( DB_EXTENDED_PROPERTY ( 'FileSize', 'temp' )
AS DECIMAL ( 15, 6 ) ) AS temp_file_pages,
CAST ( DB_PROPERTY ( 'PageSize' )
AS DECIMAL ( 15, 6 ) ) AS page_size ) AS sizes;

Breck Carter said...

@Erik: The query is correct as shown; the column alias names TempFilePagesK and TempTablePagesK make it clear the measurements are in K.

That query was written for the article. Foxhound calculates the number in bytes and "normalizes" it for display so that the image shows both "k" and "M" amounts... smaller amounts would show without any letter, and huge amounts with a "G".

Erik said...

I certainly must be missing something in your explanation. I am presuming that the alias "AS TempFileK" should represent the file size in KB, but it seems to me that it is actually reporting size in MB.

Based on the OS report of file size, the size of my temp file is
3,270,479,872.00 bytes
3,193,828.00 KB
3118.97 MB
3.04 GB
Our page size is 4,096 Bytes.
Our page count is 798,457.

page_size * temp_file_pages gives the file size in bytes...is that not correct?

The following query returns the above values as reported by the OS.

SELECT
cast(CAST ( temp_file_pages * page_size as decimal(13,2))AS varchar(50))AS TempFileBytes,
cast(CAST ( temp_file_pages * page_size / 1024 as decimal(12,2)) AS varchar(50))AS TempFileK,
cast(CAST ( temp_file_pages * page_size / 1024 / 1024 as decimal(12,2)) AS varchar(50))AS TempFileM,
cast(CAST ( temp_file_pages * page_size / 1024 / 1024 / 1024 as decimal(4,2)) AS varchar(50))AS TempFileG
FROM
( SELECT
CAST ( DB_EXTENDED_PROPERTY ( 'FileSize', 'temp' ) AS DECIMAL ( 15, 6 ) ) AS temp_file_pages,
CAST ( DB_PROPERTY ( 'PageSize' ) AS DECIMAL ( 15, 6 ) ) AS page_size
) AS sizes;

Breck Carter said...

@Erik: One of the main points of the article is that CONNECTION_PROPERTY ( 'TempFilePages' ) is NOT a measurement of the total number of pages in the file, it is a measurement of the number of pages being used by SQL Anywhere, and it can be (and often is) very much smaller than the file size. The file size is a "high water mark", not a measurement of current requirements.