Stay organized with collections
Save and categorize content based on your preferences.
Spanner provides built-in tables that record read, query, and write
operation statistics for your table columns. With column operations statistics
you can do the following:
Identify columns with unexpected read, query, and write traffic.
Identify heavily-used columns.
When you query or write to a column, Spanner increments the
corresponding operation count for that column increments by one, regardless of the
number of rows accessed.
You can monitor a database's overall using metrics that measure
operations-per-second, operations per second by API method, and other
related metrics within your System Insights
charts.
Access column operations statistics
Spanner provides the column operations statistics in the
SPANNER_SYS schema. You can use the following to access SPANNER_SYS data:
A database's Spanner Studio page in the Google Cloud console
The following tables track the read, query, and write statistics on your columns
during a specific time period:
SPANNER_SYS.COLUMN_OPERATIONS_STATS_MINUTE: Operations during 1-minute intervals
SPANNER_SYS.COLUMN_OPERATIONS_STATS_10MINUTE: Operations during 10-minute intervals
SPANNER_SYS.COLUMN_OPERATIONS_STATS_HOUR: Operations during 1-hour intervals
These tables have the following properties:
Each table contains data for non-overlapping time intervals of the length that
the table name specifies.
1-minute intervals start on the minute,
10-minute intervals start every 10 minutes starting on the hour, and 1-hour
intervals start on the hour.
For example, at 11:59:30 AM, SQL queries can access the following most
recent intervals:
1 minute: 11:58:00–11:58:59 AM
10 minute: 11:40:00–11:49:59 AM
1 hour: 10:00:00–10:59:59 AM
Schema for all column operations statistics tables
Column name
Type
Description
INTERVAL_END
TIMESTAMP
End of time interval in which the column usage statistics were collected.
TABLE_NAME
STRING
Name of the table or the index.
COLUMN_NAME
STRING
Name of the column.
READ_COUNT
INT64
Number of reads from the column.
QUERY_COUNT
INT64
Number of queries reading from the column.
WRITE_COUNT
INT64
Number of queries writing to the table.
IS_QUERY_CACHE_MEMORY_CAPPED
BOOL
Whether the statistics collection was capped due to memory pressure.
If you insert data into your database using mutations, Spanner
increments the WRITE_COUNT by 1 for each table that the insert statement
accesses. In addition, a query that accesses an index without scanning the
underlying table only increments the QUERY_COUNT on the index.
Data retention
At a minimum, Spanner keeps data for each table for the following
time periods:
SPANNER_SYS.COLUMN_OPERATIONS_STATS_MINUTE: Intervals covering the previous
six hours.
SPANNER_SYS.COLUMN_OPERATIONS_STATS_10MINUTE: Intervals covering the
previous four days.
SPANNER_SYS.COLUMN_OPERATIONS_STATS_HOUR: Intervals covering the previous 30
days.
Example queries
This section includes several example SQL statements that retrieve aggregate
column operations statistics. You can run these SQL statements using the
client libraries or the
Google Cloud CLI.
Query the table columns with the most write operations for the most recent interval
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Hard to understand","hardToUnderstand","thumb-down"],["Incorrect information or sample code","incorrectInformationOrSampleCode","thumb-down"],["Missing the information/samples I need","missingTheInformationSamplesINeed","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2025-08-07 UTC."],[],[],null,["# Column operations statistics\n\nSpanner provides built-in tables that record read, query, and write\noperation statistics for your table columns. With column operations statistics\nyou can do the following:\n\n- Identify columns with unexpected read, query, and write traffic.\n\n- Identify heavily-used columns.\n\nWhen you query or write to a column, Spanner increments the\ncorresponding operation count for that column increments by one, regardless of the\nnumber of rows accessed.\n\nYou can monitor a database's overall using metrics that measure\noperations-per-second, operations per second by API method, and other\nrelated metrics within your [System Insights](/spanner/docs/monitoring-console)\ncharts.\n\nAccess column operations statistics\n-----------------------------------\n\nSpanner provides the column operations statistics in the\n`SPANNER_SYS` schema. You can use the following to access `SPANNER_SYS` data:\n\n- A database's Spanner Studio page in the Google Cloud console\n\n- The [`gcloud spanner databases execute-sql`](/sdk/gcloud/reference/spanner/databases/execute-sql) command\n\n- The [`executeSql`](/spanner/docs/reference/rest/v1/projects.instances.databases.sessions/executeSql)\n or the [`executeStreamingSql`](/spanner/docs/reference/rest/v1/projects.instances.databases.sessions/executeStreamingSql)\n method.\n\nThe following single read methods that Spanner provides\ndon't support `SPANNER_SYS`:\n\n- Performing a strong read from a single row or multiple rows in a table.\n- Performing a stale read from a single row or multiple rows in a table.\n- Reading from a single row or multiple rows in a secondary index.\n\nFor more information, see [Single read methods](/spanner/docs/reads#single_read_methods).\n\nColumn operations statistics\n----------------------------\n\nThe following tables track the read, query, and write statistics on your columns\nduring a specific time period:\n\n- `SPANNER_SYS.COLUMN_OPERATIONS_STATS_MINUTE`: Operations during 1-minute intervals\n- `SPANNER_SYS.COLUMN_OPERATIONS_STATS_10MINUTE`: Operations during 10-minute intervals\n- `SPANNER_SYS.COLUMN_OPERATIONS_STATS_HOUR`: Operations during 1-hour intervals\n\nThese tables have the following properties:\n\n- Each table contains data for non-overlapping time intervals of the length that\n the table name specifies.\n\n- 1-minute intervals start on the minute,\n 10-minute intervals start every 10 minutes starting on the hour, and 1-hour\n intervals start on the hour.\n\n For example, at 11:59:30 AM, SQL queries can access the following most\n recent intervals:\n - **1 minute**: 11:58:00--11:58:59 AM\n - **10 minute**: 11:40:00--11:49:59 AM\n - **1 hour**: 10:00:00--10:59:59 AM\n\n### Schema for all column operations statistics tables\n\nIf you insert data into your database using mutations, Spanner\nincrements the `WRITE_COUNT` by 1 for each table that the insert statement\naccesses. In addition, a query that accesses an index without scanning the\nunderlying table only increments the `QUERY_COUNT` on the index.\n\nData retention\n--------------\n\nAt a minimum, Spanner keeps data for each table for the following\ntime periods:\n\n- `SPANNER_SYS.COLUMN_OPERATIONS_STATS_MINUTE`: Intervals covering the previous\n six hours.\n\n- `SPANNER_SYS.COLUMN_OPERATIONS_STATS_10MINUTE`: Intervals covering the\n previous four days.\n\n- `SPANNER_SYS.COLUMN_OPERATIONS_STATS_HOUR`: Intervals covering the previous 30\n days.\n\n| **Note:** You can't prevent Spanner from collecting column operations statistics. To delete the data in these tables, you must delete the database associated with them or wait until Spanner removes the data after the data retention period ends.\n\n### Example queries\n\nThis section includes several example SQL statements that retrieve aggregate\ncolumn operations statistics. You can run these SQL statements using the\n[client libraries](/spanner/docs/reference/libraries) or the\n[Google Cloud CLI](/spanner/docs/gcloud-spanner#execute_sql_statements).\n\n#### Query the table columns with the most write operations for the most recent interval\n\n### GoogleSQL\n\n\n```googlesql\n SELECT interval_end,\n table_name,\n column_name,\n write_count\n FROM spanner_sys.column_operations_stats_minute\n WHERE interval_end = (\n SELECT MAX(interval_end)\n FROM spanner_sys.column_operations_stats_minute)\n ORDER BY write_count DESC;\n```\n\n\u003cbr /\u003e\n\n### PostgreSQL\n\n\n```postgresql\n SELECT interval_end,\n table_name,\n column_name,\n write_count\n FROM spanner_sys.column_operations_stats_minute\n WHERE interval_end = (\n SELECT MAX(interval_end)\n FROM spanner_sys.column_operations_stats_minute)\n ORDER BY write_count DESC;\n```\n\n\u003cbr /\u003e\n\n#### Query the columns with the most query operations for the most recent interval\n\n### GoogleSQL\n\n\n```googlesql\n SELECT interval_end,\n table_name,\n column_name,\n query_count\n FROM spanner_sys.column_operations_stats_minute\n WHERE interval_end = (\n SELECT MAX(interval_end)\n FROM spanner_sys.column_operations_stats_minute)\n ORDER BY query_count DESC;\n```\n\n\u003cbr /\u003e\n\n### PostgreSQL\n\n\n```postgresql\n SELECT interval_end,\n table_name,\n column_name,\n query_count\n FROM spanner_sys.column_operations_stats_minute\n WHERE interval_end = (\n SELECT MAX(interval_end)\n FROM spanner_sys.column_operations_stats_minute)\n ORDER BY query_count DESC;\n```\n\n\u003cbr /\u003e\n\n#### Query the usage of a column over the last 6 hours\n\n### GoogleSQL\n\n```googlesql\n SELECT interval_end,\n read_count,\n query_count,\n write_count\n FROM spanner_sys.column_operations_stats_minute\n WHERE table_name = \"\u003cvar translate=\"no\"\u003etable_name\u003c/var\u003e\"\n AND column_name = \"\u003cvar translate=\"no\"\u003ecolumn_name\u003c/var\u003e\"\n ORDER BY interval_end DESC;\n \n```\n\nWhere:\n\n- \u003cvar translate=\"no\"\u003e\u003ccode translate=\"no\" dir=\"ltr\"\u003etable_name\u003c/code\u003e\u003c/var\u003e must be an existing table or index in the database.\n- \u003cvar translate=\"no\"\u003e\u003ccode translate=\"no\" dir=\"ltr\"\u003ecolumn_name\u003c/code\u003e\u003c/var\u003e must be an existing column in the table.\n\n### PostgreSQL\n\n```postgresql\n SELECT interval_end,\n read_count,\n query_count,\n write_count\n FROM spanner_sys.column_operations_stats_minute\n WHERE table_name = '\u003cvar translate=\"no\"\u003etable_name\u003c/var\u003e'\n AND column_name = '\u003cvar translate=\"no\"\u003ecolumn_name\u003c/var\u003e'\n ORDER BY interval_end DESC;\n \n```\n\nWhere:\n\n- \u003cvar translate=\"no\"\u003e\u003ccode translate=\"no\" dir=\"ltr\"\u003etable_name\u003c/code\u003e\u003c/var\u003e must be an existing table or index in the database.\n- \u003cvar translate=\"no\"\u003e\u003ccode translate=\"no\" dir=\"ltr\"\u003ecolumn_name\u003c/code\u003e\u003c/var\u003e must be an existing column in the table.\n\n#### Query the usage of a column over the last 14 days\n\n### GoogleSQL\n\n```googlesql\nSELECT interval_end,\n read_count,\n query_count,\n write_count\nFROM spanner_sys.column_operations_stats_hour\nWHERE interval_end \u003e TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL -14 DAY)\n AND table_name = \"\u003cvar translate=\"no\"\u003etable_name\u003c/var\u003e\"\n AND column_name = \"\u003cvar translate=\"no\"\u003ecolumn_name\u003c/var\u003e\"\nORDER BY interval_end DESC;\n```\n\nMake the following replacements:\n\n- \u003cvar translate=\"no\"\u003e\u003ccode translate=\"no\" dir=\"ltr\"\u003etable_name\u003c/code\u003e\u003c/var\u003e: table or index name in the database.\n- \u003cvar translate=\"no\"\u003e\u003ccode translate=\"no\" dir=\"ltr\"\u003ecolumn_name\u003c/code\u003e\u003c/var\u003e: column name in the table.\n\n### PostgreSQL\n\n```postgresql\nSELECT interval_end,\n read_count,\n query_count,\n write_count\nFROM spanner_sys.column_operations_stats_hour\nWHERE interval_end \u003e spanner.timestamptz_subtract(now(), '14 DAY')\n AND table_name = '\u003cvar translate=\"no\"\u003etable_name\u003c/var\u003e'\n AND column_name = '\u003cvar translate=\"no\"\u003ecolumn_name\u003c/var\u003e'\nORDER BY interval_end DESC;\n```\n\nMake the following replacements:\n\n- \u003cvar translate=\"no\"\u003e\u003ccode translate=\"no\" dir=\"ltr\"\u003etable_name\u003c/code\u003e\u003c/var\u003e: table or index name in the database.\n- \u003cvar translate=\"no\"\u003e\u003ccode translate=\"no\" dir=\"ltr\"\u003ecolumn_name\u003c/code\u003e\u003c/var\u003e: column name in the table.\n\nWhat's next\n-----------\n\n- Learn about other [Built-in statistics tables](/spanner/docs/introspection).\n\n- Learn more about [SQL best practices](/spanner/docs/sql-best-practices) for\n Spanner."]]