简体   繁体   English

InnoDB上的MySQL UPDATE操作偶尔会超时

[英]MySQL UPDATE operations on InnoDB occasionally timeout

These are simple UPDATE s on very small tables in an InnoDB database. 这些是InnoDB数据库中非常小的表上的简单UPDATE On occasion, an operation appears to lock, and doesn't timeout. 有时,操作似乎锁定,并且不会超时。 Then every subsequent UPDATE ends with a timeout. 然后每个后续UPDATE以超时结束。 The only recourse right now is to ask my ISP to restart the daemon. 现在唯一的办法就是让我的ISP重启守护进程。 Every field in the table is used in queries, so all the fields are indexed, including a primary. 表中的每个字段都用于查询,因此所有字段都被编入索引,包括主要字段。

I'm not sure what causes the initial lock, and my ISP doesn't provide enough information to diagnose the problem. 我不确定导致初始锁定的原因,我的ISP没有提供足够的信息来诊断问题。 They are reticent about giving me access to any settings as well. 他们对于让我访问任何设置都保持沉默。

In a previous job, I was required to handle similar information, but instead I would do an INSERT . 在以前的工作中,我被要求处理类似的信息,但我会做一个INSERT Periodically, I had a script run to DELETE old records from the table, so that not so many records needed to be filtered. 我定期运行一个脚本来DELETE表中的旧记录,这样就不需要过滤那么多记录了。 When SELECT ing I used extrapolation techniques so having more than just the most recent data was useful. SELECT我使用外推技术时,不仅仅有最新的数据是有用的。 This setup was rock solid, it never hung, even under very heavy usage. 这种设置坚如磐石,即使在非常繁重的使用情况下也不会挂起。

I have no problem replacing the UPDATE with an INSERT and periodic DELETE s, but it just seems so clunky. INSERT和定期DELETE替换UPDATE没有问题,但它看起来很笨重。 Has anyone encountered a similar problem and fixed it more elegantly? 有没有人遇到类似的问题并更优雅地修复它?

Current Configuration 当前配置

  • max_heap_table_size : 16 MiB max_heap_table_size :16 MiB
  • count(*): 4 (not a typo, four records!) count(*):4(不是拼写错误,四个记录!)
  • innodb_buffer_pool_size : 1 GiB innodb_buffer_pool_size :1 GiB

Edit : DB is failing now; 编辑 :DB现在失败了; locations has 5 records. locations有5条记录。 Sample error below. 以下示例错误。

MySQL query: MySQL查询:

UPDATE locations SET x = "43.630181733", y = "-79.882244160", updated = NULL
    WHERE uuid = "6a5c7e9d-400f-c098-68bd-0a0c850b9c86";

MySQL error: MySQL错误:

Error #1205 - Lock wait timeout exceeded; 错误#1205 - 超出锁定等待超时; try restarting transaction 尝试重新启动事务

locations
Field      Type         Null  Default
uuid       varchar(36)  No
x          double       Yes    NULL
y          double       Yes    NULL
updated    timestamp    No     CURRENT_TIMESTAMP 


Indexes:
Keyname    Type     Cardinality  Field
PRIMARY    PRIMARY  5            uuid
x          INDEX    5            x
y          INDEX    5            y
updated    INDEX    5            updated

It's a known issue with InnoDB, see MySQL rollback with lost connection . 这是InnoDB的一个已知问题,请参阅连接丢失的MySQL回滚 I would welcome something like innodb_rollback_on_disconnect as mentioned there. 我会欢迎像innodb_rollback_on_disconnect提到的innodb_rollback_on_disconnect这样的东西。 What's happening to you is that you're getting connections disconnected early, as can happened on the web, and if this happens in the middle of a modifying query, the thread doing that will hang but retain a lock on the table. 发生在你身上的事情是你早期断开连接,就像在网络上发生的那样,如果在修改查询中发生这种情况,那么执行该操作的线程将挂起但保留对表的锁定。

Right now, accessing InnoDB directly with web services is vulnerable to these kinds of disconnects and there's nothing you can do within FatCow other than ask them to restart the service for you. 现在,直接使用Web服务访问InnoDB很容易受到这些类型的断开连接,除了要求他们为您重新启动服务之外,您无法在FatCow中执行任何操作。 Your idea to use MyISAM and low priority is okay, and will probably not have this problem, but if you want to go with InnoDB, would recommend an approach like the following. 您使用MyISAM和低优先级的想法是可以的,并且可能不会出现此问题,但如果您想使用InnoDB,则会建议采用如下方法。

