Check mysql-index-health¶
Overview¶
Reports the two index-housekeeping findings that MySQLTuner:mysql_pfs() flags: unused indexes (never read since the last server start, listed in sys.schema_unused_indexes) and redundant indexes (a narrower index fully covered by a wider one, listed in sys.schema_redundant_indexes). Both views are populated by the Performance Schema; the plugin reports STATE_UNKNOWN with a clear hint when performance_schema = OFF (the MariaDB default).
The check is meant as a trip-wire only: it surfaces the findings, not the full per-index analysis. The plugin itself does not duplicate mysqltuner’s deep diagnostic output; it is sized for a once-a-day Icinga check, not a 60-second one (the underlying counters are cumulative since server start, so sub-daily sampling would add nothing).
Important Notes:
The plugin needs the Performance Schema. On MariaDB it is OFF by default; enable it with
performance_schema = ONinmy.cnfand restart the server. MySQL ships it ON by defaultsys.schema_unused_indexesandsys.schema_redundant_indexesexist in MySQL 5.7+ and MariaDB 10.6+Counters are cumulative since the last server start. Restarting the server resets them, so a freshly booted host may take a few hours before unused-index numbers settle (the query pattern needs time to exercise all indexes)
System schemas (
mysql,information_schema,performance_schema,sys) are excluded, matching the WHERE clause used by mysqltunerIndex housekeeping is never a wake-up-at-night finding, so the plugin only emits WARN (and the implicit OK), never CRIT
Output ships a ready-to-paste
ALTER TABLE ... DROP INDEXstatement per finding.--lengthyshows the full statement; the default truncates after 80 characters so the table stays readable in IcingaWebRedundant indexes are safe to drop because the dominant index already covers every query the redundant one served. Unused indexes need verification first: „unused since last server start“ can miss weekly or monthly jobs, recently restarted servers, and indexes that back foreign-key constraints. Wait at least one full business cycle before dropping
Data Collection:
SHOW GLOBAL VARIABLES LIKE 'performance_schema'to detect the prerequisiteSELECT ... FROM sys.schema_unused_indexesexcluding the four server-managed schemasSELECT ... FROM sys.schema_redundant_indexes(already excludes server schemas internally)
Fact Sheet¶
Fact |
Value |
|---|---|
Check Plugin Download |
https://github.com/Linuxfabrik/monitoring-plugins/tree/main/check-plugins/mysql-index-health |
Nagios/Icinga Check Name |
|
Check Interval Recommendation |
Once a day |
Can be called without parameters |
Yes |
Runs on |
Cross-platform |
Compiled for Windows |
No |
Requirements |
User with |
3rd Party Python modules |
|
Help¶
usage: mysql-index-health [-h] [-V] [--always-ok]
[--defaults-file DEFAULTS_FILE]
[--defaults-group DEFAULTS_GROUP] [--lengthy]
[--min-uptime-hours MIN_UPTIME_HOURS]
[--timeout TIMEOUT]
[--warning-redundant WARN_REDUNDANT]
[--warning-unused WARN_UNUSED]
Reports the two index-housekeeping findings that MySQLTuner flags inside its
`mysql_pfs()` block: unused indexes (never read since the last server start,
listed in `sys.schema_unused_indexes`) and redundant indexes (a narrower index
fully covered by a wider one, listed in `sys.schema_redundant_indexes`). Both
views are populated by the Performance Schema; the plugin reports
STATE_UNKNOWN with a clear hint when `performance_schema = OFF` (the MariaDB
default). The check is meant as a trip-wire only: it surfaces the findings,
not the full per-index analysis. System schemas (`mysql`,
`information_schema`, `performance_schema`, `sys`) are excluded. Counters are
cumulative since server start; restarting the server resets them, so the
plugin stays silent (STATE_OK with a wait hint) until server uptime crosses
`--min-uptime-hours` (default 24h). This avoids the false-clean signal right
after a restart and the false-positive "unused" signal that would fire before
weekly or monthly jobs have had a chance to touch their indexes. Index
housekeeping is never a wake-up-at-night finding, so the plugin only emits
WARN (and the implicit OK), never CRIT.
options:
-h, --help show this help message and exit
-V, --version show program's version number and exit
--always-ok Always returns OK.
--defaults-file DEFAULTS_FILE
MySQL/MariaDB cnf file to read user, host and password
from. Example: `--defaults-
file=/var/spool/icinga2/.my.cnf`. Default:
/var/spool/icinga2/.my.cnf
--defaults-group DEFAULTS_GROUP
Group/section to read from in the cnf file. Default:
client
--lengthy Extended reporting.
--min-uptime-hours MIN_UPTIME_HOURS
Minimum server uptime (in hours) before the plugin
starts evaluating findings. Performance Schema
counters reset on every server restart, so a freshly
booted server has no record of which indexes are read
or unused; alerting on that data would produce false
positives. Below the threshold the plugin reports OK
with an info hint. Example: `--min-uptime-hours=48`.
Default: 24
--timeout TIMEOUT Network timeout in seconds. Default: 3 (seconds)
--warning-redundant WARN_REDUNDANT
WARN threshold for the number of matching items.
Applies to redundant indexes. Supports Nagios ranges.
Example: `--warning-redundant=10`. Default: 0
--warning-unused WARN_UNUSED
WARN threshold for the number of matching items.
Applies to unused indexes. Supports Nagios ranges.
Example: `--warning-unused=10`. Default: 0
Usage Examples¶
./mysql-index-health --defaults-file=/var/spool/icinga2/.my.cnf
OK output:
Everything is ok. 0 unused indexes, 0 redundant indexes.
UNKNOWN output (Performance Schema off):
Performance Schema is OFF, index-health views are unobservable. Enable with `performance_schema = ON` in `my.cnf` and restart the server, or set `--always-ok` if the host is intentionally left without Performance Schema.
WARN output:
2 unused indexes [WARNING], 1 redundant index [WARNING].
67% of findings concentrate in schema `orders` (2 of 3); start the cleanup there.
Run `mysqltuner --pfstat` on the host for the full list with remediation hints.
Redundant indexes (safe to drop; the dominant index already covers the same query patterns):
! Schema ! Table ! Redundant Index ! Dominant Index ! SQL Drop !
! ------- ! ----- ! --------------- ! -------------- ! ---------------------------------------------- !
! orders ! line ! idx_a ! idx_a_b ! ALTER TABLE `orders`.`line` DROP INDEX `idx_a` !
Unused indexes (verify before dropping: "unused since last server start" can miss weekly or monthly jobs, recently restarted servers, and indexes that back foreign-key constraints; wait at least one full business cycle, then drop):
! Schema ! Table ! Index ! SQL Drop !
! ------- ! ------- ! ---------- ! --------------------------------------------------- !
! orders ! line ! idx_status ! ALTER TABLE `orders`.`line` DROP INDEX `idx_status` !
! reports ! summary ! idx_year ! ALTER TABLE `reports`.`summary` DROP INDEX ... !
States¶
OK if zero unused and zero redundant indexes (counter < threshold).
WARN if the unused- or redundant-index count crosses
--warning-unused/--warning-redundant(default: any > 0).No CRIT path: index housekeeping is never a wake-up-at-night finding.
UNKNOWN if
performance_schema = OFFon the server (the views cannot be populated).--always-oksuppresses all alerts and always returns OK.
Perfdata / Metrics¶
Name |
Type |
Description |
|---|---|---|
mysql_redundant_indexes |
Number |
Count of indexes covered by a wider sibling on the same table. A non-zero value usually means a |
mysql_unused_indexes |
Number |
Count of indexes that have not been read since the last server start. A non-zero value is a candidate-for-removal list, not a hard verdict: short-lived workloads need time to exercise all indexes. |
Credits, License¶
Authors: Linuxfabrik GmbH, Zurich
License: The Unlicense, see LICENSE file.
Credits:
heavily inspired by MySQLTuner (https://github.com/major/MySQLTuner-perl)