惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
A
About on SuperTechFans
IT之家
IT之家
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Blog — PlanetScale
Blog — PlanetScale
aimingoo的专栏
aimingoo的专栏
云风的 BLOG
云风的 BLOG
The GitHub Blog
The GitHub Blog
Vercel News
Vercel News
G
Google Developers Blog
J
Java Code Geeks
宝玉的分享
宝玉的分享
T
Tailwind CSS Blog
Cloudbric
Cloudbric
L
LINUX DO - 最新话题
MyScale Blog
MyScale Blog
H
Heimdal Security Blog
PCI Perspectives
PCI Perspectives
Attack and Defense Labs
Attack and Defense Labs
S
Security @ Cisco Blogs
Latest news
Latest news
I
Intezer
L
Lohrmann on Cybersecurity
C
CXSECURITY Database RSS Feed - CXSecurity.com
月光博客
月光博客
T
Threatpost
博客园 - 【当耐特】
S
Schneier on Security
P
Privacy International News Feed
G
GRAHAM CLULEY
T
Tenable Blog
AWS News Blog
AWS News Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
雷峰网
雷峰网
博客园 - Franky
Engineering at Meta
Engineering at Meta
美团技术团队
S
Secure Thoughts
T
Troy Hunt's Blog
Microsoft Security Blog
Microsoft Security Blog
SecWiki News
SecWiki News
V
Visual Studio Blog
人人都是产品经理
人人都是产品经理
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Cisco Talos Blog
Cisco Talos Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Martin Fowler
Martin Fowler
Webroot Blog
Webroot Blog
Google DeepMind News
Google DeepMind News
H
Hackread – Cybersecurity News, Data Breaches, AI and More

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
How to Optimize BigQuery Costs (Real Techniques That Work)
Arunkumar Am · 2026-05-06 · via DEV Community

I want to start with a number: $140,000.

That's how much a single misconfigured scheduled query cost one of the teams I worked with over a three-month period. Not a rogue machine learning job. Not a massive ETL pipeline. A scheduled query. Running every 15 minutes. Scanning a 4TB table every time. For 90 days before anyone looked at the bill closely enough to notice.

Nobody wrote that query with malicious intent. The engineer who wrote it was experienced. The table had been small when the query was first created. Then the table grew. The query didn't know that. The bill did.

I've spent the better part of the last decade building and optimizing data platforms on GCP — including BigQuery at enterprise scale at Macy's Systems & Technology. This post is what I wish someone had handed me early on. Not the official Google documentation version of cost optimization. The actual production version, including the mistakes that end up in the bill.


First: Understand What You're Actually Paying For

BigQuery has two pricing models and a lot of people mix them up or don't think about which one they're on.

On-demand pricing charges you per byte scanned. As of 2026, that's around $6.25 per TB in most regions. Every query you run, BigQuery measures how much data it touched and charges accordingly. Write a bad query that scans 10TB when it needed to scan 10GB and you've just paid 1,000x more than necessary.

Capacity pricing (flat-rate / editions) charges you for reserved compute slots — basically compute reservations — regardless of how much data you scan. If your workloads are predictable and heavy, this can be dramatically cheaper. If your workloads are bursty and light, on-demand is usually better.

Most teams start on on-demand and never revisit that decision. That's often a mistake. But before you switch, you need to understand your query patterns — and that's what the rest of this post is largely about.


The Single Biggest Lever: Stop Scanning Data You Don't Need

On-demand BigQuery charges by bytes scanned, not bytes returned. That means the columns you don't SELECT and the rows you don't filter still cost money if BigQuery has to read past them.

Never use SELECT *

I know you know this. I also know that half the scheduled queries in your project have SELECT * in them right now. Go check.

-- This scans every column in a 2TB table
SELECT * FROM `project.dataset.orders`
WHERE order_date = '2026-01-15'

-- This scans only what you need
SELECT order_id, customer_id, total_amount
FROM `project.dataset.orders`
WHERE order_date = '2026-01-15'