1) Go with stored procedures, then the transactions are guaranteed to run to completion and not hang in the event of a disconnect. 1)使用存储过程,然后保证事务运行完成,并且在断开连接时不挂起。 It's a lot of work, but improves reliability big time. 这是一项很多工作,但大大提高了可靠性。

2) Don't rely on auto commit , ideally set it to zero, and explicitly begin and end each transaction with BEGIN TRANSACTION and COMMIT . 2)不要依赖auto commit ,理想情况下将其设置为零,并使用BEGIN TRANSACTIONCOMMIT显式开始和结束每个事务。

transaction1> START TRANSACTION;
transaction1> SELECT * FROM t WHERE i > 20 FOR UPDATE;
+------+
| i |
+------+
| 21 |
| 25 |
| 30 |
+------+

transaction2> START TRANSACTION;
transaction2> INSERT INTO t VALUES(26);
transaction2> COMMIT;
transaction1> select * from t where i > 20 FOR UPDATE;

+------+
| i |
+------+
| 21 |
| 25 |
| 26 |
| 30 |
+------+

What is a gap lock? 什么是差距锁定?

  1. A gap lock is a lock on the gap between index records. 缺口锁定是锁定索引记录之间的差距。 Thanks to this gap lock, when you run the same query twice, you get the same result, regardless other session modifications on that table. 由于此间隙锁定,当您运行相同的查询两次时,无论该表上的其他会话修改如何,您都会得到相同的结果。

  2. This makes reads consistent and therefore makes the replication between servers consistent. 这使得读取一致,因此使服务器之间的复制保持一致。 If you execute SELECT * FROM id > 1000 FOR UPDATE twice, you expect to get the same value twice. 如果执行SELECT * FROM id> 1000 FOR UPDATE两次,则期望获得两次相同的值。

  3. To accomplish that, InnoDB locks all index records found by the WHERE clause with an exclusive lock and the gaps between them with a shared gap lock. 为了实现这一点,InnoDB使用独占锁来锁定WHERE子句找到的所有索引记录,并使用共享间隙锁将它们之间的间隙锁定。

This lock doesn't only affect to SELECT … FOR UPDATE. 此锁定不仅影响SELECT ... FOR UPDATE。 This is an example with a DELETE statement: 这是一个带有DELETE语句的示例:

transaction1 > SELECT * FROM t;
+------+
| age |
+------+
| 21 |
| 25 |
| 30 |
+------+

Start a transaction and delete the record 25: 启动一个事务并删除记录25:

transaction1 > START TRANSACTION;
transaction1 > DELETE FROM t WHERE age=25;

At this point we suppose that only the record 25 is locked. 此时我们假设只有记录25被锁定。 Then, we try to insert another value on the second session: 然后,我们尝试在第二个会话中插入另一个值:

transaction2 > START TRANSACTION;
transaction2 > INSERT INTO t VALUES(26);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
transaction2 > INSERT INTO t VALUES(29);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
transaction2 > INSERT INTO t VALUES(23);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
transaction2 > INSERT INTO t VALUES(31);
Query OK, 1 row affected (0.00 sec)

After running the delete statement on the first session, not only the affected index record has been locked but also the gap before and after that record with a shared gap lock preventing the insertion of data to other sessions. 在第一个会话上运行delete语句后,不仅受影响的索引记录已被锁定,而且该记录之前和之后的间隙也带有共享间隙锁定,阻止将数据插入其他会话。

If your UPDATE is literally: 如果您的UPDATE字面意思是:

UPDATE locations SET updated = NULL;

You are locking all rows in the table. 您正在锁定表中的所有行。 If you abandon the transaction while holding locks on all rows, of course all rows will remain locked. 如果在对所有行保持锁定时放弃事务,当然所有行都将保持锁定状态。 InnoDB is not "unstable" in your environment, it would appear that it is doing exactly what you ask. InnoDB在您的环境中并不“不稳定”,它似乎正在按照您的要求进行操作。 You need to not abandon the open transaction. 您不需要放弃开放交易。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM