近日遇到个卡库的问题,环境是MySQL5.5.12,报错信息如下

[ERROR] Slave SQL: Query partially completed on the master (error on master: 1317) and was aborted. There is a chan
ce that your master is inconsistent at this point. If you are sure that your master is ok, run this query manually on the slave and
then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; . Query: 'update nls_quotes_delay_tmp A set t_volume
=(select B.t_volume from nls_quotes_delay B where A.symbol=B.symbol and A.symbol='sina')', Error_code: 1317

从报错信息上可以很直观的了解到,在主库上这个SQL部分被执行,并中断了。如果目前主库的数据是正确的,mysql建议在从库上skip这条SQL。

处理这个卡库比较简单,只要对比一下主库和从库的数据,然后稍作判断即可,我们也很快就skip过这个sql既恢复了服务。


但是处理完这个故障之后,忽然打算对update进行一下扩展的学习。

在这个场景下,开发的意图是用B的一个结果集更新A表的结果集,条件为A的一个字段等于B的一个字段。

但是明显,上面报错的SQL并不能实现这个需求,它会将A表的被更新字段全都刷成一个values,根本达不达业务的需求。那么这个SQL应该如何正确书写呢?

我们以2个表为例,aaa和bbb,表结构如下:

aaa表:
+------+------+
| x | y |
+------+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
+------+------+ bbb表:
+------+------+
| x | y |
+------+------+
| 1 | 3 |
| 2 | 4 |
| 3 | 5 |
+------+------+

目前的需求就是将bbb表的y字段的值按照aaa.x=bbb.x的条件赋值给aaa的y字段。

首先,如果是打算每次更新一行,那么sql应该写成如下,然后使用脚本等外部手段循环所有的x值。(比如for i in循环等脚本)

update aaa set y=(select y from bbb where bbb.x=2) where x=2;

然后,如果不打算使用外部脚本直接在mysql中实现呢? 那么可以按照如下写法:

update aaa set y=(select y from bbb where aaa.x=bbb.x) where x in (select x from bbb);

因为x in (select x from bbb)被等效修改为 select x from aaa where exists (select 1 from bbb where aaa.x = bbb.x)

> explain extended select * from aaa,bbb where aaa.x in (select x from bbb);
+----+--------------------+-------+------+---------------+------+---------+------+------+----------+-------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------------+-------+------+---------------+------+---------+------+------+----------+-------------------+
| 1 | PRIMARY | aaa | ALL | NULL | NULL | NULL | NULL | 4 | 100.00 | Using where |
| 1 | PRIMARY | bbb | ALL | NULL | NULL | NULL | NULL | 4 | 100.00 | Using join buffer |
| 2 | DEPENDENT SUBQUERY | bbb | ALL | NULL | NULL | NULL | NULL | 4 | 100.00 | Using where |
+----+--------------------+-------+------+---------------+------+---------+------+------+----------+-------------------+
3 rows in set, 1 warning (0.00 sec) > show warnings;
+-------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message |
+-------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note | 1003 | select `test`.`aaa`.`x` AS `x`,`test`.`aaa`.`y` AS `y`,`test`.`bbb`.`x` AS `x`,`test`.`bbb`.`y` AS `y` from `test`.`aaa` join `test`.`bbb` where <in_optimizer>(`test`.`aaa`.`x`,<exists>(select 1 from `test`.`bbb` where (<cache>(`test`.`aaa`.`x`) = `test`.`bbb`.`x`))) |
+-------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

ps:这要感谢explain extended,可以使用show warnings查看sql被改写成什么。

具体可以参看:http://www.mysqlperformanceblog.com/2006/07/24/extended-explain/

最后,我们发现如果这么写也能实现我们的目的。

update aaa set y=(select y from bbb where aaa.x=bbb.x);

但是这是有前提的,第一bbb表的x字段需要唯一,并且比aaa表的x字段的values多,否则就会变成如下这种情况。有一列会被更新成null。

 > select * from aaa;
+------+------+
| x | y |
+------+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
+------+------+
4 rows in set (0.00 sec) > select * from bbb;
+------+------+
| x | y |
+------+------+
| 1 | 5 |
| 2 | 6 |
| 3 | 7 |
+------+------+
3 rows in set (0.00 sec) m7798:10.73.11.210 > update aaa set y=(select y from bbb where aaa.x=bbb.x);
Query OK, 4 rows affected (0.01 sec)
Rows matched: 4 Changed: 4 Warnings: 0 > select * from aaa;
+------+------+
| x | y |
+------+------+
| 1 | 5 |
| 2 | 6 |
| 3 | 7 |
| 4 | NULL |
+------+------+
4 rows in set (0.01 sec)

从结果看,应该是先进行了left join然后将aaa表的y列更新了,但是具体内部逻辑,没有找到相关官方文档支持,比较可惜,继续去找原因。

MySQL遇到的一个卡库问题及对update的学习的更多相关文章

  1. java web(一) 使用sql标签库+tomcat+mysql手动创建一个jsp练习总结

    2016-09-0111:06:53                                     使用sql标签库+tomcat+mysql手动创建一个jsp 1. 1.1安装tomcat ...

  2. golang github.com/go-sql-driver/mysql 遇到的数据库,设置库设计不合理的解决方法

    golang github.com/go-sql-driver/mysql 遇到的数据库,设置库设计不合理的解决方法,查询中报了以下这个错 Scan error on column index 2: ...

  3. mysql 语句的使用清库数据转移

    mysql清空数据库表 方法1:重建库和表用mysqldump --no-data把建表SQL导出来,然后drop database再create database,执行一下导出的SQL文件: 方法2 ...

  4. mysql下批量清空某个库下的所有表(库不要删除,保留空库)

    总所周知,mysql下要想删除某个库下的某张表,只需要切换到该库下,执行语句"drop table tablename"即可删除!但若是该库下有成百上千张表,要是再这样一次次执行d ...

  5. mysql中把一个表的数据批量导入另一个表中

    mysql中把一个表的数据批量导入另一个表中   不管是在网站开发还是在应用程序开发中,我们经常会碰到需要将MySQL或MS SQLServer某个表的数据批量导入到另一个表的情况,甚至有时还需要指定 ...

  6. mysql中查询一个字段属于哪一个数据库中的哪一个表的方式

    mysql中查询一个字段具体是属于哪一个数据库的那一张表:用这条语句就能查询出来,其中 table_schema 是所在库, table_name 是所在表 --mysql中查询某一个字段名属于哪一个 ...

  7. 如何给mysql数据库添加一个用户

    首先以root身份登录到MySQL服务器中. $ mysql -u root -p 当验证提示出现的时候,输入MySQL的root帐号的密码. 创建一个MySQL用户 使用如下命令创建一个用户名和密码 ...

  8. Spring Boot+Jpa(MYSQL)做一个登陆注册系统(前后端数据库一站式编程)

    Spring Boot最好的学习方法就是实战训练,今天我们用很短的时间启动我们第一个Spring Boot应用,并且连接我们的MySQL数据库. 我将假设读者为几乎零基础,在实战讲解中会渗透Sprin ...

  9. MySQL如何搭建主库从库(Docker)

    目录 MySQL主从搭建 一.主从配置原理 二.操作步骤 1.创建主库和从库容器 2.启动主从库容器 3.远程连接并操作主从库 4.测试主从同步 MySQL主从搭建 一.主从配置原理 mysql主从配 ...

随机推荐

  1. webgote的例子(4)Sql注入(SelectGET)

    SQL Injection (Select/GET) 本章内容 (查询显示中要注意的错误) 这里面我们看一下 movie的数值,选择表单中的当我们选择的二个的时候 move的值也变成了第二个,选择表单 ...

  2. phinx:php数据库迁移

    Phinx使你的php app进行数据迁移的过程变得异常轻松,在五分钟之内你就可以安装好Phinx 并进行数据迁移. 特性 使用php代码进行数据迁移 部署模式下迁移 五分钟之内使用 不再担心数据库的 ...

  3. ftp,nfs和samba的区别

    先从名字上进行理解: 1. FTP(文件传输协议) 2. NFS(网络文件系统) 3. samba 即smb(服务信息块)协议 1 其中FTP 是TCP/IP协议栈所提供的一种子协议,该子协议具体可以 ...

  4. java中参数传递--值传递,引用传递

    java中的参数传递——值传递.引用传递   参数是按值而不是按引用传递的说明 Java 应用程序有且仅有的一种参数传递机制,即按值传递. 在 Java 应用程序中永远不会传递对象,而只传递对象引用. ...

  5. LightOJ 1370- Bi-shoe and Phi-shoe (欧拉函数)

    题目大意:一个竹竿长度为p,它的score值就是比p长度小且与且与p互质的数字总数,比如9有1,2,4,5,7,8这六个数那它的score就是6.给你T组数据,每组n个学生,每个学生都有一个幸运数字, ...

  6. 【PAT】1001. A+B Format (20)

    1001. A+B Format (20) Calculate a + b and output the sum in standard format -- that is, the digits m ...

  7. python开发学习-day09(队列、多路IO阻塞、堡垒机模块、mysql操作模块)

    s12-20160312-day09 *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: ...

  8. 易普优APS高级计划排程系统系列提纲:行业知识,业务建模,排程算法,计划可视化,平台框架,案例分享

    专注于高级计划排程系统研发与实施10来年了,国内外各种APS软件基本都研究过,这里列个提纲主要从6个方面跟大家一起讨论分享,欢迎大家鼓掌或拍砖 易普优APS高级计划排程系统系列001:行业知识,APS ...

  9. 通过 JS 实现错误页面在指定的时间跳到主页

    通过 JS 实现错误页面在指定的时间跳到主页 <!DOCTYPE html> <html> <head> <title>浏览器对象</title& ...

  10. ref:Adding AFL Bloom Filter to Domato for Fun

    ref:https://www.sigpwn.io/blog/2018/5/13/adding-afl-bloom-filter-to-domato-for-fun Adding AFL Bloom ...