负载变成索引需求索引设计的输入应是应用真实发出的查询,而不是表字段清单。对每类重要 SQL 记录过滤谓词、连接条件、排序、分组、分页方式、返回列、调用频率和参数分布。将查询按读写比例、延迟目标和数据规模分组,先处理对业务影响最大的形状。一个索引服务多个相近查询可能很有价值;为每个 SQL 单独建索引则容易造成重复结构和高写成本。
对于常见的 B-tree 复合索引,可以先把稳定的等值条件列放在前面,再依据范围过滤和排序需求选择后续列。例如索引 (tenant_id, status, created_at) 可为同时按租户、状态过滤并按时间访问的查询提供连续范围。若查询只按状态过滤而没有租户条件,不能假定该索引仍能高效缩小范围。左前缀决定了复合索引能否从首列开始定位。
多个等值列之间,通常再根据查询覆盖范围、选择性、关联查询和排序用途确定顺序。遇到范围谓词后,后续列通常不再像前置等值列那样继续缩小同一个连续扫描区间;不过后续列仍可能用于覆盖所需数据或满足部分排序条件。具体能力依赖数据库版本、优化器和查询形式,应以计划与实际执行验证。对谓词列施加函数、隐式类型转换,或在列上做不匹配的排序表达式,也可能让索引无法用于预期路径。
覆盖索引把查询需要的列都包含在索引记录中,有机会减少回表,但每增加一列都会使索引变宽。宽索引占用更多缓存与存储,更新和插入时需要维护更多字节,页分裂和日志写入也可能增加。返回列很多或列值很长时,为了覆盖而复制大量数据常常得不偿失。覆盖不是无成本的优化。
低基数列单独索引可能需要读取表中很大比例的记录,优化器可能认为全表扫描更便宜。但在多租户系统中,一个租户可能占据大量数据,另一个租户只有少量数据;平均选择性会掩盖这种倾斜。对典型、大租户、冷门值和范围边界分别检查实际扫描行数。注意索引优化读请求时是否让写事务变慢,且冷热工作集变化会改变索引留在内存中的概率。
通过工作负载记录和系统索引统计找出长期未使用、与其他索引高度重叠的候选项,但不要仅凭单一统计周期直接判定无用:月度报表、故障恢复查询或季节性工作可能低频却关键。制定删除候选前,先核对约束、唯一性、排序和备用查询用途,再观察充分的业务周期。索引是持续维护的负载资产,合理取舍要同时说明扫描如何减少、维护开销如何控制,以及哪些参数范围已通过验收。