Skip to content

Data and Analytics Services - Cloud Engineer

πŸ“– Data Analytics Products - Google Cloud data and analytics services

Cloud Storage

Overview

  • Object storage service for unstructured data
  • Highly durable (99.999999999% durability)
  • Scalable to exabytes
  • Worldwide accessibility with low latency
  • Integrated with all GCP services

Storage Classes

Class Use Case Min Storage Retrieval Cost Monthly Cost/GB
Standard Frequently accessed data None None $0.020
Nearline < 1x/month access 30 days $0.01/GB $0.010
Coldline < 1x/quarter access 90 days $0.02/GB $0.004
Archive < 1x/year access 365 days $0.05/GB $0.0012

πŸ“– Storage Classes Guide - Choose the right storage class πŸ“– gsutil Tool - Command-line tool for Cloud Storage

Bucket Creation and Management

# Create bucket
gsutil mb -c STANDARD -l us-central1 gs://my-bucket

# Create multi-regional bucket
gsutil mb -c STANDARD -l us gs://my-multi-region-bucket

# Set storage class
gsutil defstorageclass set NEARLINE gs://my-bucket

# Enable versioning
gsutil versioning set on gs://my-bucket

# Check versioning status
gsutil versioning get gs://my-bucket

# Upload file
gsutil cp file.txt gs://my-bucket/

# Upload folder recursively
gsutil -m cp -r ./folder gs://my-bucket/

# List bucket contents
gsutil ls gs://my-bucket

# List with details (size, timestamp)
gsutil ls -l gs://my-bucket

# Download file
gsutil cp gs://my-bucket/file.txt ./

# Sync directories
gsutil rsync -r ./local-dir gs://my-bucket/remote-dir

# Delete file
gsutil rm gs://my-bucket/file.txt

# Delete bucket (must be empty)
gsutil rb gs://my-bucket

Lifecycle Policies

# Create lifecycle policy file (lifecycle.json)
cat > lifecycle.json <<EOF
{
  "lifecycle": {
    "rule": [
      {
        "action": {"type": "SetStorageClass", "storageClass": "NEARLINE"},
        "condition": {"age": 30}
      },
      {
        "action": {"type": "SetStorageClass", "storageClass": "COLDLINE"},
        "condition": {"age": 90}
      },
      {
        "action": {"type": "Delete"},
        "condition": {"age": 365}
      }
    ]
  }
}
EOF

# Apply lifecycle policy
gsutil lifecycle set lifecycle.json gs://my-bucket

# View lifecycle policy
gsutil lifecycle get gs://my-bucket

Retention Policies and Locks

# Set retention policy (90 days)
gsutil retention set 90d gs://my-bucket

# View retention policy
gsutil retention get gs://my-bucket

# Lock retention policy (IRREVERSIBLE)
gsutil retention lock gs://my-bucket

# Remove retention policy (only if not locked)
gsutil retention clear gs://my-bucket

Object Versioning

# Enable versioning
gsutil versioning set on gs://my-bucket

# List all versions
gsutil ls -a gs://my-bucket/file.txt

# Copy specific version
gsutil cp gs://my-bucket/file.txt#1234567890 ./file-old.txt

# Delete specific version
gsutil rm gs://my-bucket/file.txt#1234567890

# Delete all versions
gsutil rm -a gs://my-bucket/file.txt

Signed URLs

# Create signed URL (valid for 1 hour)
gsutil signurl -d 1h key.json gs://my-bucket/file.txt

# Create signed URL with custom HTTP method
gsutil signurl -m PUT -d 1h key.json gs://my-bucket/file.txt

# Using gcloud
gcloud storage sign-url gs://my-bucket/file.txt --duration=1h

IAM vs ACLs

IAM (Recommended): - Apply permissions at bucket or project level - Role-based access control - Integrates with organization policies - Uniform bucket-level access

ACLs (Legacy): - Object-level permissions - Finer-grained control - Can conflict with IAM

# Enable uniform bucket-level access (IAM only)
gsutil uniformbucketlevelaccess set on gs://my-bucket

# Grant IAM role
gsutil iam ch user:user@example.com:objectViewer gs://my-bucket

# View IAM policy
gsutil iam get gs://my-bucket

# Set ACL (if uniform access disabled)
gsutil acl set private gs://my-bucket/file.txt

# Grant ACL permission
gsutil acl ch -u user@example.com:READ gs://my-bucket/file.txt

Cloud SQL

Overview

  • Fully managed relational database service
  • Supports MySQL, PostgreSQL, SQL Server
  • Automated backups, replication, failover
  • High availability with 99.95% SLA
  • Scale up to 96 CPU cores, 624 GB RAM

πŸ“– Cloud SQL Overview - Managed relational databases πŸ“– Backup and Recovery - Backup and restore operations

Instance Creation

# Create MySQL instance
gcloud sql instances create my-instance \
  --database-version=MYSQL_8_0 \
  --tier=db-n1-standard-1 \
  --region=us-central1 \
  --root-password=mypassword \
  --backup \
  --backup-start-time=03:00

# Create PostgreSQL instance
gcloud sql instances create pg-instance \
  --database-version=POSTGRES_15 \
  --tier=db-custom-2-8192 \
  --region=us-central1 \
  --root-password=mypassword

# List instances
gcloud sql instances list

# Describe instance
gcloud sql instances describe my-instance

# Delete instance
gcloud sql instances delete my-instance

Machine Types and Sizing

# Shared-core (dev/test)
--tier=db-f1-micro      # 0.6 GB RAM
--tier=db-g1-small      # 1.7 GB RAM

# Standard
--tier=db-n1-standard-1  # 1 CPU, 3.75 GB
--tier=db-n1-standard-2  # 2 CPU, 7.5 GB
--tier=db-n1-standard-4  # 4 CPU, 15 GB

# High memory
--tier=db-n1-highmem-2   # 2 CPU, 13 GB
--tier=db-n1-highmem-4   # 4 CPU, 26 GB

# Custom
--tier=db-custom-2-8192  # 2 CPU, 8 GB (8192 MB)

High Availability Configuration

# Create HA instance
gcloud sql instances create ha-instance \
  --database-version=MYSQL_8_0 \
  --tier=db-n1-standard-2 \
  --region=us-central1 \
  --availability-type=REGIONAL \
  --root-password=mypassword

# Enable HA on existing instance
gcloud sql instances patch my-instance \
  --availability-type=REGIONAL

# Disable HA (fallback to zonal)
gcloud sql instances patch my-instance \
  --availability-type=ZONAL

Read Replicas

# Create read replica
gcloud sql instances create my-replica \
  --master-instance-name=my-instance \
  --tier=db-n1-standard-1 \
  --region=us-east1

# Create read replica in same region
gcloud sql instances create my-local-replica \
  --master-instance-name=my-instance \
  --tier=db-n1-standard-1

# Promote replica to standalone
gcloud sql instances promote-replica my-replica

# Delete replica
gcloud sql instances delete my-replica

Backups and Point-in-Time Recovery

# Enable automated backups
gcloud sql instances patch my-instance \
  --backup-start-time=03:00 \
  --backup-location=us

# Create on-demand backup
gcloud sql backups create \
  --instance=my-instance \
  --description="Manual backup before upgrade"

# List backups
gcloud sql backups list --instance=my-instance

# Restore from backup
gcloud sql backups restore BACKUP_ID \
  --backup-instance=my-instance \
  --backup-id=1234567890

# Clone instance (creates new instance from backup)
gcloud sql instances clone my-instance cloned-instance

# Enable binary logging (required for PITR)
gcloud sql instances patch my-instance \
  --enable-bin-log

# Point-in-time recovery (restore to specific timestamp)
gcloud sql instances restore-backup my-instance \
  --backup-id=BACKUP_ID \
  --backup-instance=SOURCE_INSTANCE

Database and User Management

# Create database
gcloud sql databases create mydb --instance=my-instance

# List databases
gcloud sql databases list --instance=my-instance

# Delete database
gcloud sql databases delete mydb --instance=my-instance

# Create user
gcloud sql users create myuser \
  --instance=my-instance \
  --password=mypassword

# List users
gcloud sql users list --instance=my-instance

# Change user password
gcloud sql users set-password myuser \
  --instance=my-instance \
  --password=newpassword

# Delete user
gcloud sql users delete myuser --instance=my-instance

Connection Methods

# Connect via Cloud SQL Proxy
./cloud_sql_proxy -instances=PROJECT:REGION:INSTANCE=tcp:3306

# Connect from local machine
gcloud sql connect my-instance --user=root

# Get connection name
gcloud sql instances describe my-instance --format="value(connectionName)"

# Authorize external IP
gcloud sql instances patch my-instance \
  --authorized-networks=203.0.113.5/32

Maintenance Windows

# Set maintenance window (Sunday 3 AM)
gcloud sql instances patch my-instance \
  --maintenance-window-day=SUN \
  --maintenance-window-hour=3

# Enable maintenance notifications
gcloud sql instances patch my-instance \
  --maintenance-release-channel=production

# Deny maintenance period (no updates during black Friday)
gcloud sql instances patch my-instance \
  --deny-maintenance-period-start-date=2025-11-20 \
  --deny-maintenance-period-end-date=2025-11-30

Cloud Spanner

Overview

  • Globally distributed, horizontally scalable relational database
  • Strong consistency across regions
  • SQL queries with ACID transactions
  • Automatic sharding and replication
  • 99.999% availability SLA for multi-region

πŸ“– Cloud Spanner Overview - Global relational database πŸ“– Spanner Schema Design - Schema and data model best practices

Instance Configuration

# Create regional instance
gcloud spanner instances create my-instance \
  --config=regional-us-central1 \
  --nodes=1 \
  --description="Regional Spanner instance"

# Create multi-region instance
gcloud spanner instances create global-instance \
  --config=nam3 \
  --processing-units=1000 \
  --description="Multi-region instance"

# List available configurations
gcloud spanner instance-configs list

# Update node count (scaling)
gcloud spanner instances update my-instance --nodes=3

# Update processing units (finer-grained scaling)
gcloud spanner instances update my-instance --processing-units=500

# Delete instance
gcloud spanner instances delete my-instance

Configuration Types

  • Regional: Single region, 99.99% SLA (e.g., us-central1)
  • Multi-Regional: Span multiple regions, 99.999% SLA (e.g., nam3, eur3)
  • Custom: Configure your own read-write regions

Database and Schema Management

# Create database
gcloud spanner databases create mydb \
  --instance=my-instance

