一张表建立多个索引后,随着业务演进,部分索引可能不再被查询使用,却仍拖慢写入、占用存储。PolarDB-X 的低效索引查询功能可发现数据库中的低效索引(包括局部索引和全局二级索引),据此对相关索引做出必要调整(删除或重建),从而在不影响业务查询性能的前提下,提升写入性能、节约存储空间。为保持应用性能,建议定期执行低效索引查询。
适用范围
局部索引查询:实例版本需在 5.4.20-20260529 或 5.4.21-20260509 及以上。
全局索引查询:实例版本需在 5.4.17-16859297 及以上。
基本原理
低效索引查询针对两类索引,其统计数据来源不同:
局部索引(LSI):各存储节点(DN)记录每个物理表上索引的访问次数,由计算节点(CN)汇总,通过
information_schema.logical_index_usage与information_schema.physical_index_usage两张视图对外提供查询。全局索引(GSI):开启
GSI_STATISTICS_COLLECTION开关后,计算节点(CN)会记录每个全局索引的访问次数与最后访问时间。INSPECT INDEX命令基于这些数据及索引的元信息,给出诊断结论与优化建议。详细的全局索引诊断方法请参见索引诊断。
逻辑表与物理表
PolarDB-X 是分布式数据库,一张表存在逻辑与物理两个层面,理解二者的区别有助于正确解读logical_index_usage和physical_index_usage两张视图的字段含义。
逻辑表:您创建和访问的表,逻辑上是完整的一张表,位于逻辑库中。日常 SQL 中书写的库名、表名均为逻辑库名与逻辑表名。
物理表:逻辑表经过分区后,实际存储在各存储节点(DN)上的分片表,归属于物理库。一张逻辑表通常对应多个物理表,物理表名一般由逻辑表名加分区后缀构成(如
my_table_xxxx_00000)。
计算节点(CN)负责维护逻辑名与物理名之间的映射。各层概念与两张视图字段的对应关系如下:
概念 | 所在节点 | 含义 | 对应字段 |
逻辑库 | 计算节点(CN) | 您访问的数据库 |
|
逻辑表 | 计算节点(CN) | 您访问的表(逻辑上完整) |
|
物理库 | 存储节点(DN) | DN 上实际存储数据的Schema |
|
物理表 | 存储节点(DN) | DN 上实际存储的分片表(含分区后缀) |
|
由于一张逻辑表对应多个物理表,两张视图的粒度差异可据此理解:
physical_index_usage按物理表统计,同一逻辑索引在不同物理分区上各占一行,展示原始计数。logical_index_usage将同一逻辑索引在所有物理分区上的计数聚合,每个逻辑索引仅一行。
查询局部索引使用情况
两张视图提供不同粒度的统计数据,请根据排查目标选择:
视图 | 统计粒度 | 主要用途 |
| 逻辑表级别(所有物理分区汇总) | 日常首选。判断“这个索引该不该删” |
| 物理表(物理分区)级别 | 查看索引在各个物理分区上的统计数据,用于深入分析 |
视图完整的列信息详解请参见元数据库和数据字典。
logical_index_usage 视图
通过 information_schema.logical_index_usage 视图查询局部索引的使用情况,直观地识别出哪些是未被使用的低效索引。以下示例涉及的关键字段含义如下:
字段 | 说明 |
| 逻辑库名 |
| 逻辑表名(若为GSI表,此处为其对应的主表名) |
| 全局二级索引名(非GSI时为空) |
| 索引名 |
| 全分区索引被访问的次数(读 + 写) |
| 分区数 |
| 平均每分区使用量(TOTAL_USAGE / PARTITION_COUNT) |
查询示例
查看所有索引的使用情况:
SELECT * FROM information_schema.logical_index_usage;查找从未被使用的索引(
TOTAL_USAGE = 0):SELECT * FROM information_schema.logical_index_usage WHERE TOTAL_USAGE = 0;按逻辑表名过滤:
SELECT * FROM information_schema.logical_index_usage WHERE LOGICAL_TABLE = 'my_table';按索引名过滤:
SELECT * FROM information_schema.logical_index_usage WHERE INDEX_NAME = 'idx_col_b';按逻辑库名过滤:
SELECT * FROM information_schema.logical_index_usage WHERE LOGICAL_SCHEMA = 'my_database';组合过滤,查询特定表的特定索引:
SELECT * FROM information_schema.logical_index_usage WHERE LOGICAL_TABLE = 'my_table' AND INDEX_NAME = 'idx_col_b';查找全局索引(GSI)上的局部索引使用情况:
SELECT * FROM information_schema.logical_index_usage WHERE GSI_NAME != '' AND GSI_NAME IS NOT NULL;按使用量排序,查找最热或最冷的索引:
SELECT LOGICAL_TABLE, INDEX_NAME, TOTAL_USAGE, AVG_USAGE, PARTITION_COUNT FROM information_schema.logical_index_usage ORDER BY TOTAL_USAGE DESC;查找低效索引(分区多但总使用量很低):
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 视图
删除前如需更保险,可通过 information_schema.physical_index_usage 视图确认索引在每一个物理分区上的使用情况。以下示例涉及的关键字段含义如下:
字段 | 说明 |
| 物理库名(DN 上的实际 Schema 名) |
| 物理表名(DN 上的实际表名) |
| 索引名 |
| 索引被访问的次数(读 + 写) |
| 逻辑库名 |
| 逻辑表名(若为 GSI 表,此处为 GSI 表名) |
查询示例
查看所有索引在各个物理分区的使用情况:
SELECT * FROM information_schema.physical_index_usage;查找各个物理分区中从未被使用的索引(
COUNT_STAR = 0):SELECT * FROM information_schema.physical_index_usage WHERE COUNT_STAR = 0;按索引名过滤:
SELECT * FROM information_schema.physical_index_usage WHERE INDEX_NAME = 'idx_col_b';按逻辑表名过滤:
SELECT * FROM information_schema.physical_index_usage WHERE LOGICAL_TABLE = 'my_table';按逻辑库名过滤:
SELECT * FROM information_schema.physical_index_usage WHERE LOGICAL_SCHEMA = 'my_database';查看 GSI 物理表上的索引统计:
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
查询超时控制
通过设置参数 INDEX_USAGE_QUERY_TIMEOUT,控制查询索引使用视图时 CN 等待所有 DN 返回结果的超时时间。
属性 | 值 |
类型 | Long |
默认值 | 120(秒) |
作用域 | Session 级别 |
方式一:通过 TDDL hint 设置,仅对当前查询生效:
/*+TDDL:cmd_extra(INDEX_USAGE_QUERY_TIMEOUT=30)*/ SELECT * FROM information_schema.physical_index_usage;方式二:通过 SET 设置,对当前会话后续所有查询生效。
SET默认为 Session 作用域,等价于SET SESSION INDEX_USAGE_QUERY_TIMEOUT=30;:SET INDEX_USAGE_QUERY_TIMEOUT=30; SELECT * FROM information_schema.physical_index_usage;查询超时时会返回错误,错误信息中包含已完成与未完成的 DN 数量,例如:
WARNING: Query timed out after 30 seconds. Retrieved results from 2/3 DN nodes.
清除统计信息
需基于明确的时间窗口重新观察索引使用情况时,可先执行以下命令将统计数据清零,等待一段时间(例如一个月)重新收集统计信息后再查询视图。
CLEAR INDEX_USAGE;查询全局索引使用情况
查询全局索引低效性有两种方式,请按目标选择:
工具 | 输出粒度 | 主要用途 |
| 根据统计数据和索引元数据,给出问题诊断与优化建议 | 默认推荐。一次性给出问题定位与两步优化建议(invisible → drop) |
| 仅原始统计数据 | 需按 |
开启全局索引使用统计
诊断低效全局索引需要依据索引的使用数据,因此在诊断前,需先打开数据库的“索引使用信息统计”开关,让其收集一段时间(如 1 天、1 周,取决于业务流量周期)的数据。
SET GLOBAL GSI_STATISTICS_COLLECTION=true;开启该开关会轻微影响查询性能(下降 1% 左右),完成诊断后建议执行 SET GLOBAL GSI_STATISTICS_COLLECTION=false 关闭。
诊断低效全局索引
使用 INSPECT INDEX 命令对全局索引进行诊断
语法
INSPECT [FULL] INDEX [FROM table_name] [MODE={STATIC|DYNAMIC|MIXED}]参数说明
MODE:指定诊断模式,支持 3 种诊断模式。STATIC(默认):用于诊断和发现静态问题,如索引的重复。刚建立索引时即可发现这类问题。DYNAMIC:用于诊断和发现动态问题,如索引列的区分度太低、索引从未被使用。这类问题需要在索引被建立后,业务运行一段时间才能被发现。(需开启全局索引使用统计)MIXED:同时诊断静态和动态问题。MIXED 模式也需要收集一段时间的索引使用数据,才能给出准确诊断结果。(需开启全局索引使用统计)
FROM:指定数据表。不附加 FROM 选项时,默认对当前数据库的所有表的索引进行诊断。
附加 FROM 选项时,仅对指定的数据表进行诊断。
FULL:指定输出信息的详细程度。附加 FULL 选项时,会输出索引的详细诊断结果,包括存在的问题和建议。
不附加 FULL 选项时,仅输出建议。
查询示例
例如,对下表 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);执行
INSPECT FULL INDEX MODE=MIXED\G,可以得到 MIXED 模式的诊断结果:*************************** 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`);PROBLEM给出索引存在的问题(如与主表分区规则相同、索引列与其他索引重复、USE_COUNT为0从未被使用等)。ADVICE栏给出两步优化建议:STEP1:建议先用invisible index隐藏该索引以评估业务影响。STEP2:在确认无影响后再删除(或删除后重建更优的索引)。
为避免影响业务,请务必先执行
STEP1评估,再执行STEP2的删除。
global_indexes 视图
为方便您对全局索引进行调优,PolarDB-X还提供了INFORMATION_SCHEMA.GLOBAL_INDEXES视图,方便查看PolarDB-X的全局索引的使用情况。执行以下命令,查看全局索引使用情况:
SELECT * FROM information_schema.global_indexes WHERE `TABLE`='tb1'\G重点关注以下字段:
字段 | 说明 |
| 索引占用的空间 |
| 开启 |
| 开启统计后,索引最后一次被使用的时间 |
| 索引的基数 |
| 索引的行数 |
USE_COUNT 长期为 0 且 SIZE_IN_MB 较大的全局索引,即为典型的低效索引。