00:00

MySQL Show Index

Last updated: 3 min read

Before adding or dropping an index you need to know which indexes a table already has. SHOW INDEX lists them, one row per indexed column, with details such as uniqueness, column order and estimated cardinality.

1. Syntax

syntax.sql
SHOW {INDEX | INDEXES | KEYS} {FROM | IN} table_name [{FROM | IN} db_name] [WHERE condition];
query.sql
SHOW INDEX FROM customers;

Result: 7 rows

TableNon_uniqueKey_nameSeq_in_indexColumn_nameSub_partCardinalityVisibleExpression
customers0PRIMARY1idNULL4916YESNULL
customers0uq_email1emailNULL4916YESNULL
customers1idx_city_last1cityNULL12YESNULL
customers1idx_city_last2last_nameNULL60YESNULL
customers1idx_email_prefix1email84916YESNULL
customers1idx_spend1spendNULL4916NONULL
customers1idx_signup_year1NULLNULL5YESyear(`signup_on`)

2. Understanding the Output

ColumnMeaningIn our example
Key_nameIndex name; PRIMARY for the primary keyidx_city_last appears twice: one row per column
Non_unique0 = unique index, 1 = duplicates allowedPRIMARY and uq_email are 0
Seq_in_indexPosition of the column in the index (1, 2, …)city = 1, last_name = 2
Column_nameIndexed column (NULL for functional indexes)NULL for idx_signup_year
Sub_partPrefix length for prefix indexes8 for idx_email_prefix
CardinalityEstimated number of distinct values (refreshed by ANALYZE TABLE)about 12 for city
NullYES if the column allows NULL
Index_typeBTREE, FULLTEXT, SPATIAL, HASHBTREE
VisibleNO for invisible indexesNO for idx_spend
ExpressionExpression of a functional indexyear(signup_on)

3. Cardinality and Selectivity

Cardinality estimates how many different values an index holds. Divide by the row count to get selectivity: close to 1 means nearly unique (great for lookups), close to 0 means many duplicates (an index alone helps less).

query.sql
SELECT index_name, column_name, cardinality,
       ROUND(cardinality / (SELECT COUNT(*) FROM crm.customers), 4) AS selectivity
FROM information_schema.statistics
WHERE table_schema = 'crm' AND table_name = 'customers' AND seq_in_index = 1
ORDER BY selectivity DESC;

Result: 6 rows

INDEX_NAMECOLUMN_NAMECARDINALITYselectivity
idx_email_prefixemail49160.9832
idx_spendspend49160.9832
PRIMARYid49160.9832
uq_emailemail49160.9832
idx_city_lastcity120.0024
idx_signup_yearNULL50.0010
Cardinality is an estimate from sampled pages. Run ANALYZE TABLE after big data changes to refresh it.

4. Filtering the Output

query.sql
SHOW INDEX FROM customers WHERE Non_unique = 0;

Unique indexes only

Key_nameColumn_name
PRIMARYid
uq_emailemail
query.sql
SHOW INDEX FROM customers WHERE Visible = 'NO';

Invisible indexes

Key_nameColumn_nameVisible
idx_spendspendNO
query.sql
SHOW KEYS FROM customers FROM crm WHERE Key_name = 'idx_city_last';

SHOW KEYS is a synonym

Key_nameSeq_in_indexColumn_name
idx_city_last1city
idx_city_last2last_name

5. One Line per Index

SHOW INDEX returns one row per column. To see each index on one line, group information_schema.statistics:

query.sql
SELECT index_name,
       IF(MIN(non_unique) = 0, 'UNIQUE', '') AS uniq,
       GROUP_CONCAT(COALESCE(column_name, expression) ORDER BY seq_in_index SEPARATOR ', ') AS columns,
       MAX(is_visible) AS visible
FROM information_schema.statistics
WHERE table_schema = 'crm' AND table_name = 'customers'
GROUP BY index_name
ORDER BY index_name;

Result: 6 rows

INDEX_NAMEuniqcolumnsvisible
idx_city_lastcity, last_nameYES
idx_email_prefixemailYES
idx_signup_yearyear(`signup_on`)YES
idx_spendspendNO
PRIMARYUNIQUEidYES
uq_emailUNIQUEemailYES

6. Indexes Across a Whole Database

query.sql
SELECT table_name, COUNT(DISTINCT index_name) AS indexes
FROM information_schema.statistics
WHERE table_schema = 'crm'
GROUP BY table_name;

Result: 1 row

TABLE_NAMEindexes
customers6

And tables without any secondary index, which are worth reviewing:

no-secondary.sql
CREATE TABLE crm.notes (id INT PRIMARY KEY, customer_id INT, body TEXT);
SELECT t.table_name
FROM information_schema.tables t
WHERE t.table_schema = 'crm' AND t.table_type = 'BASE TABLE'
  AND NOT EXISTS (SELECT 1 FROM information_schema.statistics s
                  WHERE s.table_schema = t.table_schema AND s.table_name = t.table_name AND s.index_name <> 'PRIMARY');

Result: 1 row

TABLE_NAME
notes

7. SHOW CREATE TABLE

To see index definitions as SQL (useful for copying), use SHOW CREATE TABLE:

query.sql
SHOW CREATE TABLE notes;

Result: 1 row

TableCreate Table
notesCREATE TABLE `notes` ( `id` int NOT NULL, `customer_id` int DEFAULT NULL, `body` text, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

8. Summary

  • SHOW INDEX FROM table; (or SHOW KEYS) lists indexes, one row per column.
  • Key_name, Non_unique, Seq_in_index, Cardinality and Visible are the most useful columns.
  • High cardinality relative to rows means a selective, effective index.
  • information_schema.statistics lets you group, filter and search across tables.