# Create database with DDL
gcloud spanner databases create mydb \
  --instance=my-instance \
  --ddl="CREATE TABLE Users (
    UserId INT64 NOT NULL,
    Name STRING(100),
    Email STRING(100)
  ) PRIMARY KEY (UserId)"

# Execute DDL
gcloud spanner databases ddl update mydb \
  --instance=my-instance \
  --ddl="CREATE TABLE Orders (
    OrderId INT64 NOT NULL,
    UserId INT64 NOT NULL,
    Amount FLOAT64,
    CreatedAt TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true)
  ) PRIMARY KEY (OrderId)"

# List databases
gcloud spanner databases list --instance=my-instance

# Delete database
gcloud spanner databases delete mydb --instance=my-instance

Interleaved Tables

Interleaving physically co-locates child rows with parent rows for better performance.

-- Parent table
CREATE TABLE Users (
  UserId INT64 NOT NULL,
  Name STRING(100)
) PRIMARY KEY (UserId);

-- Interleaved child table
CREATE TABLE Orders (
  UserId INT64 NOT NULL,
  OrderId INT64 NOT NULL,
  Amount FLOAT64
) PRIMARY KEY (UserId, OrderId),
  INTERLEAVE IN PARENT Users ON DELETE CASCADE;
# Create interleaved tables
gcloud spanner databases ddl update mydb \
  --instance=my-instance \
  --ddl="CREATE TABLE Users (UserId INT64, Name STRING(100)) PRIMARY KEY (UserId);
        CREATE TABLE Orders (UserId INT64, OrderId INT64, Amount FLOAT64)
        PRIMARY KEY (UserId, OrderId), INTERLEAVE IN PARENT Users ON DELETE CASCADE;"

Secondary Indexes

# Create index
gcloud spanner databases ddl update mydb \
  --instance=my-instance \
  --ddl="CREATE INDEX UsersByEmail ON Users(Email)"

# Create unique index
gcloud spanner databases ddl update mydb \
  --instance=my-instance \
  --ddl="CREATE UNIQUE INDEX UsersByEmail ON Users(Email)"

# Create storing index (include extra columns)
gcloud spanner databases ddl update mydb \
  --instance=my-instance \
  --ddl="CREATE INDEX UsersByEmail ON Users(Email) STORING (Name)"

# Drop index
gcloud spanner databases ddl update mydb \
  --instance=my-instance \
  --ddl="DROP INDEX UsersByEmail"

Queries and Transactions

# Execute query
gcloud spanner databases execute-sql mydb \
  --instance=my-instance \
  --sql="SELECT * FROM Users WHERE UserId = 1"

# Execute DML
gcloud spanner databases execute-sql mydb \
  --instance=my-instance \
  --sql="INSERT INTO Users (UserId, Name, Email) VALUES (1, 'John', 'john@example.com')"

Bigtable

Overview

  • NoSQL wide-column database
  • Petabyte-scale, sub-10ms latency
  • Ideal for time-series, IoT, analytics workloads
  • HBase compatible
  • Linear scalability

πŸ“– Bigtable Overview - NoSQL database service πŸ“– Schema Design for Time Series - Time-series data patterns

Instance and Cluster Creation

# Create instance with cluster
gcloud bigtable instances create my-instance \
  --display-name="My Bigtable Instance" \
  --cluster=my-cluster \
  --cluster-zone=us-central1-a \
  --cluster-num-nodes=3 \
  --instance-type=PRODUCTION

# Create development instance (single node)
gcloud bigtable instances create dev-instance \
  --display-name="Dev Instance" \
  --cluster=dev-cluster \
  --cluster-zone=us-central1-a \
  --cluster-num-nodes=1 \
  --instance-type=DEVELOPMENT

# List instances
gcloud bigtable instances list

# Update instance (scaling)
gcloud bigtable clusters update my-cluster \
  --instance=my-instance \
  --num-nodes=5

# Enable autoscaling
gcloud bigtable clusters update my-cluster \
  --instance=my-instance \
  --autoscaling-min-nodes=3 \
  --autoscaling-max-nodes=10 \
  --autoscaling-cpu-target=70

# Delete instance
gcloud bigtable instances delete my-instance

Table Creation and Management

# Create table
cbt -project=my-project -instance=my-instance createtable my-table

# List tables
cbt -project=my-project -instance=my-instance ls

# Create column family
cbt -project=my-project -instance=my-instance createfamily my-table cf1

# Set garbage collection policy (keep last 7 days)
cbt -project=my-project -instance=my-instance setgcpolicy my-table cf1 maxage=7d

# Set GC policy (keep last 3 versions)
cbt -project=my-project -instance=my-instance setgcpolicy my-table cf1 maxversions=3

# Write data
cbt -project=my-project -instance=my-instance set my-table r1 cf1:c1=value1

# Read data
cbt -project=my-project -instance=my-instance read my-table

# Read specific row
cbt -project=my-project -instance=my-instance lookup my-table r1

# Delete table
cbt -project=my-project -instance=my-instance deletetable my-table

Row Key Design Best Practices

Critical for performance: 1. Avoid monotonically increasing keys (timestamps, sequential IDs) - Bad: timestamp#user_id - Good: reverse_domain#timestamp or user_id#timestamp

  1. Distribute writes evenly
  2. Use hash prefix: md5(user_id)[:4]#user_id#timestamp
  3. Reverse timestamps: Long.MAX_VALUE - timestamp

  4. Design for access patterns

  5. If querying by user: user_id#timestamp
  6. If querying by device: device_id#timestamp

  7. Keep row keys short (4-100 bytes optimal)

