How to query inefficient indexes
After multiple indexes are created on a table, some indexes may no longer be used by queries as your business evolves, but they still slow down writes and consume storage. The inefficient index query feature of PolarDB-X can identify inefficient indexes in databases, including local indexes and global secondary indexes (GSIs). Based on the query results, you can make necessary adjustments such as deleting or rebuilding indexes to improve write performance and save storage space without affecting query performance. We recommend that you run inefficient index queries on a regular basis.
Scope of application
-
Local index query: The instance version must be 5.4.20-20260529, 5.4.21-20260509, or later.
-
Global index query: The instance version must be 5.4.17-16859297 or later.
-
Instance version naming rules, see Version notes.
-
Instance version viewing method, see View the instance version.
How it works
Inefficient index queries cover two types of indexes, each with different data sources:
-
Local indexes: Each data node (DN) records the access count of each index on physical tables. Compute nodes (CNs) aggregate the data and expose it through the
information_schema.logical_index_usageandinformation_schema.physical_index_usageviews. -
Global secondary indexes (GSIs): After you enable the
GSI_STATISTICS_COLLECTIONparameter, CNs record the access count and last access time of each GSI. TheINSPECT INDEXcommand provides diagnostic conclusions and optimization suggestions based on this data and index metadata. For more information about GSI diagnostics, see Index diagnostics.
Logical tables and physical tables
PolarDB-X is a distributed database. A table exists at both the logical and physical levels. Understanding the difference helps you correctly interpret the fields in the logical_index_usage and physical_index_usage views.
-
Logical table: The table that you create and access. It is logically a complete table and resides in a logical database. The database names and table names used in daily SQL statements are logical database names and logical table names.
-
Physical table: After a logical table is partitioned, the shard tables are physically stored on DNs and belong to physical databases. A logical table usually corresponds to multiple physical tables. A physical table name typically consists of the logical table name and a partition suffix, such as
my_table_xxxx_00000.
CNs maintain the mapping between logical names and physical names. The following table describes the relationships between concepts at each level and the fields in the two views:
|
Concept |
Node |
Description |
Corresponding field |
|
Logical database |
Compute node (CN) |
The database you access |
|
|
Logical table |
Compute node (CN) |
The table you access (logically complete) |
|
|
Physical database |
Data node (DN) |
The actual schema that stores data on the DN |
|
|
Physical table |
Data node (DN) |
The actual shard table stored on the DN, including the partition suffix |
|
Because one logical table corresponds to multiple physical tables, the granularity difference between the two views can be understood as follows:
-
physical_index_usageprovides statistics at the physical table level. The same logical index occupies one row per physical partition, showing raw counts. -
logical_index_usageaggregates the counts of the same logical index across all physical partitions. Each logical index occupies only one row.
Query local index usage
The two views provide statistics at different granularities. Choose the appropriate view based on your troubleshooting goal:
|
View |
Granularity |
Primary use case |
|
|
Logical table level (aggregated across all physical partitions) |
Recommended for daily use. Determine whether an index should be deleted. |
|
|
Physical table (partition) level |
View index statistics on each physical partition for in-depth analysis. |
For complete column information of the views, see Metadatabases and data dictionaries.
logical_index_usage view
Query the usage of local indexes through the information_schema.logical_index_usage view to identify unused inefficient indexes. The key fields used in the following examples are described below:
|
Field |
Description |
|
|
The logical database name. |
|
|
The logical table name. For a GSI table, this is the name of the corresponding primary table. |
|
|
The index name. |
|
|
The GSI name to which the index belongs. A non-empty value indicates that the row corresponds to a local index on a GSI. An empty value indicates a local index on a regular logical table. |
|
|
The total number of times the index was accessed across all physical partitions. |
|
|
The average number of times the index was accessed per physical partition. |
|
|
The number of physical partitions that the index covers. |
Query examples
-
View the usage of all indexes:
SELECT * FROM information_schema.logical_index_usage; -
Find indexes that have never been used (
TOTAL_USAGE = 0):SELECT * FROM information_schema.logical_index_usage WHERE TOTAL_USAGE = 0; -
Filter by logical table name:
SELECT * FROM information_schema.logical_index_usage WHERE LOGICAL_TABLE = 'my_table'; -
Filter by index name:
SELECT * FROM information_schema.logical_index_usage WHERE INDEX_NAME = 'idx_col_b'; -
Filter by logical database name:
SELECT * FROM information_schema.logical_index_usage WHERE LOGICAL_SCHEMA = 'my_database'; -
Combine filters to query a specific index on a specific table:
SELECT * FROM information_schema.logical_index_usage WHERE LOGICAL_TABLE = 'my_table' AND INDEX_NAME = 'idx_col_b'; -
Find the usage of local indexes on GSIs:
SELECT * FROM information_schema.logical_index_usage WHERE GSI_NAME != '' AND GSI_NAME IS NOT NULL; -
Sort by usage to find the hottest or coldest indexes:
SELECT LOGICAL_TABLE, INDEX_NAME, TOTAL_USAGE, AVG_USAGE, PARTITION_COUNT FROM information_schema.logical_index_usage ORDER BY TOTAL_USAGE DESC; -
Find inefficient indexes (many partitions but low usage):
SELECT LOGICAL_TABLE, INDEX_NAME, TOTAL_USAGE, PARTITION_COUNT, AVG_USAGE FROM information_schema.logical_index_usage WHERE PARTITION_COUNT > 4 AND AVG_USAGE < 10 ORDER BY AVG_USAGE ASC;
physical_index_usage view
Before deleting an index, you can use the information_schema.physical_index_usage view to check the usage of the index on each physical partition. The key fields used in the following examples are described below:
|
Field |
Description |
|
|
The physical database name (the actual schema name on the DN). |
|
|
The physical table name (the actual table name on the DN). |
|
|
The index name. |
|
|
The number of times the index was accessed (reads + writes). |
|
|
The logical database name. |
|
|
The logical table name. For a GSI table, this is the GSI table name. |
Query examples
-
View the usage of all indexes on each physical partition:
SELECT * FROM information_schema.physical_index_usage; -
Find indexes that have never been used on any physical partition (
COUNT_STAR = 0):SELECT * FROM information_schema.physical_index_usage WHERE COUNT_STAR = 0; -
Filter by index name:
SELECT * FROM information_schema.physical_index_usage WHERE INDEX_NAME = 'idx_col_b'; -
Filter by logical table name:
SELECT * FROM information_schema.physical_index_usage WHERE LOGICAL_TABLE = 'my_table'; -
Filter by logical database name:
SELECT * FROM information_schema.physical_index_usage WHERE LOGICAL_SCHEMA = 'my_database'; -
View index statistics on GSI physical tables:
SELECT OBJECT_SCHEMA, OBJECT_NAME, INDEX_NAME, COUNT_STAR, LOGICAL_SCHEMA, LOGICAL_TABLE FROM information_schema.physical_index_usage WHERE LOGICAL_SCHEMA = 'my_database' AND LOGICAL_TABLE LIKE 'gsi_name%' ORDER BY COUNT_STAR DESC LIMIT 100
Query timeout control
You can set the INDEX_USAGE_QUERY_TIMEOUT parameter to control the timeout for CN to wait for results from all DNs when querying index usage views.
|
Property |
Value |
|
Type |
Long |
|
Default value |
120 (seconds) |
|
Scope |
Session level |
-
Method 1: Set through a TDDL hint. This takes effect only for the current query:
/*+TDDL:cmd_extra(INDEX_USAGE_QUERY_TIMEOUT=30)*/ SELECT * FROM information_schema.physical_index_usage; -
Method 2: Set through the SET statement. This takes effect for all subsequent queries in the current session.
SETdefaults to the SESSION scope, which is equivalent toSET SESSION INDEX_USAGE_QUERY_TIMEOUT=30;:SET INDEX_USAGE_QUERY_TIMEOUT=30; SELECT * FROM information_schema.physical_index_usage; -
When a query times out, an error is returned. The error message includes the number of DNs that have completed and those that have not. Example:
WARNING: Query timed out after 30 seconds. Retrieved results from 2/3 DN nodes.
Clear statistics
To re-observe index usage based on a specific time window, run the following command to reset the statistics to zero, wait for a period of time (such as one month) to collect new statistics, and then query the views.
CLEAR INDEX_USAGE;
Query global index usage
Two methods are available to query inefficient global indexes. Choose the appropriate method based on your goal:
|
Tool |
Output granularity |
Primary use case |
|
|
Provides problem diagnosis and optimization suggestions based on statistics and index metadata |
Recommended by default. Provides problem identification and two-step optimization suggestions (invisible then drop) in one command. |
|
|
Raw statistics only |
Use when you need to filter by raw fields such as |
Enable global index usage statistics
Diagnosing inefficient global indexes requires index usage data. Before diagnosis, enable the index usage statistics collection feature and allow it to collect data for a period of time (such as 1 day or 1 week, depending on your business traffic cycle).
SET GLOBAL GSI_STATISTICS_COLLECTION=true;
Enabling this feature slightly affects query performance (approximately 1% decrease). After diagnosis is complete, we recommend that you run SET GLOBAL GSI_STATISTICS_COLLECTION=false to disable it.
Diagnose inefficient global indexes
Use the INSPECT INDEX command to diagnose global indexes.
Syntax
INSPECT [FULL] INDEX [FROM table_name] [MODE={STATIC|DYNAMIC|MIXED}]
Parameters
-
MODE: Specifies the diagnosis mode. Three modes are supported.-
STATIC(default): Diagnoses static issues such as duplicate indexes. These issues can be identified immediately after an index is created. -
DYNAMIC: Diagnoses dynamic issues such as low index discrimination or indexes that have never been used. These issues can only be discovered after the index has been in use for a period of time. (Requires global index usage statistics to be enabled.) -
MIXED: Diagnoses both static and dynamic issues. The MIXED mode also requires index usage data to be collected over a period of time for accurate diagnosis results. (Requires global index usage statistics to be enabled.)
-
-
FROM: Specifies the table.-
If the FROM clause is omitted, all indexes in the current database are diagnosed by default.
-
If the FROM clause is specified, only the indexes on the specified table are diagnosed.
-
-
FULL: Specifies the detail level of the output.-
With the FULL option, detailed diagnosis results are returned, including identified issues and suggestions.
-
Without the FULL option, only suggestions are returned.
-
Query examples
-
For example, diagnose the following table tb1:
CREATE TABLE tb1( id int, name varchar(20), code varchar(50), primary key(id), global index idx_name(`name`) partition by key(name), global index idx_name_code(`name`, `code`) partition by key(name, code), global index idx_id(`id`) partition by key(id) ) partition by key(id); -
Run
INSPECT FULL INDEX MODE=MIXED\Gto get the MIXED mode diagnosis results:*************************** 1. row *************************** SCHEMA: d5 TABLE: tb1 INDEX: idx_id INDEX_TYPE: GLOBAL INDEX INDEX_COLUMN: id COVERING_COLUMN: USE_COUNT: 0 LAST_ACCESS_TIME: NULL DISCRIMINATION: 0.0 PROBLEM: ineffective gsi `idx_id` because it has the same rule as primary table ADVICE (STEP1): alter table `tb1` alter index `idx_id` invisible; ADVICE (STEP2): alter table `tb1` drop index `idx_id`; alter table `tb1` add local index `idx_id` (`id`);-
PROBLEMdescribes the issues with the index, such as the same partitioning rule as the primary table, duplicate index columns with other indexes, or USE_COUNT of 0 indicating the index has never been used. -
The
ADVICEfield provides two-step optimization suggestions:-
STEP1: Hide the index by using aninvisible indexto evaluate the business impact. -
STEP2: Delete the index after confirming no impact (or rebuild a better index).
To avoid affecting your business, make sure to execute
STEP1for evaluation before executing the deletion inSTEP2. -
-
global_indexes view
To help you tune global indexes, PolarDB-X also provides the INFORMATION_SCHEMA.GLOBAL_INDEXES view for viewing the usage of global indexes. Run the following command to view the global index usage:
SELECT * FROM information_schema.global_indexes WHERE `TABLE`='tb1'\G
Focus on the following fields:
|
Field |
Description |
|
|
The storage space occupied by the index. |
|
|
The number of times the index was used after |
|
|
The last time the index was used after statistics collection was enabled. |
|
|
The cardinality of the index. |
|
|
The number of rows in the index. |
A global index with USE_COUNT consistently at 0 and a large SIZE_IN_MB is a typical inefficient index.