Shell ScriptingDiffingDatabase CentricAdvancedMay 2026

Shell Scripting Database Centric: Database Table Diffing

Compare database schemas and table contents between environments — schema diffing with information_schema, CHECKSUM TABLE for fast equality detection, row-level diff export, and environment drift reporting.

Table diffing is the ability to compare two database snapshots and identify what changed — which rows were added, deleted, or modified. This is essential for auditing migrations, debugging data discrepancies, and building change-detection pipelines.

BASH
# ── Compare schemas between environments ──────────────────
# Using mysqldiff (part of MySQL Utilities)
mysqldiff   --server1=user:pass@prod-db-01   --server2=user:pass@staging-db-01   prod_myapp:staging_myapp

# ── Manual schema comparison via information_schema ────────
PROD_CONF="/etc/myapp/prod-mysql.conf"
STAGE_CONF="/etc/myapp/staging-mysql.conf"

# Get column definitions for a table in each env
diff <(
  mysql --defaults-file="${PROD_CONF}" -BNs information_schema     -e "SELECT COLUMN_NAME,COLUMN_TYPE,IS_NULLABLE,COLUMN_DEFAULT
        FROM COLUMNS WHERE TABLE_SCHEMA='myapp' AND TABLE_NAME='users'
        ORDER BY ORDINAL_POSITION"
) <(
  mysql --defaults-file="${STAGE_CONF}" -BNs information_schema     -e "SELECT COLUMN_NAME,COLUMN_TYPE,IS_NULLABLE,COLUMN_DEFAULT
        FROM COLUMNS WHERE TABLE_SCHEMA='myapp' AND TABLE_NAME='users'
        ORDER BY ORDINAL_POSITION"
) && echo "Schemas identical" || echo "Schema differences found"

# ── List tables present in prod but not staging ────────────
comm -23   <(mysql --defaults-file="${PROD_CONF}" -BNs -e "SHOW TABLES IN myapp" | sort)   <(mysql --defaults-file="${STAGE_CONF}" -BNs -e "SHOW TABLES IN myapp" | sort)
BASH
# ── Compare row counts across environments ────────────────
echo "Table count comparison:"
mysql --defaults-file="${PROD_CONF}" -BNs information_schema   -e "SELECT TABLE_NAME, TABLE_ROWS FROM TABLES WHERE TABLE_SCHEMA='myapp' ORDER BY TABLE_NAME" | while IFS=$'\t' read -r tbl rows; do
  stage_rows=$(mysql --defaults-file="${STAGE_CONF}" -BNs information_schema     -e "SELECT TABLE_ROWS FROM TABLES WHERE TABLE_SCHEMA='myapp' AND TABLE_NAME='${tbl}'")
  diff=$(( rows - stage_rows ))
  printf "  %-25s prod=%7d staging=%7d diff=%+d\n" "${tbl}" "${rows}" "${stage_rows}" "${diff}"
done

# ── Checksum entire table contents ────────────────────────
# MySQL CHECKSUM TABLE for fast comparison
for tbl in users orders products; do
  PROD_CK=$(mysql --defaults-file="${PROD_CONF}" -BNs myapp     -e "CHECKSUM TABLE ${tbl}" | awk '{print $2}')
  STAGE_CK=$(mysql --defaults-file="${STAGE_CONF}" -BNs myapp     -e "CHECKSUM TABLE ${tbl}" | awk '{print $2}')
  if [[ "${PROD_CK}" == "${STAGE_CK}" ]]; then
    echo "  ${tbl}: IDENTICAL"
  else
    echo "  ${tbl}: DIFFERS (prod=${PROD_CK} stage=${STAGE_CK})"
  fi
done

# ── Find rows in prod not in staging ──────────────────────
# Export both, sort, diff
mysql --defaults-file="${PROD_CONF}" -BNs myapp   -e "SELECT id,email FROM users ORDER BY id" | sort > /tmp/prod_users.txt
mysql --defaults-file="${STAGE_CONF}" -BNs myapp   -e "SELECT id,email FROM users ORDER BY id" | sort > /tmp/stage_users.txt

echo "Rows in prod but not staging:"
comm -23 /tmp/prod_users.txt /tmp/stage_users.txt | head -20
echo "Rows in staging but not prod:"
comm -13 /tmp/prod_users.txt /tmp/stage_users.txt | head -20
✔ Diffi — Use CHECKSUM TABLE for fast binary equality checks — if checksums match, skip row-level comparison. For row-level diffs, export both tables sorted by primary key, then use comm or diff. Store diffs to timestamped files so you can track what changed between runs. Use mysqldiff or pgdiff from the respective toolsets for production schema drift detection.