Skip to content
Finitizer
Estimate what a query costs before you run it

This recipe tells you what already happened. The analyzer takes a query you have not run yet and estimates what it will scan, in your browser.

Should my dataset use logical or physical storage billing?

Per-dataset storage cost under both billing models at US multi-region list prices, beside what each dataset pays today.

Reads metadata only, a fraction of a cent to run (10 MB minimum)Reviewed against Google’s docs, 23 Oct 2026

Permissions. Needs bigquery.tables.get and bigquery.tables.list for TABLE_STORAGE (BigQuery Metadata Viewer has them); bigquery.datasets.get on the project for SCHEMATA_OPTIONS (BigQuery Data Viewer has it); bigquery.jobs.create to run any query (BigQuery Job User has it).

Pick the region your data is in: every INFORMATION_SCHEMA view here is qualified by region.

-- Compare the two storage billing models per dataset, and price the
-- model each dataset is on today.
-- US multi-region list prices: logical $0.02/GiB active, $0.01 long-term;
-- physical $0.04/GiB active, $0.02 long-term. Substitute your region's rates.
-- active_physical_bytes already includes the time-travel bytes, so they are
-- not added a second time; fail-safe bytes are billed on top at the active
-- rate. A deleted table bills physical bytes until its time travel and
-- fail-safe windows end, and logical bytes not at all. Base tables only, as
-- in Google's own forecast: clones and snapshots report full-table sizes.
WITH models AS (
  SELECT
    table_schema,
    ROUND(SUM(IF(deleted, 0, active_logical_bytes))    / POW(1024, 3) * 0.02
        + SUM(IF(deleted, 0, long_term_logical_bytes)) / POW(1024, 3) * 0.01, 2) AS logical_model_usd,
    ROUND(SUM(active_physical_bytes + fail_safe_physical_bytes)
            / POW(1024, 3) * 0.04
        + SUM(long_term_physical_bytes) / POW(1024, 3) * 0.02, 2)  AS physical_model_usd,
    ROUND(SAFE_DIVIDE(
      SUM(IF(deleted, 0, total_logical_bytes)),
      SUM(IF(deleted, 0, total_physical_bytes - time_travel_physical_bytes))), 2)
                                                                   AS compression_ratio
  FROM `region-us`.INFORMATION_SCHEMA.TABLE_STORAGE
  WHERE table_type = 'BASE TABLE'
  GROUP BY table_schema
),
billing AS (
  -- A dataset with no storage_billing_model row bills logical bytes.
  SELECT
    schema_name                                                    AS table_schema,
    UPPER(REPLACE(option_value, '"', ''))                          AS billing_model
  FROM `region-us`.INFORMATION_SCHEMA.SCHEMATA_OPTIONS
  WHERE option_name = 'storage_billing_model'
)
SELECT
  m.table_schema,
  IFNULL(b.billing_model, 'LOGICAL')                               AS billing_model,
  IF(IFNULL(b.billing_model, 'LOGICAL') = 'PHYSICAL',
     m.physical_model_usd, m.logical_model_usd)                    AS cost_today_usd,
  m.logical_model_usd,
  m.physical_model_usd,
  m.compression_ratio
FROM models m
LEFT JOIN billing b USING (table_schema)
ORDER BY cost_today_usd DESC;

What it returns

billing_model
The model the dataset is billed on now, from SCHEMATA_OPTIONS. No setting means LOGICAL, the default.
cost_today_usd
Monthly storage cost under the model the dataset is on: the storage cost by dataset.
logical_model_usd
Monthly storage cost under logical (uncompressed) billing.
physical_model_usd
Monthly cost under physical billing, including time travel and fail-safe, which logical billing does not charge for.

How to read it

  • Compare cost_today_usd with the other model. The difference is the monthly saving of a switch, at these list prices.
  • Physical billing charges roughly double per byte but bills the compressed size, so it wins whenever compression beats about 2×. Well-structured columnar data often compresses 4 to 10×.
  • The trap is time travel and fail-safe: logical billing ignores them, physical bills them. A heavily rewritten table can compress well and still be cheaper on logical.
  • The setting is per dataset and there is a cooldown before you can switch back. Verify against your region's real rates before changing anything.

Run this once, or have it run every day.

Finitizer evaluates this class of question continuously against your live BigQuery estate, tracks how each number moves between runs, and turns findings into assigned tasks. Read-only and keyless.

See how Finitizer works