Column Families and Columns

# Multiple column families
cbt createfamily my-table profile
cbt createfamily my-table metrics
cbt createfamily my-table logs

# Set different GC policies
cbt setgcpolicy my-table profile maxversions=1
cbt setgcpolicy my-table metrics maxage=30d
cbt setgcpolicy my-table logs maxage=7d or maxversions=3

Replication

# Add replica cluster
gcloud bigtable clusters create my-cluster-replica \
  --instance=my-instance \
  --zone=us-east1-b \
  --num-nodes=3

# List clusters
gcloud bigtable clusters list --instances=my-instance

# Create app profile for single-cluster routing
gcloud bigtable app-profiles create single-cluster-profile \
  --instance=my-instance \
  --route-to=my-cluster

# Create app profile for multi-cluster routing (replication)
gcloud bigtable app-profiles create multi-cluster-profile \
  --instance=my-instance \
  --route-any

# Update app profile
gcloud bigtable app-profiles update multi-cluster-profile \
  --instance=my-instance \
  --route-to=my-cluster-replica

Firestore / Datastore

Overview

  • NoSQL document database
  • Strong consistency within region
  • Automatic scaling
  • ACID transactions
  • Real-time updates (Firestore Native mode)

Modes: - Datastore mode: Server-side applications, no real-time updates - Native mode: Mobile/web apps, real-time sync

Database Creation

# Create Firestore database (Native mode)
gcloud firestore databases create \
  --location=us-central \
  --type=firestore-native

# Create Datastore database
gcloud firestore databases create \
  --location=us-central \
  --type=datastore-mode

# Note: Only one database per project (default), multiple databases in preview

Collections and Documents

# Datastore: Create entity (via gcloud)
gcloud datastore entities create --kind=User \
  --properties='name:string=John,email:string=john@example.com,age:integer=30'

# Query entities
gcloud datastore queries fetch --kind=User

# Delete entity
gcloud datastore entities delete --kind=User --keys=KEY_ID

Indexes

Single-field indexes: Automatic Composite indexes: Must be defined

# index.yaml
indexes:
- kind: Task
  properties:
  - name: priority
    direction: desc
  - name: created
    direction: asc

- kind: Order
  properties:
  - name: status
  - name: amount
    direction: desc
# Deploy indexes
gcloud datastore indexes create index.yaml

# List indexes
gcloud datastore indexes list

# Cleanup unused indexes
gcloud datastore indexes cleanup index.yaml

Queries and Transactions

# Export data
gcloud datastore export gs://my-bucket/datastore-export \
  --kinds=User,Order \
  --namespaces=default

# Import data
gcloud datastore import gs://my-bucket/datastore-export/export.overall_export_metadata

# Operations list
gcloud datastore operations list

BigQuery

Overview

  • Serverless data warehouse
  • SQL queries on petabyte-scale data
  • Columnar storage
  • No infrastructure management
  • Sub-second query response

πŸ“– BigQuery Overview - Serverless data warehouse πŸ“– Query Best Practices - Optimize query performance πŸ“– Cost Optimization - Control BigQuery costs

Dataset and Table Creation

# Create dataset
bq mk --dataset --location=US --default_table_expiration=3600 my_dataset

# Create dataset with description
bq mk --dataset \
  --description="Sales data warehouse" \
  --location=us-central1 \
  my_project:sales_data

# List datasets
bq ls

# List datasets in project
bq ls --project_id=my_project

# Show dataset details
bq show my_dataset

# Create table from schema
bq mk --table my_dataset.my_table schema.json

# Create table with inline schema
bq mk --table my_dataset.users \
  user_id:INTEGER,name:STRING,email:STRING,created:TIMESTAMP

# Create external table (data in Cloud Storage)
bq mk --external_table_definition=schema.json@CSV=gs://my-bucket/data.csv \
  my_dataset.external_table

# Load data from CSV
bq load --source_format=CSV \
  my_dataset.my_table \
  gs://my-bucket/data.csv \
  schema.json

# Load data with autodetect schema
bq load --autodetect \
  --source_format=CSV \
  my_dataset.my_table \
  gs://my-bucket/data.csv

# Delete table
bq rm -t my_dataset.my_table

# Delete dataset
bq rm -r -d my_dataset

Partitioning

Benefits: Reduce query costs, improve performance

# Create time-partitioned table (ingestion time)
bq mk --table \
  --time_partitioning_type=DAY \
  my_dataset.partitioned_table \
  schema.json

# Create time-partitioned table (on specific column)
bq mk --table \
  --time_partitioning_type=DAY \
  --time_partitioning_field=transaction_date \
  my_dataset.transactions \
  schema.json

# Create integer-range partitioned table
bq mk --table \
  --range_partitioning=customer_id,0,1000000,100 \
  my_dataset.customers \
  schema.json

# Partition expiration (90 days)
bq mk --table \
  --time_partitioning_type=DAY \
  --time_partitioning_expiration=7776000 \
  my_dataset.logs \
  schema.json

# Query partitioned table (cost optimization)
bq query --use_legacy_sql=false '
SELECT *
FROM `my_dataset.transactions`
WHERE transaction_date = "2025-01-15"
'

Clustering

