Assert icon
Query icon
OutputValues icon
Log icon
If icon
SlackIncomingWebhook icon
Pause icon
Queries icon
Schedule icon

Refresh stale InnoDB row estimates after a bulk load

Refresh stale persistent InnoDB row estimates after bulk loads with a bounded exact count, locked table identity checks and approved local ANALYZE.

Categories
Data

Safety

READ locks block writers during maintenance. Choose a quiet window and one known bulk-load target.

How it works

Native MySQL Query reads one file-per-table InnoDB target. Count rows within a time budget then compare persistent n_rows with the exact count. Eligibility requires the row floor, stats age and abs(estimate-count)/count >= drift_ratio. Missing statistics or unsupported targets fail before maintenance. Live mode pauses for explicit approval. MySQL Queries takes a READ lock, checks TABLE_ID, count and physical size again then runs ANALYZE LOCAL TABLE on the same connection. An error status or a fresh estimate outside verify_tolerance fails the run. The final count and TABLE_ID must still match approval. Connection pooling is off; maintenance uses no transaction wrapper because MySQL implicitly commits these statements.

What you get

A bounded statistics refresh after a loader missed its final ANALYZE. InnoDB samples pages, so the estimate is checked with relative tolerance. This flow changes statistics, not application rows. LOCAL suppresses binary logging of maintenance. It makes no query-speed or plan-improvement claim.

Who it's for

MySQL operators managing tables with persistent statistics after bulk loads or purges, especially when STATS_AUTO_RECALC=0 requires explicit maintenance.

Why orchestrate this with Kestra

Connect the loader's target to a bounded count, approval and verified maintenance result. Slack reports stale estimates and failed runs. The disabled daily trigger forces read-only inputs. All SQL uses native MySQL Query or Queries; no client script or stored procedure is installed.

Tested end to end

MySQL 8.0.46, Kestra 2.0.6 (MySQL plugin 2.3.0) and 2.0.5 (plugin 2.1.0). A second MySQL instance repeated recovery. Independent mysql reads preserved count, key sum, checksum and ordered data SHA-256. After loading 1,000 rows, n_rows changed from 2 to 1,002. EXPLAIN already estimated 1,002 before refresh.

Case Execution Result
Healthy 6q34wrazmW3P6l7Z2clW2j SUCCESS
Dry run iEdplWhRZpm6D8MSrYPNo No write
Declined 5d4U39kdb3Gyp7Fk4K4zXR No write
Refresh 2Pb2vF1ZQ6tCLEneNCfNLe 2 to 1,002
Repeat 1Fg1uqc6FhoQeA4InSsdfJ No write
Row changed 7WdeXyRPsoxmzYoH5qHpfD FAILED
Refused write 5juaTVEWM42maGcTqYzgzB FAILED

Prerequisites

MySQL 8.0.24 or later, unpartitioned file-per-table InnoDB with persistent statistics. Tested grants: SELECT and INSERT on the target, LOCK TABLES on its database, PROCESS and SELECT on mysql.innodb_table_stats. INSERT is required by ANALYZE. Use a JDBC URL without credentials and configure TLS for your server.

Secrets

MYSQL_USERNAME, MYSQL_PASSWORD and SLACK_WEBHOOK_URL. Password and webhook overrides are SECRET inputs.

Inputs

schema_name/table_name allow 1 to 64 ASCII letters, digits or underscores; system schemas are refused. max_table_mb defaults to 16 MiB (1 to 128). min_rows defaults to 1,000; min_stats_age_seconds to 3,600. drift_ratio defaults to 0.5 (0.1 to 1); verify_tolerance to 0.25 (0.01 to 0.5). count_timeout_ms defaults to 10,000 (1 to 10,000). dry_run=true and auto_remediate=false are safe defaults.

Quick start

  1. Configure secrets, mysql_url and the target; run safe mode.
  2. Review the count, estimate, size and stats age.
  3. Set dry_run=false and auto_remediate=true; resume with approved=true.

How to extend

Trigger from the loader that owns this table. Limits: one target, no partitions or histograms. Metadata and row lock waits are 2 seconds; connect timeout is 5 seconds and socket timeout 30 seconds. Socket timeout does not guarantee server-side ANALYZE cancellation. Approval expires after one hour. Queue scope is this flow only. Stats age cannot be reread under LOCK TABLES, so already-fresh stats may be refreshed. Equal-count data edits are allowed; table replacement is refused. Recount after any failure before retrying.

Links

This blueprint was created by zkasuran.

See How

New to Kestra?

Use blueprints to kickstart your first workflows.