BigQuery Load Testing
BigQuery Scheduled Query Load Testing Performance Baseline Stress Testing Slot Estimation Cost Forecasting Production Monitoring
| Metric | Source | Target | Alert Threshold |
|---|---|---|---|
| Query Duration | INFORMATION_SCHEMA.JOBS | < 30 min | > 45 min |
| Bytes Scanned | INFORMATION_SCHEMA.JOBS | Trend stable | > 2x baseline |
| Slot Usage | Cloud Monitoring | < 80% capacity | > 90% capacity |
| Cost per Query | INFORMATION_SCHEMA.JOBS | Within budget | > 150% baseline |
| Failure Rate | Transfer Run logs | 0% | > 0% (any failure) |
| Queue Wait Time | Cloud Monitoring | < 5 sec | > 30 sec |
Performance Measurement
# === BigQuery Performance Queries ===
# Query performance from INFORMATION_SCHEMA
# SELECT
# job_id,
# query,
# creation_time,
# end_time,
# TIMESTAMP_DIFF(end_time, creation_time, SECOND) AS duration_sec,
# total_bytes_processed / POW(1024, 3) AS gb_scanned,
# total_slot_ms,
# total_slot_ms / NULLIF(TIMESTAMP_DIFF(end_time, creation_time, MILLISECOND), 0) AS avg_slots,
# (total_bytes_processed / POW(1024, 4)) * 6.25 AS estimated_cost_usd
# FROM `region-us`.INFORMATION_SCHEMA.JOBS
# WHERE job_type = 'QUERY'
# AND state = 'DONE'
# AND creation_time > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 7 DAY)
# ORDER BY total_slot_ms DESC
# LIMIT 50;
# Scheduled Query specific monitoring
# SELECT
# j.job_id,
# j.creation_time,
# TIMESTAMP_DIFF(j.end_time, j.creation_time, SECOND) AS duration_sec,
# j.total_bytes_processed / POW(1024, 3) AS gb_scanned,
# j.total_slot_ms,
# j.error_result.message AS error
# FROM `region-us`.INFORMATION_SCHEMA.JOBS j
# WHERE j.configuration.query.destination_table.dataset_id = 'analytics'
# AND j.creation_time > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
# ORDER BY j.creation_time DESC;
from dataclasses import dataclass
@dataclass
class LoadTest:
scenario: str
data_size: str
expected_duration: str
expected_slots: int
expected_cost: str
pass_criteria: str
tests = [
LoadTest("Baseline (Current)", "50 GB daily",
"5 minutes", 500, "$0.31/run",
"Duration < 10 min, Cost < $0.50"),
LoadTest("2x Growth", "100 GB daily",
"8 minutes", 800, "$0.63/run",
"Duration < 15 min, Cost < $1.00"),
LoadTest("5x Growth", "250 GB daily",
"15 minutes", 1500, "$1.56/run",
"Duration < 30 min, Cost < $2.00"),
LoadTest("10x Growth", "500 GB daily",
"25 minutes", 2000+, "$3.13/run",
"Duration < 45 min, may need Reservation"),
LoadTest("Peak Concurrent", "5 queries × 50 GB",
"15 minutes (queued)", 2000, "$1.56 total",
"All complete < 30 min, no timeout"),
]
print("=== Load Test Scenarios ===")
for t in tests:
print(f" [{t.scenario}] Data: {t.data_size}")
print(f" Duration: {t.expected_duration} | Slots: {t.expected_slots}")
print(f" Cost: {t.expected_cost}")
print(f" Pass: {t.pass_criteria}")
Slot and Cost Planning
# === Slot and Cost Calculator ===
@dataclass
class PricingTier:
tier: str
pricing: str
slots: str
cost_monthly: str
best_for: str
tiers = [
PricingTier("On-demand", "$6.25 per TB scanned",
"Up to 2000 (shared, best effort)",
"Variable — pay per scan",
"< $2000/month, unpredictable workload"),
PricingTier("Standard Edition", "$0.04/slot-hour",
"Autoscale 0 to max",
"~$1200/month for 100 baseline slots",
"$2K-10K/month, need autoscaling"),
PricingTier("Enterprise Edition", "$0.06/slot-hour",
"Autoscale + advanced features",
"~$1800/month for 100 baseline slots",
"$5K+/month, need governance features"),
PricingTier("Enterprise Plus", "$0.10/slot-hour",
"Highest performance + all features",
"~$3000/month for 100 baseline slots",
"Large enterprise, mission critical"),
]
print("=== Pricing Tiers ===")
for p in tiers:
print(f" [{p.tier}] {p.pricing}")
print(f" Slots: {p.slots}")
print(f" Monthly: {p.cost_monthly}")
print(f" Best for: {p.best_for}")
# Cost estimation
def estimate_monthly_cost(daily_gb, price_per_tb=6.25):
daily_tb = daily_gb / 1024
daily_cost = daily_tb * price_per_tb
monthly_cost = daily_cost * 30
print(f" Daily: {daily_gb} GB = {daily_tb:.3f} TB = ")
print(f" Monthly: ")
return monthly_cost
print(f"\n\nCost Estimation (On-demand):")
for gb in [10, 50, 100, 500, 1000]:
print(f"\n [{gb} GB/day]")
estimate_monthly_cost(gb)
Production Monitoring
# === Monitoring Setup ===
@dataclass
class MonitorAlert:
alert: str
metric: str
condition: str
action: str
channel: str
alerts = [
MonitorAlert("Query Duration Spike",
"INFORMATION_SCHEMA duration",
"Duration > 2x 7-day average",
"Check data growth, optimize query, add slots",
"Slack #data-alerts"),
MonitorAlert("Cost Spike",
"Billing export + bytes_processed",
"Daily cost > 150% of budget",
"Review queries, check partition pruning",
"Email + Slack"),
MonitorAlert("Scheduled Query Failure",
"Transfer run state = FAILED",
"Any failure",
"Check error message, fix and re-run",
"PagerDuty + Slack"),
MonitorAlert("Slot Saturation",
"Cloud Monitoring slot utilization",
"Slot usage > 90% for 10+ min",
"Increase reservation or optimize queries",
"Slack #infra"),
MonitorAlert("Data Freshness",
"MAX(timestamp) in destination table",
"Data > 2 hours stale",
"Check source, check scheduled query status",
"Slack #data-quality"),
]
print("=== Production Alerts ===")
for a in alerts:
print(f" [{a.alert}]")
print(f" Metric: {a.metric}")
print(f" Condition: {a.condition}")
print(f" Action: {a.action}")
print(f" Channel: {a.channel}")
เคล็ดลับ
- Baseline: วัด Baseline ก่อน ดู Duration Slot Cost ปกติ
- Dry Run: ใช้ Dry Run ทุกครั้งก่อน Schedule ดู Cost ล่วงหน้า
- Partition: ใช้ Partitioned Table ลด Scan 50-90% ลด Cost
- Edition: ถ้า Monthly Cost > $2K พิจารณา Edition Pricing
- Alert: ตั้ง Alert สำหรับ Duration Spike Cost Spike Failure ทุกตัว
การนำไปใช้งานจริงในองค์กร
สำหรับองค์กรขนาดกลางถึงใหญ่ แนะนำให้ใช้หลัก Three-Tier Architecture คือ Core Layer ที่เป็นแกนกลางของระบบ Distribution Layer ที่ทำหน้าที่กระจาย Traffic และ Access Layer ที่เชื่อมต่อกับผู้ใช้โดยตรง การแบ่ง Layer ชัดเจนช่วยให้การ Troubleshoot ง่ายขึ้นและสามารถ Scale ระบบได้ตามความต้องการ
เรื่อง Network Security ก็สำคัญไม่แพ้กัน ควรติดตั้ง Next-Generation Firewall ที่สามารถ Deep Packet Inspection ได้ ใช้ Network Segmentation แยก VLAN สำหรับแต่ละแผนก ติดตั้ง IDS/IPS เพื่อตรวจจับการโจมตี และทำ Regular Security Audit อย่างน้อยปีละ 2 ครั้ง
เปรียบเทียบข้อดีและข้อเสีย
จากตารางเปรียบเทียบจะเห็นว่าข้อดีมีมากกว่าข้อเสียอย่างชัดเจน โดยเฉพาะในแง่ของประสิทธิภาพและความสามารถในการ Scale สำหรับข้อเสียส่วนใหญ่สามารถแก้ไขได้ด้วยการเรียนรู้อย่างเป็นระบบและวางแผนทรัพยากรให้เหมาะสม
Load Testing สำหรับ BigQuery คืออะไร
ทดสอบ Scheduled Query ข้อมูลเพิ่ม 10x 50x 100x Duration Slot Bytes Cost SLA Concurrent Peak Load
วัดประสิทธิภาพอย่างไร
INFORMATION_SCHEMA.JOBS total_bytes_processed total_slot_ms Duration Audit Logs Cloud Monitoring Query Plan Shuffle Spill
Slot Estimation ทำอย่างไร
total_slot_ms หาร Duration Average Slots On-demand 2000 Default Queue Reservation Flex Slots Edition Standard Enterprise
Cost Forecasting ทำอย่างไร
On-demand $6.25 per TB Dry Run Monthly Cost Reservation Budget Alert Partitioned Clustering INFORMATION_SCHEMA Edition Pricing
สรุป
BigQuery Scheduled Query Load Testing Performance Slot Estimation Cost Forecasting Partition Clustering Monitoring Alert Edition Production