Benefits: Further optimize queries within partitions

# Create partitioned + clustered table
bq mk --table \
  --time_partitioning_type=DAY \
  --time_partitioning_field=date \
  --clustering_fields=customer_id,product_id \
  my_dataset.sales \
  schema.json

# Best practices:
# - Cluster on columns frequently used in WHERE/JOIN
# - Up to 4 clustering columns
# - Order matters (most selective first)

Materialized Views

# Create materialized view
bq query --use_legacy_sql=false '
CREATE MATERIALIZED VIEW my_dataset.daily_sales AS
SELECT
  DATE(order_timestamp) as order_date,
  product_id,
  SUM(amount) as total_sales
FROM my_dataset.orders
GROUP BY order_date, product_id
'

# Refresh materialized view
bq query --use_legacy_sql=false '
REFRESH MATERIALIZED VIEW my_dataset.daily_sales
'

# Query will automatically use materialized view when beneficial

Slots and Reservations

# List reservations
bq ls --reservations --location=us-central1 --project_id=my_project

# Create reservation (flat-rate pricing)
bq mk --reservation \
  --location=us-central1 \
  --slots=500 \
  production_reservation

# Create assignment (link reservation to project/folder/org)
bq mk --reservation_assignment \
  --reservation_id=production_reservation \
  --job_type=QUERY \
  --assignee_type=PROJECT \
  --assignee_id=my_project

# Update reservation slots
bq update --reservation \
  --location=us-central1 \
  --slots=1000 \
  production_reservation

Query Optimization

# Dry run to estimate costs
bq query --dry_run --use_legacy_sql=false '
SELECT * FROM my_dataset.large_table
'

# Query with destination table
bq query --use_legacy_sql=false \
  --destination_table=my_dataset.results \
  --replace \
  'SELECT * FROM my_dataset.source_table WHERE date > "2025-01-01"'

# Query with table expiration
bq query --use_legacy_sql=false \
  --destination_table=my_dataset.temp_results \
  --time_partitioning_expiration=86400 \
  'SELECT * FROM my_dataset.source'

# Query with caching disabled
bq query --use_legacy_sql=false --use_cache=false 'SELECT ...'

# Extract query results to Cloud Storage
bq extract --destination_format=CSV \
  my_dataset.results \
  gs://my-bucket/results-*.csv

Advanced Queries

# Query with parameters
bq query --use_legacy_sql=false \
  --parameter=min_amount:FLOAT64:1000 \
  'SELECT * FROM my_dataset.orders WHERE amount > @min_amount'

# Export to Cloud Storage
bq extract \
  --destination_format=NEWLINE_DELIMITED_JSON \
  --compression=GZIP \
  my_dataset.my_table \
  gs://my-bucket/export-*.json.gz

# Copy table
bq cp my_dataset.source_table my_dataset.destination_table

# Copy table from another project
bq cp source_project:dataset.table my_project:dataset.table

Troubleshooting Scenarios

Scenario 1: Cloud Storage High Egress Costs

Problem: Unexpected egress charges from Cloud Storage bucket.

Step-by-step resolution: 1. Identify traffic patterns:

# Enable request logs
gsutil logging set on -b gs://logging-bucket gs://my-bucket

# Analyze logs in BigQuery
bq query --use_legacy_sql=false '
SELECT client_ip, COUNT(*) as requests, SUM(bytes_sent) as total_bytes
FROM `my_project.storage_logs.usage_*`
GROUP BY client_ip
ORDER BY total_bytes DESC
LIMIT 10
'

  1. Check bucket location vs. compute location:

    gsutil ls -L -b gs://my-bucket | grep Location
    gcloud compute instances list --format="table(name,zone)"
    

  2. Solutions:

  3. Move bucket to same region as compute resources
  4. Enable CDN for public content
  5. Use signed URLs with restrictions
  6. Implement request rate limiting

  7. Prevention:

    # Create bucket in same region as GKE cluster
    gsutil mb -c STANDARD -l us-central1 gs://app-data-bucket
    

Scenario 2: Cloud SQL High CPU and Slow Queries

Problem: Cloud SQL instance showing 95% CPU, application timeouts.

Step-by-step resolution: 1. Check current metrics:

gcloud sql instances describe my-instance \
  --format="value(settings.tier,settings.dataDiskSizeGb)"

  1. Enable query insights:

    gcloud sql instances patch my-instance \
      --insights-config-query-insights-enabled \
      --insights-config-query-string-length=1024 \
      --insights-config-record-application-tags
    

  2. Analyze slow queries (via Cloud Console):

  3. Navigation: SQL > Instance > Query Insights
  4. Sort by execution time and frequency

  5. Check for missing indexes:

    -- MySQL: Check queries without indexes
    SELECT * FROM mysql.slow_log
    WHERE rows_examined > 1000
    ORDER BY query_time DESC LIMIT 10;
    

  6. Immediate mitigation:

    # Scale up instance
    gcloud sql instances patch my-instance \
      --tier=db-n1-standard-4
    
    # Add read replica for read-heavy workloads
    gcloud sql instances create my-replica \
      --master-instance-name=my-instance \
      --tier=db-n1-standard-2
    

  7. Long-term fixes:

  8. Add appropriate indexes
  9. Implement query caching
  10. Use connection pooling (PgBouncer/ProxySQL)

Scenario 3: Spanner High Latency Across Regions

