`
Asen丶
  • 浏览: 40380 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

不恰当的update语句使用主键和索引导致mysql死锁

阅读更多

 背景知识:

截至目前,MySQL一共向用户提供了包括DBD、HEAP、ISAM、MERGE、MyIAS、InnoDB以及Gemeni这7种Mysql表类型。其中DBD、InnoDB属于事务安全类表,而其他属于事务非安全类表。

 

DBD
    Berkeley DB(DBD)表是支持事务处理的表,由Sleepycat软件公司开发。它提供MySQL用户期待已久的功能--事务控制。事务控制在任何数据库系统中都是一个极有价值的功能,因为它们确保一组命令能成功地执行或回滚。

MyIASM

    MyIASM基于了IASM代码,应该可以说是IASM的衍生品,不过增加了不少有用的扩展。它是MySQL的默认数据表类型,基于了传统的ISAM类型,ISAM是Indexed Sequential Access Method(有索引的顺序访问方法)的缩写,一般来说,它是存储记录和文件的标准方法。与其他存储引擎比较,MyISAM具有检查和修复表格的大多数工具。ISAM表格可以被压缩,而且它们支持全文搜索,不过它们是事务不安全的,而且也不支持外键。如果事务回滚将会造成不完全回滚,从而不具备原子性。所以假如忽略事务以及访问并发性的话,并且需要执行大量的SELECT检索语句的话,MyISAM将是最好的选择。

InnoDB

    InnoDB是MySQL 4.0之后推出的一种比较新的数据表类型,这种类型是事务安全的。它与BDB类型具有相同的特性,它们还支持外键。InnoDB表格速度很快具有比BDB还丰富的特性,因此如果需要一个事务安全的存储引擎,建议使用它。如果你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑,同样应该使用InnoDB表。对于支持事务的InnoDB类型的表来说,影响速度的主要原因是AUTOCOMMIT默认设置是打开的,而且程序没有显式调用BEGIN 开始事务,导致每插入一条都自动提交,严重影响了速度。可以在执行sql前调用begin,多条sql形成一个事物(即使autocommit打开也可以),将大大提高性能。

 

MySQL的数据表类型很多,其中比较重要的是MyISAM,InnoDB这两种。

 

同时,MySQL有三种锁的级别:页级、表级、行级。

MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking);BDB存储引擎采用的是页面锁(page-level locking),但也支持表级锁;InnoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。

 

MySQL这3种锁的特性可大致归纳如下:

 

表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

行级锁并不是直接锁记录,而是锁索引,如果一条SQL语句用到了主键索引,mysql会锁住主键索引;如果一条语句操作了非主键索引,mysql会先锁住非主键索引,再锁定主键索引。

 

问题现象:

首先是数据库表结构如下:



 

 在执行

UPDATE ccvzb_room SET STATUS=1 WHERE begin_time<'2017-02-05 17:24:12'

 报错,报错信息为:

ERROR 1062 (23000): Duplicate entry '000e2619f0c5487880829e4165e714ff-0' for key 'PRIMARY'

 其实这条sql执行时,就产生了死锁,根据背景知识里的红色描述:如果用到了主键索引,mysql会锁定主键索引,如果用到了非主键索引,msyql会先锁定非主键索引,再锁定主键索引。如果两条sql执行间隔时间非常短的话就会出现资源争夺的情况,从而造成死锁。

解决办法:

解决办法一:

首先通过条件查询出符合条件的记录,然后根据查询出的结果的主键id再进行update操作。

UPDATE ccvzb_room a INNER JOIN ccvzb_room b ON a.room_id=b.room_id SET a.status=1 WHERE a.begin_time<'2017-02-05 17:24:12' AND a.status=0</span> 

 

 解决办法二:

UPDATE ccvzb_room SET STATUS=STATUS+1 WHERE begin_time<'2017-02-05 17:24:12' AND STATUS=0 ORDER BY STATUS

 

经验总结:

电商无论前台后台的程序,都不应该存在仅根据非主键的几个字段一查就要update/delete的场景。即使有,也应该改为先把要更新的记录查出来然后逐条按主键id更新。

  • 大小: 17.5 KB
  • 大小: 5.5 KB
1
1
分享到:
评论

相关推荐

    一个最不可思议的MySQL死锁分析1

    MySQL中的死锁问题是一个复杂而微妙的议题,尤其是在数据库优化和并发控制中。本文将深入探讨一个看似不可能发生的死锁案例,并分析其背后的原理。死锁通常发生在多个事务相互等待对方释放资源的情况下,但在这个...

    mysql死锁分析

    ### MySQL死锁分析 #### 死锁问题背景 在MySQL的使用过程中,死锁是一个较为常见的现象,尤其是在并发量较大的应用场景下。死锁的发生往往会给系统带来不可预知的影响,严重时甚至会导致整个数据库服务不可用。...

    Mysql 数据库死锁过程分析(select for update)

    避免这种死锁的一种方法是在设计事务时遵循一定的顺序规则,例如,确保所有事务按照相同的顺序访问和修改数据,或者使用`FOR UPDATE SKIP LOCKED`(Oracle支持,但MySQL不直接支持)来跳过已锁定的行。另外,可以...

    MySQL DELETE 删除语句加锁分析1

    在MySQL中,DELETE语句的加锁行为是数据库事务处理的重要组成部分,尤其是在并发环境中,正确理解其加锁机制对于避免死锁和提高系统性能至关重要。本篇文章主要探讨了在不同隔离级别下,针对不同索引类型的DELETE...

    几种不常见的MySQL InnoDB 死锁情况--1

    本篇文章将探讨几种不常见的MySQL InnoDB死锁情况。 一、死锁的概念与产生原因 死锁是指两个或多个事务在执行过程中,因争夺资源而造成的一种相互等待的现象,若无外力干涉它们都将无法推进下去。InnoDB引擎通过...

    记一次排查线上MySQL死锁过程,不能只会curd,还要知道加锁原理.doc

    在MySQL中,InnoDB存储引擎提供了事务处理和行级锁定机制,以避免并发操作带来的数据不一致性,但同时也可能导致死锁。 当MySQL检测到死锁时,它会自动选择一个事务进行回滚以打破死锁循环。在上述案例中,问题出在...

    MySQL死锁、锁、索引相关资料整理

    这是因为二级索引可能导致行锁定顺序与主键索引不一致,从而产生死锁。例如,事务A先锁定索引B的行,然后尝试锁定索引A的行,而事务B则相反,这样就形成了死锁。 解决这类问题,可以检查更新语句是否按照特定的顺序...

    一次MYSQL死锁分析案例1

    - **索引**: 死锁涉及到的是`order_pay_status`表的主键索引。 **行锁类型**: - **记录锁(LOCK_REC_NOT_GAP)**: Session1等待的锁类型,锁定具体记录。 - **间隙锁(LOCK_GAP)**: 未出现在日志中,但可能存在于...

    由不同的索引更新解决MySQL死锁套路

    通过理解死锁产生的原因和MySQL的死锁检测机制,我们可以更好地设计SQL语句和事务处理逻辑,以减少死锁的发生。在实际操作中,务必注意事务间的锁冲突,并尽可能保持一致的加锁顺序,这是预防死锁的关键。

    Mysql Innodb死锁情况分析与归纳.docx

    - 由于语句中使用了非聚簇索引`k_id_titleWeight_score`,因此不仅会对主键索引上的行加上X锁,还会对非聚簇索引上的相关行加上X锁。 ##### 锁冲突产生的原因 - **共享锁与排他锁之间的冲突**:当一个事务持有了...

    mysql-常见问题,索引优化

    松散索引(也称为非聚簇索引)不包含主键数据,只存储索引列,需要回表查找完整记录。而紧凑索引(聚簇索引)将数据和索引存储在一起,查询效率更高,但插入和删除操作相对较慢。选择哪种类型取决于具体应用。 以上...

    Mysql 行级锁的使用及死锁的预防方案

    在MySQL中,可以通过设置合适的事务隔离级别、优化查询语句(如避免索引使用的循环依赖)和调整应用程序逻辑来预防死锁。例如,确保事务按相同的顺序锁定资源,或者在更新时尽可能直接引用主键,而不是通过非主键...

    mysql基础知识和mysql优化整理

    1. 查询优化:避免全表扫描,合理使用索引,减少JOIN操作,优化SQL语句结构,避免在WHERE子句中使用不等于或NOT IN操作。 2. 索引优化:创建合适的索引,考虑使用覆盖索引,避免过多的索引,定期分析和优化索引。 ...

    Effective MySQL之SQL语句最优化

    书中的内容可能涵盖如何正确创建和设计索引,包括主键、唯一索引和非唯一索引。复合索引的使用,以及避免全表扫描,都是优化查询速度的重要策略。 2. **查询结构优化**:SQL查询的结构对执行速度有很大影响。避免...

    MYSQL必会必知

    7. 索引的使用和优化 - 索引的概念、类型(如B-Tree、Hash等)及其在查询性能优化上的作用。 - 如何创建索引以及管理索引的使用(CREATE INDEX, ALTER TABLE, DROP INDEX)。 8. 数据库的故障处理与维护 - 日志...

    阿里大牛何sir 深入MySQL加锁处理分析

    - 当使用主键(ID)进行查询且隔离级别为读已提交(RC)时,对于主键索引的操作是当前读,会加锁; - 在相同条件下,使用非唯一索引或无索引进行查询时,InnoDB会加不同类型的锁,具体取决于SQL语句; - 对于可重复...

    MySQL Innodb表导致死锁日志情况分析与归纳

    ### MySQL Innodb表导致死锁日志情况分析与归纳 #### 概述 在数据库管理领域,特别是针对MySQL的InnoDB存储引擎,了解并解决死锁问题是至关重要的。本文将详细探讨一个具体案例:当备份表格的SQL语句与删除该表...

    mysql面试题100题,包含答案和解析.docx

    MySQL面试题涵盖了许多核心知识点,包括索引使用、死锁处理、SQL优化、数据库引擎对比、分布式主键选择以及事务管理等。以下是对这些主题的详细解析: 1. **索引使用注意事项**: - 索引在含有`OR`、`LIKE`通配符...

Global site tag (gtag.js) - Google Analytics