Enter fullscreen mode Exit fullscreen mode

The second query might cost 10-20x less depending on how wide the table is. For a table with 60 columns where you need 4, the math is brutal.

Use partition pruning — and verify it's working

Partitioned tables are one of BigQuery's most powerful cost controls, but they only work if your query filter actually triggers partition elimination.

-- ✅ This WILL prune partitions (uses the partition column directly)
SELECT order_id, total_amount
FROM `project.dataset.orders`
WHERE order_date BETWEEN '2026-01-01' AND '2026-01-31'

-- ❌ This will NOT prune partitions (wraps the column in a function)
SELECT order_id, total_amount
FROM `project.dataset.orders`
WHERE DATE(order_timestamp) BETWEEN '2026-01-01' AND '2026-01-31'

Enter fullscreen mode Exit fullscreen mode

The second query looks like it should be equivalent. It isn't — wrapping the partition column in a function forces a full table scan. This is one of the most common and expensive mistakes I see in production.

How to verify: Run the query and look at the execution details. If you see "Partitions scanned: 1 of 365" — great, it's working. If you see "Partitions scanned: 365 of 365" on a query filtering a single day — your filter isn't hitting the partition column the way you think it is.

Cluster your tables

Partitioning handles time-based filtering. Clustering handles everything else. If you're frequently filtering by customer_id, product_id, store_id, or region — those columns should be in your clustering key.

CREATE TABLE `project.dataset.orders`
PARTITION BY DATE(order_timestamp)
CLUSTER BY customer_id, store_id
OPTIONS (require_partition_filter = TRUE)
AS SELECT * FROM `project.dataset.orders_raw`

Enter fullscreen mode Exit fullscreen mode

That require_partition_filter = TRUE option is worth calling out explicitly. It makes BigQuery reject any query that doesn't include a partition filter. Annoying to developers at first. Saves you from the $140,000 mistake I mentioned at the top.


Materialized Views: The Most Underused Feature in BigQuery

Most people know materialized views exist. Few people use them properly for cost optimization.

Here's the thing about BigQuery materialized views that isn't obvious: they can answer queries even when the query doesn't directly reference them. BigQuery's query optimizer will automatically rewrite a query against a base table to use a materialized view instead, if the view can satisfy the query and is more efficient.

-- Create the materialized view
CREATE MATERIALIZED VIEW `project.dataset.daily_sales_mv`
PARTITION BY sale_date
AS
SELECT
  DATE(order_timestamp)     AS sale_date,
  store_id,
  product_id,
  SUM(quantity)             AS total_units,
  SUM(total_amount)         AS total_revenue,
  COUNT(DISTINCT order_id)  AS order_count
FROM `project.dataset.orders`
GROUP BY 1, 2, 3;

Enter fullscreen mode Exit fullscreen mode

Now here's where it gets interesting. A dashboard query that does:

SELECT store_id, SUM(total_amount) AS revenue
FROM `project.dataset.orders`
WHERE DATE(order_timestamp) = '2026-01-15'
GROUP BY store_id

Enter fullscreen mode Exit fullscreen mode

...might get automatically rewritten to query the materialized view instead of the full orders table — even though the query never mentioned the materialized view. That's BigQuery doing the cost optimization for you, provided you've set things up right.

The maintenance overhead is minimal. The cost reduction on heavily queried aggregations can be 80-95%.


Query Cost Estimation Before You Run

This one sounds obvious but is skipped constantly: estimate cost before running unfamiliar queries, especially on large tables.

In BigQuery console, every query shows a bytes-to-be-processed estimate in the top right before execution. Pay attention to it.

In code, you can do a dry run:

from google.cloud import bigquery

client = bigquery.Client()

job_config = bigquery.QueryJobConfig(dry_run=True, use_query_cache=True)

query = """
    SELECT *
    FROM `project.dataset.large_table`
    WHERE region = 'US'
"""

job = client.query(query, job_config=job_config)

# Bytes processed if this query ran
bytes_processed = job.total_bytes_processed
gb_processed = bytes_processed / (1024 ** 3)
estimated_cost = (bytes_processed / (1024 ** 4)) * 6.25  # $6.25 per TB

print(f"This query would scan: {gb_processed:.2f} GB")
print(f"Estimated cost: ${estimated_cost:.4f}")

Enter fullscreen mode Exit fullscreen mode

Build this into your data pipeline development workflow. Make developers run a dry-run estimate before merging new queries into production. It takes 30 seconds. It occasionally saves you $10,000.


Slots, Reservations, and When Flat-Rate Actually Makes Sense

The on-demand vs. flat-rate decision is one that most teams make once and never revisit. That's a mistake because the right answer changes as your workload matures.

On-demand is usually right when:

  • Your query volume is unpredictable or spiky
  • You're early-stage and still figuring out your workload patterns
  • Your monthly BigQuery bill is under ~$2,000

Flat-rate (Editions) is usually right when:

  • You have consistent, heavy query workloads running throughout the day
  • You're running large-scale batch processing jobs on a schedule
  • Your on-demand bill has stabilized and is consistently above ~$3,000/month

The crossover point depends on your region and edition tier, but a rough rule: if you're consistently buying more than 500 slot-hours per month at on-demand prices, flat-rate reservations are worth modeling out.

One trap to avoid: Buying flat-rate capacity and then not using it. Idle reserved slots cost the same as busy ones. If you're going to commit to flat-rate, you need to actually fill those slots — which means scheduling your heavy batch jobs during off-peak hours to maximize slot utilization.

-- Check your slot utilization in INFORMATION_SCHEMA
SELECT
  TIMESTAMP_TRUNC(period_start, HOUR)     AS hour,
  project_id,
  SUM(period_slot_ms) / (1000 * 3600)    AS slot_hours_used
FROM `region-us`.INFORMATION_SCHEMA.TIMELINE_BY_PROJECT
WHERE period_start >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 7 DAY)
GROUP BY 1, 2
ORDER BY 1 DESC

Enter fullscreen mode Exit fullscreen mode

Run this before committing to any reservation purchase. If you're averaging 40 slot-hours per hour during business hours and near-zero overnight, a flat-rate reservation sized for your peak will be mostly idle.


INFORMATION_SCHEMA: Your Cost Debugging Best Friend

BigQuery's INFORMATION_SCHEMA views are where you find the expensive queries. Most people don't use them nearly enough.

Find your most expensive queries from the last 30 days

SELECT
  job_id,
  user_email,
  ROUND(total_bytes_processed / POW(1024, 4), 4)  AS tb_processed,
  ROUND((total_bytes_processed / POW(1024, 4)) * 6.25, 2) AS estimated_cost_usd,
  SUBSTR(query, 0, 200)                            AS query_preview,
  creation_time
FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT
WHERE
  creation_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
  AND job_type = 'QUERY'
  AND state = 'DONE'
ORDER BY total_bytes_processed DESC
LIMIT 25

Enter fullscreen mode Exit fullscreen mode

Run this query once a week. The top 5 results are almost always where your money is going. In my experience, fixing the top 3 queries on this list typically cuts the bill by 30-50%.

Find queries run by service accounts that are scanning too much

SELECT
  user_email,
  COUNT(*) AS query_count,
  ROUND(SUM(total_bytes_processed) / POW(1024, 4), 2) AS total_tb_processed,
  ROUND(SUM(total_bytes_processed) / POW(1024, 4) * 6.25, 2) AS total_cost_usd
FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT
WHERE
  creation_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
  AND job_type = 'QUERY'
GROUP BY user_email
ORDER BY total_tb_processed DESC

Enter fullscreen mode Exit fullscreen mode

Service accounts running scheduled queries are frequently the biggest offenders because nobody's watching them. A dashboard refresh that runs every 15 minutes against an unpartitioned table is 2,880 queries per month. Do the math on what each of those costs and multiply.


Caching: Free Is Good, When It Works

BigQuery caches query results for 24 hours. Identical queries (same SQL, same referenced tables, no changes to underlying data) return cached results at zero cost.

This sounds great. It has a few gotchas:

  • Caching doesn't work if your query uses non-deterministic functions like CURRENT_TIMESTAMP(), NOW(), or RAND()
  • Caching doesn't work if you explicitly disable it
  • Caching doesn't work across projects by default

The biggest practical implication: don't put CURRENT_DATE() or CURRENT_TIMESTAMP() directly in scheduled queries if you can help it. Pass the date as a parameter instead. An identical parameterized query against a table that hasn't changed since the last run will hit the cache. A query with an inline CURRENT_DATE() won't.

-- ❌ This will never hit cache (current_date() makes it non-deterministic)
SELECT store_id, SUM(revenue)
FROM `project.dataset.daily_sales`
WHERE sale_date = CURRENT_DATE()
GROUP BY store_id

-- ✅ Pass the date as a scripting variable or scheduled query parameter
DECLARE run_date DATE DEFAULT DATE('2026-01-15');

SELECT store_id, SUM(revenue)
FROM `project.dataset.daily_sales`
WHERE sale_date = run_date
GROUP BY store_id

Enter fullscreen mode Exit fullscreen mode


The Cost Optimization Mindset Shift

Here's the thing that took me the longest to internalize: BigQuery cost optimization is not a one-time project. It's a continuous practice.

Tables grow. Query patterns change. New analysts join the team and write queries the way they're used to writing queries in other systems. A dashboard that was cheap six months ago isn't necessarily cheap today because the underlying table is now 10x larger.

The teams that control their BigQuery costs over the long term are the ones that have made it a habit — weekly cost reviews, dry-run estimates as part of code review, INFORMATION_SCHEMA queries on a dashboard that someone actually looks at.

The teams that get surprised by the bill are the ones that set it up and assumed it would stay efficient on its own.

It won't. But with the right habits, it's absolutely manageable — and the savings compound faster than you'd expect.


Quick Reference Checklist

Before you ship any new BigQuery query or table to production, run through this:

  • [ ] No SELECT * — only columns you need
  • [ ] Table is partitioned on the most common filter column
  • [ ] Partition filter is on the raw column, not wrapped in a function
  • [ ] Clustering keys match your most common WHERE and JOIN conditions
  • [ ] require_partition_filter = TRUE for large tables
  • [ ] Dry-run estimate reviewed before merging
  • [ ] Materialized view considered for any aggregation queried more than daily
  • [ ] No CURRENT_TIMESTAMP() inline if caching matters
  • [ ] Scheduled query frequency matches actual business need (not "every 15 minutes because that was the default")

Wrapping Up

The $140,000 story at the top of this post isn't the worst one I've heard. It's not even close. BigQuery cost disasters tend to be quiet — they accumulate over weeks or months before anyone notices, and by then the money is gone.

The good news: almost every expensive pattern is avoidable, and most of them are avoidable with techniques that also make your queries faster. Partition pruning, clustering, materialized views, proper column selection — these aren't just cost controls. They're good engineering.

Start with INFORMATION_SCHEMA. Find your top 5 most expensive queries. Fix them. Repeat monthly. You'll be surprised how quickly the bill responds.


Have a BigQuery cost story of your own? Drop it in the comments — the good ones are always educational (and occasionally horrifying).


Arunkumar Amaran — Tech Manager, Data Engineering & Architecture at Macy's Systems & Technology. 20+ years building enterprise data platforms on GCP, AWS, and Azure. IEEE Senior Member. Writes about the things that don't make it into the official docs.

🔗 linkedin.com/in/arunkumar-amaran · 📧 arunkumar.amaran@ieee.org

Opinions are my own and do not represent my employer.