Problem: Application in us-central1 experiencing high latency reading from Spanner.

Step-by-step resolution: 1. Check instance configuration:

gcloud spanner instances describe my-instance \
  --format="value(config)"

  1. Identify if instance is multi-region:

    gcloud spanner instance-configs describe nam3
    # Shows: Read-write: us-east1, us-central1, us-west1
    

  2. Check read latency by location:

  3. Use Cloud Monitoring metrics
  4. Query: spanner.googleapis.com/api/request_latencies

  5. Solutions:

    # If regional instance, migrate to multi-region
    # 1. Create new multi-region instance
    gcloud spanner instances create global-instance \
      --config=nam3 \
      --processing-units=1000
    
    # 2. Create database in new instance
    gcloud spanner databases create mydb \
      --instance=global-instance
    
    # 3. Export/import data using Dataflow
    

  6. Optimize queries for distribution:

  7. Use stale reads for non-critical data: SELECT ... FROM ... FOR SYSTEM_TIME AS OF ...
  8. Batch mutations to reduce round trips

Scenario 4: Bigtable Hotspotting

Problem: Bigtable showing uneven node utilization, some nodes at 90% CPU.

Step-by-step resolution: 1. Check Key Visualizer (Cloud Console): - Navigation: Bigtable > Instance > Key Visualizer - Look for dark vertical bands (hotspots)

  1. Identify problematic row keys:

    # Check row key distribution
    cbt -project=my-project -instance=my-instance \
      read my-table count=100
    

  2. Analyze row key pattern:

  3. Sequential keys: user_001, user_002 (BAD)
  4. Timestamp-prefixed: 2025-01-15#data (BAD)
  5. Hashed keys: a3f2#user_001 (GOOD)

  6. Solutions:

  7. Field promotion: Move high-cardinality field first

    • Bad: timestamp#user_id
    • Good: user_id#timestamp
  8. Salting: Add random prefix

    • Bad: timestamp#user_id
    • Good: {random(0-99)}#timestamp#user_id
  9. Reverse timestamp:

    # Python example
    reverse_ts = (2**63 - 1) - timestamp_ms
    row_key = f"user_{user_id}#{reverse_ts}"
    

  10. Scale nodes temporarily:

    gcloud bigtable clusters update my-cluster \
      --instance=my-instance \
      --num-nodes=10
    

  11. Monitor improvement:

  12. Wait 15-20 minutes for rebalancing
  13. Check CPU distribution in monitoring

Scenario 5: BigQuery Query Scanning Too Much Data

Problem: Query costs exceeding budget, scanning TBs of data unnecessarily.

Step-by-step resolution: 1. Estimate query cost before running:

bq query --dry_run --use_legacy_sql=false '
SELECT * FROM `my-project.my_dataset.large_table`
WHERE date >= "2025-01-01"
'
# Output shows bytes that will be processed

  1. Common issues:
  2. Selecting all columns: SELECT *
  3. Not filtering partitioned columns
  4. Querying entire table instead of specific partitions

  5. Optimize query:

    # Bad query (scans entire table)
    bq query --dry_run --use_legacy_sql=false '
    SELECT * FROM `my_dataset.transactions`
    WHERE status = "completed"
    '
    
    # Good query (uses partition)
    bq query --dry_run --use_legacy_sql=false '
    SELECT user_id, amount, status
    FROM `my_dataset.transactions`
    WHERE DATE(transaction_date) = "2025-01-15"
      AND status = "completed"
    '
    

  6. Implement partitioning:

    # Create partitioned table from existing table
    bq query --use_legacy_sql=false \
      --destination_table=my_dataset.transactions_partitioned \
      --time_partitioning_field=transaction_date \
      --clustering_fields=user_id,status \
    'SELECT * FROM my_dataset.transactions'
    

  7. Add clustering:

    bq update --clustering_fields=customer_id,product_id \
      my_dataset.sales
    

  8. Set up cost controls:

    # Set custom quota to limit query bytes
    bq mk --transfer_config \
      --target_dataset=my_dataset \
      --display_name="Cost Control" \
      --params='{"query":"SELECT 1","custom_user_name":"cost-control"}'
    
    # Set maximum bytes billed in query
    bq query --maximum_bytes_billed=1000000000 \
      --use_legacy_sql=false 'SELECT ...'
    

Scenario 6: Firestore Read/Write Limits Exceeded

Problem: Application getting "RESOURCE_EXHAUSTED" errors from Firestore.

Step-by-step resolution: 1. Check quota limits: - 10,000 writes/second to a document - 500 writes/second to collection - 1 million concurrent connections

  1. Identify hot documents:

    # Check Firestore metrics in Cloud Monitoring
    gcloud monitoring time-series list \
      --filter='metric.type="firestore.googleapis.com/document/write_count"'
    

  2. Common causes:

  3. Counter document updated too frequently
  4. Fan-out writes to same collection
  5. Unbounded array growth

  6. Solutions for high-write counters:

  7. Distributed counter pattern:

    /counters/page_views/shards/{shard_id}
    # Sum 10 shards instead of single counter
    

  8. Batch writes:

    # Instead of individual writes, batch them
    # SDK example: batch.commit() instead of doc.set()
    

  9. Query optimization:

    # Create composite index
    gcloud firestore indexes composite create \
      --collection-group=orders \
      --field-config field-path=status,order=ascending \
      --field-config field-path=created,order=descending
    

  10. Scale considerations:

  11. Shard high-write documents
  12. Use subcollections for unbounded data
  13. Implement pagination for large queries

