- Posted on
- • Artificial Intelligence
Artificial Intelligence Database Automation
- Author
-
-
- User
- linuxbash
- Posts by this author
- Posts by this author
-
Bash-first AI: Automating Database Ops on Linux
Ever been paged at 2 a.m. because a database suddenly slowed to a crawl? Most “incidents” are patterns you’ve seen before—spikes in transactions, cache hit dips, bloated indexes, or a slow query going wild. Artificial Intelligence (AI) can learn those patterns from your own telemetry and then flag anomalies, trigger safe remediations, and buy you precious time. The best part: you don’t need to rip-and-replace anything. With a few Bash scripts, a lightweight Python model, and standard Linux tools, you can start automating database operations today.
This guide shows you how to:
Collect meaningful DB signals with a portable Bash script
Detect anomalies using a tiny, train-on-the-fly ML model
Trigger safe actions or alerts automatically
Schedule the whole pipeline with cron or systemd timers
We’ll focus on PostgreSQL and SQLite for portability, but the pattern applies broadly.
Why AI for database automation?
Databases already emit rich, quantitative signals (transactions, buffer hits, I/O). That’s perfect ML fodder.
“Toil” tasks (watching dashboards, firing routine ANALYZE, notifying SREs) are repetitive and rule-like—ideal for automation.
Lightweight models can run at the edge (on your Linux host) with no expensive infrastructure.
Bash is the glue—simple to deploy, easy to read, and integrates with your existing ops stack.
1) Install the toolbox
We’ll use:
Bash, jq, curl, git: shell glue and HTTP/webhook helpers
Python 3 + venv + pip: to run a tiny anomaly detector
SQLite and PostgreSQL client (psql): to demo data collection
Run the commands for your distro:
Debian/Ubuntu (apt):
sudo apt update
sudo apt install -y \
python3 python3-venv python3-pip \
sqlite3 postgresql-client \
jq curl git cron
Fedora/RHEL/CentOS (dnf):
sudo dnf install -y \
python3 python3-pip python3-virtualenv \
sqlite postgresql \
jq curl git cronie
openSUSE (zypper):
sudo zypper refresh
sudo zypper install -y \
python3 python3-pip python3-virtualenv \
sqlite3 postgresql \
jq curl git cron
Set up a Python virtual environment for the anomaly detector:
python3 -m venv .venv
. .venv/bin/activate
pip install --upgrade pip
pip install pandas scikit-learn
Tip: systemd is installed by default on most modern distros, so no package step is needed if you choose the timer approach later.
2) Collect meaningful DB signals (Bash)
The goal: produce a compact CSV of time series features the model can learn from. For PostgreSQL, we’ll read transaction counters and buffer I/O counters from pg_stat_database and compute rates. If Postgres isn’t available, we’ll fall back to a synthetic demo mode so you can try the pipeline end-to-end.
Save as collect_db_metrics.sh:
#!/usr/bin/env bash
set -euo pipefail
# Config
METRICS_CSV="${METRICS_CSV:-./metrics.csv}"
STATE_FILE="${STATE_FILE:-/var/tmp/db_metrics.state}"
PSQL_CONNSTR="${PSQL_CONNSTR:-}" # e.g. "postgresql://user:pass@host:5432/db?sslmode=require"
DEMO="${DEMO:-0}" # DEMO=1 to generate synthetic metrics if no Postgres
NOW_EPOCH="$(date +%s)"
NOW_ISO="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
# Ensure CSV header
if [ ! -f "$METRICS_CSV" ]; then
echo "timestamp_iso,tps,cache_hit_ratio" > "$METRICS_CSV"
fi
# Load previous state if present
PREV_EPOCH=0; PREV_XACTS=0; PREV_BLK_READ=0; PREV_BLK_HIT=0
if [ -f "$STATE_FILE" ]; then
# shellcheck disable=SC1090
source "$STATE_FILE"
fi
XACTS=0; BLK_READ=0; BLK_HIT=0
if command -v psql >/dev/null 2>&1 && [ -n "$PSQL_CONNSTR" ]; then
# Query cumulative counters from pg_stat_database
read -r XACTS BLK_READ BLK_HIT < <(
psql "$PSQL_CONNSTR" -Atc \
"SELECT COALESCE(sum(xact_commit+xact_rollback),0),
COALESCE(sum(blks_read),0),
COALESCE(sum(blks_hit),0)
FROM pg_stat_database;"
)
elif [ "$DEMO" = "1" ]; then
# Synthetic counters (monotonically increasing with random deltas)
inc_x=$(( RANDOM % 300 + 200 ))
inc_r=$(( RANDOM % 500 + 100 ))
inc_h=$(( RANDOM % 3000 + 2000 ))
XACTS=$(( PREV_XACTS + inc_x ))
BLK_READ=$(( PREV_BLK_READ + inc_r ))
BLK_HIT=$(( PREV_BLK_HIT + inc_h ))
else
echo "No Postgres connection (PSQL_CONNSTR) and DEMO=0. Nothing to collect." >&2
exit 1
fi
# Compute deltas and rates
ELAPSED=$(( NOW_EPOCH - PREV_EPOCH ))
if [ "$ELAPSED" -le 0 ]; then ELAPSED=60; fi
DX=$(( XACTS - PREV_XACTS ))
DR=$(( BLK_READ - PREV_BLK_READ ))
DH=$(( BLK_HIT - PREV_BLK_HIT ))
if [ "$DX" -lt 0 ]; then DX=0; fi
if [ "$DR" -lt 0 ]; then DR=0; fi
if [ "$DH" -lt 0 ]; then DH=0; fi
# Transactions per minute (rate-normalized)
TPS=$(awk -v dx="$DX" -v el="$ELAPSED" 'BEGIN{ printf "%.2f", (dx/el)*60 }')
# Cache hit ratio over the last interval
DENOM=$(( DR + DH ))
if [ "$DENOM" -gt 0 ]; then
CHR=$(awk -v dh="$DH" -v d="$DENOM" 'BEGIN{ printf "%.4f", dh/d }')
else
CHR="1.0000"
fi
# Append to CSV
echo "$NOW_ISO,$TPS,$CHR" >> "$METRICS_CSV"
# Persist state
cat > "$STATE_FILE" <<EOF
PREV_EPOCH=$NOW_EPOCH
PREV_XACTS=$XACTS
PREV_BLK_READ=$BLK_READ
PREV_BLK_HIT=$BLK_HIT
EOF
echo "collected: ts=$NOW_ISO tps=$TPS cache_hit=$CHR"
Make it executable:
chmod +x collect_db_metrics.sh
Notes:
For richer Postgres features (e.g., query latencies), consider enabling
pg_stat_statementson the server:- postgresql.conf:
shared_preload_libraries = 'pg_stat_statements' - SQL (superuser):
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
- postgresql.conf:
Non-superusers may need
pg_read_all_statsto query some views.
3) Detect anomalies with a tiny ML model (Python)
We’ll fit an Isolation Forest on recent data and check if the latest row is unusual given history. It’s fast and requires no labels.
Save as detect_anomalies.py:
#!/usr/bin/env python3
import argparse, json, sys
import pandas as pd
from sklearn.ensemble import IsolationForest
from sklearn.preprocessing import StandardScaler
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--csv", default="metrics.csv")
ap.add_argument("--window", type=int, default=200, help="rows of history to learn from")
ap.add_argument("--contamination", type=float, default=0.03, help="expected anomaly ratio")
args = ap.parse_args()
try:
df = pd.read_csv(args.csv, parse_dates=["timestamp_iso"])
except FileNotFoundError:
print(json.dumps({"ok": False, "error": "metrics.csv not found"}))
sys.exit(1)
if len(df) < 20:
print(json.dumps({"ok": True, "is_anomaly": False, "reason": "insufficient_history"}))
return
dfw = df.tail(args.window).copy()
X = dfw[["tps", "cache_hit_ratio"]].astype(float).values
scaler = StandardScaler()
Xs = scaler.fit_transform(X)
model = IsolationForest(
n_estimators=200,
contamination=args.contamination,
random_state=42,
n_jobs=1
)
model.fit(Xs)
latest = Xs[-1].reshape(1, -1)
pred = model.predict(latest)[0] # -1 anomaly, 1 normal
score = model.decision_function(latest)[0] # the more negative, the more anomalous
out = {
"ok": True,
"is_anomaly": (pred == -1),
"score": float(score),
"latest": {
"timestamp": dfw.iloc[-1]["timestamp_iso"].isoformat(),
"tps": float(dfw.iloc[-1]["tps"]),
"cache_hit_ratio": float(dfw.iloc[-1]["cache_hit_ratio"])
}
}
print(json.dumps(out))
return
if __name__ == "__main__":
main()
Make it executable:
chmod +x detect_anomalies.py
Try it:
# Demo mode (no DB needed)
DEMO=1 ./collect_db_metrics.sh
. .venv/bin/activate
./detect_anomalies.py --csv metrics.csv
4) Automate safe actions (notify, nudge, or analyze)
Glue it together in one script that collects, runs the detector, then decides what to do. Start conservatively: log and notify. Later, you can add guarded remediations (e.g., run ANALYZE off-hours if cache-hit tanks).
Save as auto_remediate.sh:
#!/usr/bin/env bash
set -euo pipefail
# Optional config
WEBHOOK_URL="${WEBHOOK_URL:-}" # e.g., Slack/Mattermost/Discord incoming webhook
PSQL_CONNSTR="${PSQL_CONNSTR:-}" # to run optional ANALYZE if you want
SAFE_ANALYZE="${SAFE_ANALYZE:-0}" # set to 1 to allow ANALYZE when anomaly seen
# 1) Collect latest metrics
./collect_db_metrics.sh >/dev/null
# 2) Run detector (ensure venv or system Python has deps installed)
if [ -f ".venv/bin/python" ]; then
PY=".venv/bin/python"
else
PY="python3"
fi
RES="$($PY ./detect_anomalies.py --csv metrics.csv || true)"
# 3) Parse result
OK=$(echo "$RES" | jq -r '.ok // false')
if [ "$OK" != "true" ]; then
logger -t ai-db-auto "Detector error: $RES"
exit 0
fi
ANOM=$(echo "$RES" | jq -r '.is_anomaly')
SCORE=$(echo "$RES" | jq -r '.score')
TS=$(echo "$RES" | jq -r '.latest.timestamp')
TPS=$(echo "$RES" | jq -r '.latest.tps')
CHR=$(echo "$RES" | jq -r '.latest.cache_hit_ratio')
if [ "$ANOM" = "true" ]; then
MSG="Anomaly detected at $TS (score=$SCORE, tps=$TPS, cache_hit=$CHR)"
echo "$MSG"
logger -t ai-db-auto "$MSG"
# Optional: send webhook
if [ -n "$WEBHOOK_URL" ]; then
curl -fsSL -X POST -H 'Content-Type: application/json' \
--data "{\"text\": \"${MSG//\"/\\\"}\"}" \
"$WEBHOOK_URL" >/dev/null || true
fi
# Optional: run a safe ANALYZE (no VACUUM by default)
if [ "$SAFE_ANALYZE" = "1" ] && command -v psql >/dev/null 2>&1 && [ -n "$PSQL_CONNSTR" ]; then
psql "$PSQL_CONNSTR" -c "ANALYZE;" || true
logger -t ai-db-auto "ANALYZE issued after anomaly"
fi
else
echo "Normal at $TS (score=$SCORE, tps=$TPS, cache_hit=$CHR)"
fi
Make it executable:
chmod +x auto_remediate.sh
Test end-to-end:
# Demo mode
export DEMO=1
. .venv/bin/activate
./auto_remediate.sh
When ready for Postgres, set:
export DEMO=0
export PSQL_CONNSTR="postgresql://user:pass@host:5432/dbname?sslmode=require"
# Optional notifications
export WEBHOOK_URL="https://hooks.example.com/..."
# Optional guarded remediation
export SAFE_ANALYZE=1
Always test remediations in staging first.
5) Schedule it (cron or systemd)
Pick one scheduler.
Option A: cron (every minute)
Debian/Ubuntu (apt): cron is provided by the
cronpackageFedora/RHEL (dnf): use
cronieopenSUSE (zypper): use
cron
Crontab entry:
crontab -e
Add:
* * * * * cd /path/to/ai-db-auto && /bin/bash ./auto_remediate.sh >> auto.log 2>&1
Option B: systemd timer
Create ~/.config/systemd/user/ai-db-auto.service:
[Unit]
Description=AI DB Automation (collect + detect + act)
[Service]
Type=oneshot
WorkingDirectory=%h/path/to/ai-db-auto
Environment=DEMO=0
# Environment=PSQL_CONNSTR=postgresql://user:pass@host:5432/db?sslmode=require
# Environment=WEBHOOK_URL=https://hooks.example.com/...
# Environment=SAFE_ANALYZE=1
ExecStart=/bin/bash -lc './auto_remediate.sh'
Create ~/.config/systemd/user/ai-db-auto.timer:
[Unit]
Description=Run AI DB Automation every minute
[Timer]
OnCalendar=*:0/1
AccuracySec=10s
Persistent=true
[Install]
WantedBy=timers.target
Enable and start:
systemctl --user daemon-reload
systemctl --user enable --now ai-db-auto.timer
systemctl --user status ai-db-auto.timer
Real-world patterns this catches
Sudden write or TPS surges: detect traffic spikes before saturation; notify and scale app workers or read replicas.
Cache hit dips: hint at workload shifts or outdated stats; trigger a safe ANALYZE during a maintenance window.
Slow drift over time: a rising anomaly score across days can warn about capacity issues—plan ahead instead of fire-fighting.
Extend the pipeline by:
Adding more features (I/O wait from iostat, disk latency, checkpoint frequency, connection counts).
Mining
pg_stat_statementsfor the top regressions and attaching their fingerprints to alerts.Learning per-hour baselines (weekday vs. weekend) by enriching your CSV with calendar features.
Conclusion and next steps
You don’t need a giant AI platform to reduce DB toil. Start with: 1) Install the tools 2) Collect a couple of reliable signals 3) Fit a simple model locally 4) Automate a cautious response
From here, iterate:
Add features and thresholds
Wire to your incident tooling
Promote safe remediations to production after staging tests
If you try this recipe, begin in DEMO mode to validate the loop, then point it at Postgres with read-only stats. Keep actions conservative, measure outcomes, and level up from “notify” to “nudge” to “automate” as confidence grows.
Happy automating—and may your next 2 a.m. page be handled by a Bash script before you even wake up.