Diez escenarios y esquemas de optimización para fallas en el índice de MySQL

1 Preparación de datos

1.1 Crear una nueva tabla de datos

CREATE TABLE `player` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `player_id` varchar(256) NOT NULL COMMENT '运动员编号',
  `player_name` varchar(256) NOT NULL COMMENT '运动员名称',
  `height` int(11) NOT NULL COMMENT '身高',
  `weight` int(11) NOT NULL COMMENT '体重',
  `type` varchar(256) DEFAULT '0' COMMENT '球员类型',
  `game_performance` text COMMENT '最近一场比赛表现',
  PRIMARY KEY (`id`),
  KEY `idx_name_height_weight` (`player_name`,`height`,`weight`),
  KEY `idx_type` (`type`),
  KEY `idx_height` (`height`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
复制代码

La tabla de datos anterior declara tres índices:

  • Índice conjunto: idx_name_height_weight
  • Índice ordinario: idx_type
  • Índice normal: idx_height

1.2 Agregar 1 millón de piezas de datos

@SpringBootTest(classes = TestApplication.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class PlayerServiceTest {

    @Resource
    private PlayerRepository playerRepository;

    @Test
    public void initBigData() {
        for (int i = 0; i < 1000000; i++) {
            PlayerEntity entity = new PlayerEntity();
            entity.setPlayerId(UUID.randomUUID().toString());
            entity.setPlayerName("球员_" + System.currentTimeMillis());
            entity.setType("0");
            entity.setWeight(150);
            entity.setHeight(188);
            entity.setGamePerformance("{\"runDistance\":8900.0,\"passSuccess\":80.12,\"scoreNum\":3}");
            playerRepository.insert(entity);
        }
    }
}
复制代码

2 Conocimientos básicos

2.1 tipo de explicación

El tipo de acceso en el plan de ejecución es un indicador de análisis importante:

03 explain_type.jpg


2.2 Explicación adicional

Extra indica la información de extensión del plan de ejecución:

15 explain extra_完整.jpg


3 escenarios de falla del índice

Este capítulo presenta diez escenarios de falla del índice:

  • tipo de consulta incorrecto
  • La columna de índice participa en la operación.
  • uso incorrecto de comodines
  • Índice de cobertura no utilizado
  • O unirse sin campos indexados
  • MySQL abandona el uso de índices
  • falla del índice conjunto
    • índice incompleto
    • salto de índice
    • emparejamiento de no equivalencia
    • falta el índice más a la izquierda

3.1 Tipo de consulta incorrecto

3.1.1 Escenarios de falla

explain select * from player where type = 0
复制代码

01 索引失效_类型错误.jpg


3.1.2 Soluciones

La tabla de datos define typeel campo como varcharun tipo y la consulta debe usar el mismo tipo:

explain select * from player where type = '0'
复制代码

02 索引失效_类型错误_解决方案.jpg


3.2 Las columnas de índice participan en operaciones

3.2.1 Escenarios de falla

explain select * from player where height + 1 > 189
复制代码

03 索引失效_索引列参与运算.jpg


3.2.2 Soluciones

explain select * from player where height > 188
复制代码

04 索引失效_索引列参与运算_解决方案.jpg


3.3 MySQL abandona el uso de índices

3.3.1 Escenarios de falla

MySQL encuentra que si el rendimiento de usar un índice es más bajo que el de un escaneo completo de la tabla, dejará de usar el índice. Por ejemplo, todos heightlos valores de campo de datos de 1 millón en la tabla son 188, por lo que el índice se abandona al ejecutar la siguiente instrucción:

explain select * from player where height > 187
复制代码

05 索引失效_MySQL放弃使用索引.jpg


3.3.2 Solución 1

Ajuste el valor de la condición de consulta:

explain select * from player where height > 188
复制代码

06 索引失效_MySQL放弃使用索引_解决方案.jpg


3.3.3 Solución 2

Especificación de índice obligatoria, es posible que este método no mejore necesariamente el rendimiento:

explain select * from player force index(idx_height) where height > 187
复制代码

06 索引失效_MySQL放弃使用索引_解决方案_2.jpg


3.4 Uso incorrecto de comodines

3.4.1 Preparación de datos

Para evitar la falla del Capítulo 3.3, modifique un dato aquí:

update player set player_name = '测试球员' where id = 1
复制代码

3.4.2 Escenario de falla 1

explain select * from player where player_name like '%测试'
复制代码

07 索引失效_通配符1.jpg


3.4.3 Escenario de falla 2

explain select * from player where player_name like '%测试%'
复制代码

07 索引失效_通配符1.jpg


3.4.4 Soluciones

explain select * from player where player_name like '测试%'
复制代码

08 索引失效_通配符2.jpg


3.5 Conexión O sin campo de índice

3.5.1 Escenarios de falla

typeCon índice, weightsin índice:

explain select * from player where type = '0' or weight = 150
复制代码

09 索引失效_or.jpg


3.5.2 Soluciones

weightAgregar nuevos índices, unionensamblar y consultar datos

explain
select * from player where type = '0' 
union
select * from player where weight = 150
复制代码

09 索引失效_or_2.jpg


3.6 Índice de cobertura no utilizado

3.6.1 Escenarios de falla

Using index conditionIndica que se usa el índice, pero debe devolverse a la tabla para la consulta

explain select * from player where player_name like '测试%'
复制代码

16 索引失效_联合索引_未使用覆盖索引.jpg


3.6.2 Soluciones

覆盖索引含义是查询时索引列完全包含查询列,查询过程无须回表(需要在同一棵索引树)性能得到提升。Using Index; Using where表示使用覆盖索引并且用where过滤查询结果:

explain select id,player_name,height,weight from player where player_name like '测试%'
复制代码

17 索引失效_联合索引_使用覆盖索引.jpg


3.7 联合索引失效

3.7.1 完整使用

联合索引idx_name_height_weight完整使用key_len=778:

explain select * from player where player_name = '球员_1682577684751' and height = 188 and weight = 150
复制代码

10 索引失效_联合索引_完整使用.jpg


3.7.2 失效场景一:索引不完整

weight不在查询条件,所以只用到idx_name_height,所以key_len= 774:

explain select * from player where player_name = '球员_1682577684751' and height = 188
复制代码

11 索引失效_联合索引_不完整使用.jpg


3.7.3 失效场景二:索引中断

height不在查询条件,所以只用到idx_name,所以key_len= 770:

explain select * from player where player_name = '球员_1682577684751' and weight = 150
复制代码

12 索引失效_联合索引_索引中断.jpg


3.7.4 失效场景三:非等值匹配

height非等值匹配,所以只用到idx_name_height,所以key_length=774:

explain select * from player where player_name='球员_1682577684751' and height > 188 and weight = 150
复制代码

13 索引失效_联合索引_非等值匹配.jpg


3.7.5 失效场景四:最左索引缺失

player_name最左索引不在查询条件,全表扫描

explain select * from player where weight = 150
复制代码

14 索引失效_联合索引_最左匹配缺失.jpg


4 文章总结

本文第一进行测试数据准备,第二介绍执行计划相关知识,第三介绍索引失效10种场景:查询类型错误,索引列参与运算,错误使用通配符,未用到覆盖索引,OR连接无索引字段,MySQL放弃使用索引,联合索引中索引不完整,索引中断,非等值匹配,最左索引缺失。


5 延伸阅读

MySQL深分页问题原理与三种解决方案

Supongo que te gusta

Origin juejin.im/post/7230120223000870971
Recomendado
Clasificación