Scenario 7: Cloud SQL Backup Restore Taking Too Long

Problem: Restoring 500 GB Cloud SQL backup estimated 6+ hours.

Step-by-step resolution: 1. Check backup details:

gcloud sql backups list --instance=my-instance
gcloud sql backups describe BACKUP_ID --instance=my-instance

  1. Understanding restore times:
  2. Automated backups: Slower (consistent snapshot)
  3. Binary logs: Required for point-in-time recovery
  4. Larger instances restore faster

  5. Faster alternatives:

Option 1: Clone instead of restore:

# Creates new instance from backup (faster)
gcloud sql instances clone my-instance cloned-instance \
  --point-in-time=2025-01-15T10:30:00.000Z

Option 2: Use read replica:

# If replica exists, promote it
gcloud sql instances promote-replica my-replica

Option 3: Export/Import specific databases:

# Export single database
gcloud sql export sql my-instance gs://my-bucket/db-export.sql \
  --database=mydb

# Import to new instance (faster for partial restore)
gcloud sql import sql new-instance gs://my-bucket/db-export.sql \
  --database=mydb

  1. Optimize future backups:

    # Enable binary logging for faster PITR
    gcloud sql instances patch my-instance \
      --enable-bin-log \
      --backup-start-time=02:00
    
    # Set transaction log retention
    gcloud sql instances patch my-instance \
      --retained-transaction-log-days=7
    

  2. Create scheduled export for critical data:

    # Create Cloud Scheduler job for exports
    gcloud scheduler jobs create http export-job \
      --schedule="0 2 * * *" \
      --uri="https://sqladmin.googleapis.com/sql/v1beta4/projects/my-project/instances/my-instance/export" \
      --message-body='{
        "exportContext": {
          "fileType": "SQL",
          "uri": "gs://my-bucket/scheduled-backup.sql",
          "databases": ["mydb"]
        }
      }'
    

Scenario 8: Datastore/Firestore Query Performance Degradation

Problem: Queries that took 100ms now taking 5+ seconds.

Step-by-step resolution: 1. Check if indexes are ready:

gcloud datastore indexes list
# Look for status: CREATING vs READY

  1. Identify missing indexes:
  2. Error message: "no matching index found"
  3. Solution: Create composite index

  4. Create required indexes:

    # index.yaml
    indexes:
    - kind: Product
      properties:
      - name: category
      - name: price
        direction: desc
      - name: created
        direction: desc
    

gcloud datastore indexes create index.yaml
  1. Check for exploding indexes:
  2. Multiple list properties = index explosion
  3. Each combination needs an index

Bad schema:

{
  "tags": ["electronics", "sale", "featured"],  # list
  "categories": ["phones", "android"],  # list
}
# Creates 3 Γ— 2 = 6 index entries

Good schema:

{
  "tags": "electronics,sale,featured",  # single string
  "categories": ["phones", "android"],
}

  1. Optimize query patterns:

    # Instead of IN query (multiple reads)
    # Bad: WHERE category IN ['a', 'b', 'c']
    
    # Use separate queries or restructure data
    # Good: WHERE category = 'a'
    

  2. Monitor query performance:

    # Enable Firestore tracing
    gcloud services enable cloudtrace.googleapis.com
    
    # View traces in Cloud Console
    # Navigation: Trace > Trace List
    

Database Selection Guide

Comparison Table

Database Type Use Case Scaling Consistency Latency
Cloud SQL Relational Traditional apps, OLTP Vertical (96 cores) Strong 5-10ms
Cloud Spanner Relational Global apps, >2TB Horizontal (unlimited) Strong 5-10ms (regional), 100ms (global)
Bigtable NoSQL Wide-column Time-series, IoT, analytics Horizontal (PB scale) Eventual <10ms (single cluster)
Firestore NoSQL Document Mobile/web apps Automatic Strong (regional) 10-20ms
Datastore NoSQL Document Server apps Automatic Strong 10-20ms
BigQuery Data warehouse Analytics, BI Automatic Strong Seconds (analytics)

Decision Tree

Need SQL and ACID transactions? - Yes β†’ Need multi-region strong consistency? - Yes β†’ Cloud Spanner - No β†’ Database size > 10TB? - Yes β†’ Cloud Spanner - No β†’ Cloud SQL

NoSQL with low latency? - Document model (mobile/web) β†’ Firestore - Document model (server) β†’ Datastore - Wide-column (time-series, IoT) β†’ Bigtable - Key-value (simple) β†’ Firestore or Memorystore

Analytics workloads? - Interactive SQL analytics β†’ BigQuery - Stream processing β†’ Dataflow + BigQuery - Hadoop/Spark jobs β†’ Dataproc

