mysql 大量更新请求 updating 状态

2016-03-24 13:29:58 +08:00
 sujin190
每秒大概 100 个更新, 200 万左右数据,每次都是有索引更新,每次更新一条记录,大量处于 updating , mysql 更新操作有这么慢么?还好多都更新等待超时了,或者该怎么找出哪的问题么?
6708 次点击
所在节点    MySQL
58 条回复
sujin190
2016-03-24 21:11:37 +08:00
@likuku buffer 调大了
sujin190
2016-03-24 21:18:05 +08:00
@likuku
innodb_data_home_dir = /data/mysql/data
#innodb_data_file_path = ibdata1:10M:autoextend
innodb_log_group_home_dir = /data/mysql/data
# You can set .._buffer_pool_size up to 50 - 80 %
# of RAM but beware of setting memory usage too high
innodb_buffer_pool_size = 5G
innodb_additional_mem_pool_size = 64M
innodb_write_io_threads = 4
innodb_read_io_threads = 4
innodb_file_io_threads = 4
innodb_thread_concurrency = 8
# Set .._log_file_size to 25 % of buffer pool size
innodb_log_file_size = 512M
innodb_log_buffer_size = 16M
innodb_flush_log_at_trx_commit = 2
innodb_lock_wait_timeout = 120
innodb_max_dirty_pages_pct = 90

8 核 12g 机械硬盘
huigeer
2016-03-24 21:21:49 +08:00
主键是自增的么
sujin190
2016-03-24 21:26:24 +08:00
@huigeer 是的,但不是根据主键更新的
yangqi
2016-03-24 21:31:04 +08:00
目测是表的索引坏了,看过 show index from table 了么? Cardinality 那一列
billgreen1
2016-03-24 21:35:32 +08:00
可能是 sql 语句有问题,我昨天做查询的时候,一个字段是股票代码, 600000 这样的,数据库里是文本格式,我查询的时候却用了数字格式,可以查的出来,但是要耗时 160+秒,后来发现这个问题,查询降到了 1 秒以下。
sujin190
2016-03-24 21:37:16 +08:00
@yangqi 什么样算坏的呢?
1964190 BTREE 索引
sujin190
2016-03-24 21:38:43 +08:00
@billgreen1 貌似不是这个问题
yangqi
2016-03-24 21:38:59 +08:00
@sujin190 看 cardinality 那列,如果有 null 的话就需要优化了。另外把 update 语句换成 select 然后 explain 一下看看。
jwdstefanie
2016-03-24 21:52:14 +08:00
注意吧 where 后面的字段设置索引 速度嗷嗷的
sujin190
2016-03-24 21:54:17 +08:00
@yangqi 没有
mysql> explain select id from order where order_id='201603010140117550200039';
+----+-------------+--------------+-------+---------------+----------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------+-------+---------------+----------+---------+-------+------+-------------+
| 1 | SIMPLE | order_201603 | const | order_id | order_id | 72 | const | 1 | Using index |
+----+-------------+--------------+-------+---------------+----------+---------+-------+------+-------------+
1 row in set (0.00 sec)
不过需要更新的那个字段是 varchar 类型,默认为 NULL 更新为 30 个字符左右的值,影响么?
yangqi
2016-03-24 22:26:37 +08:00
SET profiling=1;

然后执行 update 语句

最后 show profile;
lecher
2016-03-25 00:25:27 +08:00
如果 varchar 的长度原先为空, update 一个 30 字符的值进去, mysql 要做的是开辟新的空间把整行数据迁移过去,这个过程会锁表,这个并发高起来,性能都消耗在计算空间申请新空间上了,其实还不如 insert 。

要优化,可以考虑将 varchar 字段改成定长,这样在行记录创建的时候,就会预留固定长度的位置, update 的时候就不需要重新开辟新的空间,执行 update 的消耗就与 select 基本一致,付出的代价就是这个表的文件大小会变大,因为预留的空字符串长度,等于空间换时间。
yangqi
2016-03-25 00:44:41 +08:00
另外看下你的 key_buffer_size, 还有索引大小, order_id 是 varchar 索引应该不小,如果不能放在 ram 里面的话就只能从 disk 上读写,每次 update 操作都要更新索引,肯定会慢。
sujin190
2016-03-25 09:18:23 +08:00
@lecher 改成 char 型默认空字符串行么?
sujin190
2016-03-25 09:31:39 +08:00
@yangqi key_buffer_size 512M 索引大小为 400M ,这个 key_buffer_size 是每个 db 单独分配的么?需要更新有两个 db 的两张表,数据差不多大
mysql> SHOW STATUS LIKE 'key_read%';
+-------------------+---------+
| Variable_name | Value |
+-------------------+---------+
| Key_read_requests | 1242558 |
| Key_reads | 639 |
+-------------------+---------+
2 rows in set (0.00 sec)
realpg
2016-03-25 09:40:30 +08:00
@sujin190
1. 本地服务器 or 云服务器 or RDS 服务?
2. 看你透露出来的表结构,有唯一自增主键,同时 orderid 有唯一索引,根据 orderid 去更新非索引列,这种模型对吧?那么, update 没问题,有问题的是其他查询导致的锁表,然后 update 就进队列了,发生三五十次,因为 update 非常频繁,堆积就很严重了,检查 slowlog 吧。
sujin190
2016-03-25 09:55:29 +08:00
@realpg 云服务器,通过看 show processlist;似乎不是查询锁表,而且平时是正常的,只是并发稍高的时候会这样
lecher
2016-03-25 09:57:00 +08:00
把线上数据导一份到本地测速一下便知。
noahzh
2016-03-25 10:25:41 +08:00
@sujin190 这是索引区分度的问题,key_buffer_size 只是对 myisam 有效,对 innodb 无效,这明显是并发锁的问题,索引对应列过多,加锁了.很正常.重新设计一个索引.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/266017

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX