mysql加索引_记一次服务器执行MySQL耗时问题

本文记录了一次服务器执行MySQL耗时的问题,通过排查死锁、添加索引和优化SQL语句,成功解决了服务响应缓慢的问题。

3bee3429eb8598204325b4d5a178c4f2.png

欢迎大家一起学习交流

正在跳转​jq.qq.com

导读:本篇记录一次服务器执行MySQL耗时的问题,耗时的问题在于一句SQL执行,耗时超过1000ms,如何解决这个问题?通过这篇文章了解下。

大概过程


在测试环境Docker容器中,在跨进程调用服务的时候,A应用通过Dubbo调用B应用的RPC接口,发现B应用接口超时错误,接着通过debug和日志,发现具体耗时的地方在于一句简单SQL执行,但是耗时超过1000ms。
通过查看数据库的进程列表,发现是有死锁锁表了,很多进程状态status处于'sending data',最后为锁住的表添加索引,并且kill掉阻塞的请求,解除死锁,服务速度恢复正常。下面记录的是大致排查过程:
通过观察业务代码,确认没有内存溢出或者其它事务问题,于是只能考虑Docker环境的数据库和jvm底层详情了。

使用Druid监控SQL执行状态


通过日志,发现有一句SQL严重超时,一句简单SQL,原本是批量插入多条记录,为了定位问题,测试时Mybatis只插入一条记录,但即便如此,还是耗时10秒

3b51c2c3777eb69b0aca636486043c95.png

于是打算使用阿里巴巴的数据库连接池Druid进行监控,监控SQL效果如下:

b59f59b286ee9e299e1bb97fb523ea58.png


在SQL监控Tab中,可以看到执行SQL的具体情况,包括某条SQL语句执行的时间(平均、最慢)、SQL执行次数、SQL执行出错的次数等
上面显示的是正常情况下,时间单位是ms,正常的SQL一般在10ms之内,数据量大的控制在30ms之内,这样用户的使用体验感才会良好。所以说之前的1000ms,是不可接受的结果。

通过JMC远程监控Tomcat

JMC(java mission control)是jdk自带的一个监控工具,在jdk的bin目录下(java大法好,该目录下有很多实用的工具)。

此处加了一个tomcat无验证模式:

1b858fd4596245c3fe01f04c120c4783.png

下面是自己本地调试的截图

b2cedfc486a183677b77867ff9eaad24.png

然后打开jmc,创建一个JMX连接,输入对应的ip和JMX端口。接着可以设定一段时间内的飞行监控,监测这一分钟内jvm具体参数

当时调试的时候,发现内存使用、CPU占用率、线程状态也挺正常的,没有发现明显的异常错误,效果如下图:

0f76377be1810bea0010bb54df040c58.png

唯一比较耗时的是在代码tab页中,当时发现了大量的I/O,比上图的比例还高,当时大概占了80%,查看调用树,很多循环tcp socket连接,考虑到应用中本来就有很多需要io以及netty也需要tcp连接,所以大概排除了jvm虚拟机的问题,然后就去排查MySQL的问题。

排查MySQL

在了解MySQL锁概念的时候,由于现在使用的比较多的是InnoDB,所以可以着重看看InnoDB锁问题。

直接执行SQL语句
通过DEBUG代码,从mybatis中取出映射后的SQL语句,在MySQL客户款直接执行SQL和Explain查看执行计划,速度都很快,排除了SQL语句的问题。

查看MySQL线程列表

f072b1efcf5bf3bde9a87ebf4bbe52bb.png

60a0d844c075c9cad6bb41e844e5d2b2.png

从图中可以看出,有些线程的状态处于sending data,查阅资料:所谓的“Sending data”并不是单纯的发送数据,而是包括“收集 + 发送 数据”。

然后后面一列info显示的是具体信息,是查询用来生成主键ID的函数,之前速度都很快,为啥突然就这么慢呢,于是回过头去查看该函数:

23d6250318350b4f6d40cd6fc60267b0.png

select for update,给这个表加了排它锁,阻止其它事务取得相同数据集的共享读锁和排他写锁,同时,这个序列表表中,用来检索的字段没有加索引,在InnoDB行锁机制中:

cb064ab377504347fc1cf44bff18c79f.png

由于MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键(在我们的场景中,就是查询时用到的table_name),是会出现锁冲突的。

所以了解到其它团队因为查询这个表产生事务问题,造成死锁,这个序列表被锁住了。

由于这个自增序列表每个团队都在使用,所以当时测试环境中,经常有dao层超时错误,最终将这些阻塞的线程kill掉,为序列表加了索引,解决了问题。

小结

下次遇到MySQL执行耗时的情况,排除了代码问题之后,要去看数据库是否有死锁的情况存在,观察有没有被阻塞的线程,排查被阻塞的线程具体info,定位到具体问题。

欢迎大家一起学习交流

正在跳转​jq.qq.com
<think>好的,我现在需要帮助用户在MySQL的三个(dts_enterprise_library、dts_renovation_project、dts_acceptance_check)的credit_code字段上创建索引。首先,我得确认用户的需求。他们提到要为这三个特定的credit_code字段添索引,所以我的回答需要涵盖如何为每个单独创建索引,或者是否有联合索引的需求。不过根据字段名credit_code,通常像是统一社会信用代码,可能是一个唯一标识符,所以可能更适合普通索引或者唯一索引,但用户有说明是否是唯一,所以默认普通索引。 接下来,我需要回忆MySQL创建索引的语法。基本结构是使用CREATE INDEX语句,格式为CREATE INDEX index_name ON table_name (column_name);。这里需要确保用户有权限执行这些操作,并且有被定。另外,如果credit_code字段已经存在索引,再次创建会导致错误,所以可能需要先检查是否存在现有索引。但用户可能不需要这么详细,但作为最佳实践,可能需要提及这一点。 然后,考虑到执行这类DDL操作的影响。在大型创建索引可能会,导致数据库性能下降,甚至影响线上服务。因此,可能需要建议在低峰时段操作,或者使用在线DDL工具,比如MySQL的ALGORITHM=INPLACE和LOCK=NONE选项,如果存储引擎支持的话(比如InnoDB)。不过用户的问题可能更关注基本步骤,高级优化可能需要作为补充建议。 另外,是否需要解释索引的作用?用户可能已经了解,但简要说明为什么添索引查询有帮助,比如速WHERE、JOIN、ORDER BY等操作,特别是基于credit_code的查询。不过用户的问题直接是如何创建,所以这部分可以作为补充信息,而不是主要步骤。 然后,生成具体的SQL语句。每个都需要单独的CREATE INDEX语句索引命名方面,可以建议有意义的名称,比如idx_credit_code,但用户可能有自己的命名规范。例如: CREATE INDEX idx_credit_code ON dts_enterprise_library (credit_code); 同样适用于另外两个,替换名即可。 还需要考虑字段的数据类型,比如credit_code是否是VARCHAR,长度是否合适,索引长度限制(例如对于较长的VARCHAR字段,可能需要指定前缀长度)。如果credit_code是较长的字符串,比如统一社会信用代码通常18位,那么使用整长度作为索引可能更好,但如果有特别说明,可以默认整个字段。 此外,是否需要唯一索引?如果credit_code在中是唯一的,应该创建唯一索引以提高查询效率并保证数据唯一性。例如: CREATE UNIQUE INDEX idx_uniq_credit_code ON dts_enterprise_library (credit_code); 但用户有说明是否需要唯一性约束,所以可能需要提醒用户根据实际情况选择普通索引或唯一索引。 另外,如果中已有数据,创建索引可能会比较耗时,特别是大,需要时间处理,这也是需要考虑的因素。 可能还需要提到如何验证索引是否创建成功,比如使用SHOW INDEX FROM table_name;命令来检查。 总结步骤应该是: 1. 确认需求:是否为每个的credit_code字段创建普通索引或唯一索引。 2. 编写CREATE INDEX语句,每个一个。 3. 执行语句,并考虑执行时机以避免影响生产环境。 4. 验证索引是否创建成功。 此外,可能需要注意事项,比如索引对写操作的影响(插入、更新、删除会变慢),以及索引占用的存储空间。 用户可能还需要知道复合索引的情况,但问题中只提到单个字段,所以可能不需要涉及,除非有后续问题。 最后,生成相关问题,比如如何优化索引,如何选择索引类型,如何监控索引性能等。</think>### 分步解答 为MySQL数据库中的字段添索引可以通过以下步骤实现: --- #### **1. 确认索引类型** - **普通索引**:适用于常规查询速 - **唯一索引**:若字段值唯一且需要约束,例如:$credit\_code$ 是唯一标识 - **复合索引**:若需联合多个字段(当前需求仅单个字段) --- #### **2. 编写创建索引SQL语句** 为每个单独执行以下操作(以 `dts_enterprise_library` 为例): ```sql -- 普通索引 CREATE INDEX idx_credit_code ON dts_enterprise_library (credit_code); -- 唯一索引(如果字段值唯一) CREATE UNIQUE INDEX idx_uniq_credit_code ON dts_enterprise_library (credit_code); ``` 重复上述语句,替换名为 `dts_renovation_project` 和 `dts_acceptance_check`。 --- #### **3. 执行注意事项** - **问题**:在大型创建索引可能阻塞写入操作,建议在低峰期执行[^1] - **在线DDL**:InnoDB引擎可使用 `ALGORITHM=INPLACE, LOCK=NONE` 减少时间: ```sql CREATE INDEX idx_credit_code ON dts_enterprise_library (credit_code) ALGORITHM=INPLACE LOCK=NONE; ``` --- #### **4. 验证索引是否生效** ```sql SHOW INDEX FROM dts_enterprise_library; ``` 输出应包含 `credit_code` 字段的索引信息。 --- #### **5. 性能影响** - **优点**:速 `WHERE credit_code=...`、`JOIN` 等操作 - **缺点**:增存储空间,可能降低写操作速度 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值