Cost Optimization Tips

  1. Cloud SQL:
  2. Use shared-core instances for dev/test
  3. Stop instances during non-business hours
  4. Use committed use discounts (CUD)
  5. Delete old automated backups

    # Stop instance (no charge except storage)
    gcloud sql instances patch my-instance --activation-policy=NEVER
    
    # Start instance
    gcloud sql instances patch my-instance --activation-policy=ALWAYS
    

  6. Cloud Spanner:

  7. Start with 100 processing units (minimum)
  8. Use regional config for single-region apps
  9. Scale nodes during peak hours only

    # Scale down during off-peak
    gcloud spanner instances update my-instance --processing-units=100
    

  10. Bigtable:

  11. Development instances: 1 node, no replication, no SLA
  12. Use autoscaling for variable workloads
  13. Delete old data with garbage collection policies

    cbt setgcpolicy my-table cf1 maxage=30d
    

  14. BigQuery:

  15. Use partitioned tables (reduce data scanned)
  16. Select specific columns, not SELECT *
  17. Use flat-rate pricing for predictable costs
  18. Enable table expiration for temp tables

    bq mk --table --expiration=3600 my_dataset.temp_table
    

  19. Cloud Storage:

  20. Use lifecycle policies to transition storage classes
  21. Enable Nearline/Coldline for infrequent access
  22. Use gsutil -m for parallel uploads (faster)

Data Migration Patterns

MySQL to Cloud SQL

# 1. Export from source MySQL
mysqldump -h source-host -u root -p \
  --databases mydb \
  --single-transaction \
  --set-gtid-purged=OFF \
  > mydb-export.sql

# 2. Upload to Cloud Storage
gsutil cp mydb-export.sql gs://my-bucket/

# 3. Import to Cloud SQL
gcloud sql import sql my-instance \
  gs://my-bucket/mydb-export.sql \
  --database=mydb

# 4. For large databases (>10GB), use parallel export/import

On-premises to BigQuery

# 1. Export to CSV/JSON
# 2. Upload to Cloud Storage
gsutil -m cp -r ./data gs://my-bucket/bq-data/

# 3. Load to BigQuery
bq load --source_format=CSV \
  --autodetect \
  --max_bad_records=100 \
  my_dataset.my_table \
  gs://my-bucket/bq-data/*.csv

# 4. Use Dataflow for complex transformations

AWS DynamoDB to Bigtable

# 1. Export DynamoDB to S3
aws dynamodb export-table-to-point-in-time \
  --table-arn arn:aws:dynamodb:region:account:table/MyTable \
  --s3-bucket my-bucket \
  --export-format DYNAMODB_JSON

# 2. Transfer to Cloud Storage
gsutil -m cp -r s3://aws-bucket gs://gcp-bucket

# 3. Use Dataflow template to import to Bigtable
gcloud dataflow jobs run import-job \
  --gcs-location=gs://dataflow-templates/latest/GCS_SequenceFile_to_Cloud_Bigtable \
  --region=us-central1 \
  --parameters=...

Exam Tips

Key Concepts to Remember

  1. Storage Classes:
  2. Standard: Hot data, no minimum storage
  3. Nearline: 30-day minimum, $0.01/GB retrieval
  4. Coldline: 90-day minimum, $0.02/GB retrieval
  5. Archive: 365-day minimum, $0.05/GB retrieval

  6. Cloud SQL:

  7. Maximum size: 64 TB
  8. HA: Synchronous replication to standby (same region)
  9. Read replicas: Asynchronous, cross-region supported
  10. Automatic backups: Retained for 7 days (configurable)

  11. Spanner:

  12. Minimum: 1 node (2 TB, 10,000 QPS) or 100 processing units
  13. Multi-region: 99.999% SLA (5 nines)
  14. Regional: 99.99% SLA (4 nines)
  15. Best for: >2TB relational data with global scale

  16. Bigtable:

  17. Minimum: 3 nodes for production (1 for dev)
  18. Row key design critical for performance
  19. Best for: >1TB, >100,000 QPS, time-series data

  20. BigQuery:

  21. Pay per query: $5/TB scanned
  22. Partitioning: Reduce costs by 90%+
  23. Clustering: Further optimization within partitions
  24. Flat-rate: 500 slots minimum

Common Exam Scenarios

Scenario: Application needs global SQL database with 99.999% availability - Answer: Cloud Spanner with multi-region configuration

Scenario: Store 100TB of time-series IoT data with <10ms latency - Answer: Bigtable with row key design: device_id#reverse_timestamp

Scenario: Analyze petabytes of logs with SQL - Answer: BigQuery with partitioned tables

Scenario: Migrate 500GB MySQL database to GCP - Answer: Cloud SQL (under 10TB limit)

Scenario: Document database for mobile app with offline sync - Answer: Firestore Native mode

Scenario: Query data in Cloud Storage without loading to database - Answer: BigQuery external tables

Common Pitfalls

  1. Using Cloud SQL for >10TB (use Spanner)
  2. Not partitioning BigQuery tables (high costs)
  3. Monotonic row keys in Bigtable (hotspotting)
  4. Not enabling binary logs for Cloud SQL PITR
  5. Using ACLs instead of IAM for Cloud Storage
  6. Not setting lifecycle policies for temp data
  7. Forgetting to enable HA for production Cloud SQL

Performance Optimization

Cloud Storage: - Use parallel uploads: gsutil -m cp - Composite uploads for large files - Enable CDN for public content

Cloud SQL: - Enable Query Insights - Add read replicas for read-heavy workloads - Use connection pooling - Optimize indexes

Bigtable: - Design row keys for even distribution - Use column families for different access patterns - Enable autoscaling - Use SSD storage (not HDD)

BigQuery: - Partition tables by date - Cluster on filter/join columns - Avoid SELECT * - Use materialized views for repeated queries - Cache results (enabled by default)