MySQL 大量异常数据导致慢查询

本文针对MySQL慢查询问题,分析了由于大量异常数据导致查询缓慢的原因,并通过增加索引、优化索引使用及清理异常数据等手段,显著提升了查询效率。

MySQL 大量异常数据导致慢查询

现象

服务端生产环境报错

org.springframework.dao.RecoverableDataAccessException: ### Error querying database. Cause: com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure The last packet successfully received from the server was 420,676 milliseconds ago. The last packet sent successfully to the server was 420,678 milliseconds ago.

定位到具体位置后发现是SQL查询过慢导致

select distinct mccr.xxx_id
        from ap ap
        inner join mccr mccr on ap.xxx_id = mccr.xxx_code
        where ap.status_code = 1 and mccr.status_code = 1
  • 其中ap表数据量1.3W mccr表数据链4W+
  • 两张数据量不大的表连接查询异常慢
  • 关联字段为varchar类型大概是varchar(64)
  • status_code字段为逻辑删除字段

思路

  • 考虑是否没走索引导致

    • 两个关联字段上都有索引
    • 通过explain看到inner join 自动将数据量少的ap作为驱动表,用到了被驱动表mccr的索引
  • status_code 为逻辑删除标识字段,DBA观测到SQL过慢后觉得where条件后该字段无索引导致给ap的status_code加上索引

    • 加上索引后确实变快了
  • explain查看 在ap加索引之前ap作为驱动表,ap加逻辑删除的索引后MySQL inner join选择机制变更且Extra列中出现Using index condition产生索引下推,变为mccr作为驱动表 推论考虑到ap加上索引后可以用到索引下推因此ap利用索引效率更高(可能还用到了索引合并 因为ap上 逻辑删除字段status_code和连接字段都是单独索引)

  • 现象:全表扫描4w的表比ap表要更快

  • 探索:变更 删除索引,强制用right join让mccr强制全表扫描,且去掉where后的条件,发现速度从25s降低到11s 还是很慢

  • 考虑:可能varchar索引没有建立前缀索引 导致变慢

    • 查询区分度

    • SELECT
      	count(
      	DISTINCT LEFT ( customer_id, 5 ))/ count(*) 
      FROM
      	ap;
      
    • 发现10个字符左右区分度达到一半然后无法再上升,两表都是类似现象

    • 构建前缀索引

  • 具体执行后发现前缀索引基本没什么效果

  • 通过SET profiling=1;select;SHOW PROFILE;SET profiling=0; 查看具体执行

  • 发现executing列执行时间占了95%+无法更高提升的区分度+两个字段只是not null default ''并不是唯一

  • 推论:字段实际数据有问题,导致MySQL执行查询速度慢

  • 字段异常统计

    • select customer_id,count(1) as count 
      				from ap
      				where status_code = 1
      				group by customer_id
      				order by count desc
      
    • 结果显示空字符串的数据列高达6000+占用了将近一半的空间

  • 推论:大量相同数据导致关联/查找每次都类似全表扫描

解决方案

  • 复制一张表 在其他环境做测试,将表内无效数据(空字符串)填充为随机字符串
  • 再执行关联查询发现速度变快
  • 解决方案:在where后加上 ap.customer_id != ‘’条件 过滤无效字段+索引下推极大加快查询效率

小结

  • join可以用但是join字段要加索引
  • 走索引更优但是索引的效果要足够好
  • 一个区分度极低的索引还不如全表扫描
  • 非唯一索引注意索引字段的区分度,若区分度不够高则考虑是否存在异常数据
### 提高 MySQL 导入数据速度的方法 #### 1. 禁用约束和索引 在导入大量数据前,禁用表中的所有约束和索引能够显著加快导入速度。这是因为每次插入操作都会触发索引更新,这会增加额外开销。完成数据导入后再重建这些结构能有效减少时间消耗。 ```sql ALTER TABLE table_name DISABLE KEYS; -- 执行数据导入语句... ALTER TABLE table_name ENABLE KEYS; ``` 此方法适用于MyISAM存储引擎,在InnoDB中则需采用其他方式处理[^3]。 #### 2. 使用 `LOAD DATA INFILE` 命令 相比逐条INSERT语句,利用MySQL内置的`LOAD DATA INFILE`命令可实现更高效的文件读取与解析流程,从而加速大批量记录写入数据库的过程。 ```sql LOAD DATA LOCAL INFILE '/path/to/file.csv' INTO TABLE table_name FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n'; ``` 该指令支持CSV等多种常见格式的数据源直接加载至目标表格内[^1]。 #### 3. 调整缓冲区参数配置 适当增大某些系统变量(如innodb_buffer_pool_size, bulk_insert_buffer_size)有助于改善磁盘I/O性能,进而促进整体吞吐率的增长。不过需要注意的是,过度分配内存可能导致服务器资源紧张甚至崩溃,因此建议依据实际硬件条件谨慎设置。 对于MyISAM类型的表来说,还可以尝试调大key_buffer_size来缓存更多的键值对信息,进一步缩短查询响应周期。 #### 4. 并行化处理机制 借助专门设计用于高效迁移场景下的工具——myloader,其核心优势在于实现了多线程并发执行以及智能调度算法的应用,使得整个作业能够在较短时间内顺利完成。此外,它还具备断点续传特性,即使中途遇到异常也能迅速恢复工作状态而不必重头再来一遍[^2]. ```bash myloader -d /backup/directory/ -t threads_number -o output_file.sql.gz ``` 以上措施综合运用可以从多个角度出发全面提升MySQL环境下大数据集传输效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值