Column operations statistics

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:

The following single read methods that Spanner provides don't support SPANNER_SYS:

  • Performing a strong read from a single row or multiple rows in a table.
  • Performing a stale read from a single row or multiple rows in a table.
  • Reading from a single row or multiple rows in a secondary index.

For more information, see Single read methods.

Column operations statistics

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

GoogleSQL

    SELECT interval_end,
          table_name,
          column_name,
          write_count
    FROM spanner_sys.column_operations_stats_minute
    WHERE interval_end = (
          SELECT MAX(interval_end)
          FROM spanner_sys.column_operations_stats_minute)
    ORDER BY write_count DESC;

PostgreSQL

    SELECT interval_end,
          table_name,
          column_name,
          write_count
    FROM spanner_sys.column_operations_stats_minute
    WHERE interval_end = (
          SELECT MAX(interval_end)
          FROM spanner_sys.column_operations_stats_minute)
    ORDER BY write_count DESC;

Query the columns with the most query operations for the most recent interval

GoogleSQL

    SELECT interval_end,
          table_name,
          column_name,
          query_count
    FROM spanner_sys.column_operations_stats_minute
    WHERE interval_end = (
          SELECT MAX(interval_end)
          FROM spanner_sys.column_operations_stats_minute)
    ORDER BY query_count DESC;

PostgreSQL

    SELECT interval_end,
          table_name,
          column_name,
          query_count
    FROM spanner_sys.column_operations_stats_minute
    WHERE interval_end = (
          SELECT MAX(interval_end)
          FROM spanner_sys.column_operations_stats_minute)
    ORDER BY query_count DESC;

Query the usage of a column over the last 6 hours

GoogleSQL

    SELECT interval_end,
          read_count,
          query_count,
          write_count
    FROM spanner_sys.column_operations_stats_minute
    WHERE table_name = "table_name"
          AND column_name = "column_name"
    ORDER BY interval_end DESC;
    

Where:

  • table_name must be an existing table or index in the database.
  • column_name must be an existing column in the table.

PostgreSQL

    SELECT interval_end,
          read_count,
          query_count,
          write_count
    FROM spanner_sys.column_operations_stats_minute
    WHERE table_name = 'table_name'
          AND column_name = 'column_name'
    ORDER BY interval_end DESC;
    

Where:

  • table_name must be an existing table or index in the database.
  • column_name must be an existing column in the table.

Query the usage of a column over the last 14 days

GoogleSQL

SELECT interval_end,
       read_count,
       query_count,
       write_count
FROM spanner_sys.column_operations_stats_hour
WHERE interval_end > TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL -14 DAY)
      AND table_name = "table_name"
      AND column_name = "column_name"
ORDER BY interval_end DESC;

Make the following replacements:

  • table_name: table or index name in the database.
  • column_name: column name in the table.

PostgreSQL

SELECT interval_end,
   read_count,
   query_count,
   write_count
FROM spanner_sys.column_operations_stats_hour
WHERE interval_end > spanner.timestamptz_subtract(now(), '14 DAY')
  AND table_name = 'table_name'
  AND column_name = 'column_name'
ORDER BY interval_end DESC;

Make the following replacements:

  • table_name: table or index name in the database.
  • column_name: column name in the table.

What's next