参数描述

MySQL中不同的版本优化器会有很多新特性,比如MRR、BKA等,optimizer_switch这个参数就是控制查询优化器怎样使用这些特性。很多情况下我们会根据自身的需求去设置optimizer_switch满足我们的需求。前段时间客户的环境中遇到一个奇怪的问题,select count(*)显示返回是有数据但是select * 返回是空结果集,最终的原因就是因为optimizer_switch设置引起了一个BUG。这里和大家分享下防止大家也遇到同样的坑。

案例分析

环境描述

数据库版本MySQL5.6.35

SQL语句

  1. select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;

分析过程

当时凌晨4点左右客户打来电话告知数据库查询不到数据了非常着急,我们赶到了现场,当时的现象是这样的:

  1. select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;

这条语句查询返回的结果集是空,但是开发人员和我们说数据库中是有数据的,我当时不相信就执行了一下:

  1. select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;
  2. Emptyset(0.41 sec)
  3. select count(*)from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;
  4. +----------+
  5. | count(*)|
  6. +----------+
  7. |475|
  8. +----------+
  9. 1 row inset(0.41 sec)

当时也是比较慌张了,count(*)显示返回475条记录但是select *却返回空结果集。。。 
想了一下SQL语句有一层嵌套,我看看里面这个SQL是否有问题,测试后发现内层语句可以正常返回,加上外层语句时就会出现这种情况。询问了应用人员系统刚迁移过来,在原系统没有这种情况,快速连到原系统上执行同样的语句对比一下两边的执行计划: 
原系统

  1. explain select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;
  2. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+-----------------------------+
  3. | id | select_type | table | type | possible_keys | key | key_len |ref| rows |Extra|
  4. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+-----------------------------+
  5. |1| PRIMARY |<derived2>|ref|<auto_key0>|<auto_key0>|153|const|10|Usingwhere;Using filesort |
  6. |2| DERIVED | o | range | idx_orderdatetime | idx_orderdatetime |6| NULL |46104|Using index condition |
  7. |2| DERIVED | mm | eq_ref | PRIMARY,idx_memberid | PRIMARY |8| mall.o.buyerid |1| NULL |
  8. |2| DERIVED | ms |ref| idx_userid | idx_userid |9| mall.o.salerid |1| NULL |
  9. |2| DERIVED | mmt | eq_ref | PRIMARY,idx_merchantid | PRIMARY |8| mall.o.salerid |1| NULL |
  10. |2| DERIVED | ma | eq_ref | PRIMARY | PRIMARY |8| mall.o.activityid |1| NULL |
  11. |2| DERIVED | md |ref| idx_activityid | idx_activityid |8| mall.ma.actid |1| NULL |
  12. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+-----------------------------+
  13. 7 rows inset(0.00 sec)

新系统

  1. explain select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;
  2. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+----------------------------------+
  3. | id | select_type | table | type | possible_keys | key | key_len |ref| rows |Extra|
  4. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+----------------------------------+
  5. |1| PRIMARY |<derived2>|ref|<auto_key0>|<auto_key0>|153|const|10|Usingwhere;Using filesort |
  6. |2| DERIVED | o | range | idx_orderdatetime | idx_orderdatetime |6| NULL |46104|Using index condition;Using MRR |
  7. |2| DERIVED | mm | eq_ref | PRIMARY,idx_memberid | PRIMARY |8| mall.o.buyerid |1| NULL |
  8. |2| DERIVED | ms |ref| idx_userid | idx_userid |9| mall.o.salerid |1| NULL |
  9. |2| DERIVED | mmt | eq_ref | PRIMARY,idx_merchantid | PRIMARY |8| mall.o.salerid |1| NULL |
  10. |2| DERIVED | ma | eq_ref | PRIMARY | PRIMARY |8| mall.o.activityid |1| NULL |
  11. |2| DERIVED | md |ref| idx_activityid | idx_activityid |8| mall.ma.actid |1| NULL |
  12. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+----------------------------------+
  13. 7 rows inset(0.00 sec)

两边的执行计划不同的地方就是新系统使用了MRR,数据库的版本都是5.6.20之后的小版本号没有差很多应该不会出现这种情况。 
想到了optimizer_switch这个参数可以设置mrr特性,是不是有人修改了他,对比了两边optimizer_switch这个参数发现mrr_cost_based这个值设置的不同。快速的将参数设置为一样再次查询:

  1. set optimizer_switch='mrr_cost_based=on';
  2. Query OK,0 rows affected (0.00 sec)
  3. select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;

立刻就返回数据了。

小结

mrr_cost_based代表是否使用基于代价的方式去计算使用MRR特性,新的系统中将他设置为off代表不使用基于代价方式而是使用基于规则的,这样设置的原因是考虑到MySQL基于代价的方式比较保守不能使用到MRR这个特性。本身设置这个参数是没有任何问题,只不过是正好将遇mrr_cost_based设置为off时碰到了这么诡异BUG,希望可以帮助到遇到同样问题的朋友们。

参数描述

MySQL中不同的版本优化器会有很多新特性,比如MRR、BKA等,optimizer_switch这个参数就是控制查询优化器怎样使用这些特性。很多情况下我们会根据自身的需求去设置optimizer_switch满足我们的需求。前段时间客户的环境中遇到一个奇怪的问题,select count(*)显示返回是有数据但是select * 返回是空结果集,最终的原因就是因为optimizer_switch设置引起了一个BUG。这里和大家分享下防止大家也遇到同样的坑。

案例分析

环境描述

数据库版本MySQL5.6.35

SQL语句

  1. select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;

分析过程

当时凌晨4点左右客户打来电话告知数据库查询不到数据了非常着急,我们赶到了现场,当时的现象是这样的:

  1. select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;

这条语句查询返回的结果集是空,但是开发人员和我们说数据库中是有数据的,我当时不相信就执行了一下:

  1. select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;
  2. Emptyset(0.41 sec)
  3. select count(*)from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;
  4. +----------+
  5. | count(*)|
  6. +----------+
  7. |475|
  8. +----------+
  9. 1 row inset(0.41 sec)

当时也是比较慌张了,count(*)显示返回475条记录但是select *却返回空结果集。。。 
想了一下SQL语句有一层嵌套,我看看里面这个SQL是否有问题,测试后发现内层语句可以正常返回,加上外层语句时就会出现这种情况。询问了应用人员系统刚迁移过来,在原系统没有这种情况,快速连到原系统上执行同样的语句对比一下两边的执行计划: 
原系统

  1. explain select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;
  2. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+-----------------------------+
  3. | id | select_type | table | type | possible_keys | key | key_len |ref| rows |Extra|
  4. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+-----------------------------+
  5. |1| PRIMARY |<derived2>|ref|<auto_key0>|<auto_key0>|153|const|10|Usingwhere;Using filesort |
  6. |2| DERIVED | o | range | idx_orderdatetime | idx_orderdatetime |6| NULL |46104|Using index condition |
  7. |2| DERIVED | mm | eq_ref | PRIMARY,idx_memberid | PRIMARY |8| mall.o.buyerid |1| NULL |
  8. |2| DERIVED | ms |ref| idx_userid | idx_userid |9| mall.o.salerid |1| NULL |
  9. |2| DERIVED | mmt | eq_ref | PRIMARY,idx_merchantid | PRIMARY |8| mall.o.salerid |1| NULL |
  10. |2| DERIVED | ma | eq_ref | PRIMARY | PRIMARY |8| mall.o.activityid |1| NULL |
  11. |2| DERIVED | md |ref| idx_activityid | idx_activityid |8| mall.ma.actid |1| NULL |
  12. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+-----------------------------+
  13. 7 rows inset(0.00 sec)

新系统

  1. explain select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;
  2. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+----------------------------------+
  3. | id | select_type | table | type | possible_keys | key | key_len |ref| rows |Extra|
  4. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+----------------------------------+
  5. |1| PRIMARY |<derived2>|ref|<auto_key0>|<auto_key0>|153|const|10|Usingwhere;Using filesort |
  6. |2| DERIVED | o | range | idx_orderdatetime | idx_orderdatetime |6| NULL |46104|Using index condition;Using MRR |
  7. |2| DERIVED | mm | eq_ref | PRIMARY,idx_memberid | PRIMARY |8| mall.o.buyerid |1| NULL |
  8. |2| DERIVED | ms |ref| idx_userid | idx_userid |9| mall.o.salerid |1| NULL |
  9. |2| DERIVED | mmt | eq_ref | PRIMARY,idx_merchantid | PRIMARY |8| mall.o.salerid |1| NULL |
  10. |2| DERIVED | ma | eq_ref | PRIMARY | PRIMARY |8| mall.o.activityid |1| NULL |
  11. |2| DERIVED | md |ref| idx_activityid | idx_activityid |8| mall.ma.actid |1| NULL |
  12. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+----------------------------------+
  13. 7 rows inset(0.00 sec)

两边的执行计划不同的地方就是新系统使用了MRR,数据库的版本都是5.6.20之后的小版本号没有差很多应该不会出现这种情况。 
想到了optimizer_switch这个参数可以设置mrr特性,是不是有人修改了他,对比了两边optimizer_switch这个参数发现mrr_cost_based这个值设置的不同。快速的将参数设置为一样再次查询:

  1. set optimizer_switch='mrr_cost_based=on';
  2. Query OK,0 rows affected (0.00 sec)
  3. select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;.

立刻就返回数据了。

小结

mrr_cost_based代表是否使用基于代价的方式去计算使用MRR特性,新的系统中将他设置为off代表不使用基于代价方式而是使用基于规则的,这样设置的原因是考虑到MySQL基于代价的方式比较保守不能使用到MRR这个特性。本身设置这个参数是没有任何问题,只不过是正好将遇mrr_cost_based设置为off时碰到了这么诡异BUG,希望可以帮助到遇到同样问题的朋友们。

参数描述

MySQL中不同的版本优化器会有很多新特性,比如MRR、BKA等,optimizer_switch这个参数就是控制查询优化器怎样使用这些特性。很多情况下我们会根据自身的需求去设置optimizer_switch满足我们的需求。前段时间客户的环境中遇到一个奇怪的问题,select count(*)显示返回是有数据但是select * 返回是空结果集,最终的原因就是因为optimizer_switch设置引起了一个BUG。这里和大家分享下防止大家也遇到同样的坑。

案例分析

环境描述

数据库版本MySQL5.6.35

SQL语句

  1. select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;

分析过程

当时凌晨4点左右客户打来电话告知数据库查询不到数据了非常着急,我们赶到了现场,当时的现象是这样的:

  1. select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;

这条语句查询返回的结果集是空,但是开发人员和我们说数据库中是有数据的,我当时不相信就执行了一下:

  1. select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;
  2. Emptyset(0.41 sec)
  3. select count(*)from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;
  4. +----------+
  5. | count(*)|
  6. +----------+
  7. |475|
  8. +----------+
  9. 1 row inset(0.41 sec)

当时也是比较慌张了,count(*)显示返回475条记录但是select *却返回空结果集。。。 
想了一下SQL语句有一层嵌套,我看看里面这个SQL是否有问题,测试后发现内层语句可以正常返回,加上外层语句时就会出现这种情况。询问了应用人员系统刚迁移过来,在原系统没有这种情况,快速连到原系统上执行同样的语句对比一下两边的执行计划: 
原系统

  1. explain select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;
  2. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+-----------------------------+
  3. | id | select_type | table | type | possible_keys | key | key_len |ref| rows |Extra|
  4. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+-----------------------------+
  5. |1| PRIMARY |<derived2>|ref|<auto_key0>|<auto_key0>|153|const|10|Usingwhere;Using filesort |
  6. |2| DERIVED | o | range | idx_orderdatetime | idx_orderdatetime |6| NULL |46104|Using index condition |
  7. |2| DERIVED | mm | eq_ref | PRIMARY,idx_memberid | PRIMARY |8| mall.o.buyerid |1| NULL |
  8. |2| DERIVED | ms |ref| idx_userid | idx_userid |9| mall.o.salerid |1| NULL |
  9. |2| DERIVED | mmt | eq_ref | PRIMARY,idx_merchantid | PRIMARY |8| mall.o.salerid |1| NULL |
  10. |2| DERIVED | ma | eq_ref | PRIMARY | PRIMARY |8| mall.o.activityid |1| NULL |
  11. |2| DERIVED | md |ref| idx_activityid | idx_activityid |8| mall.ma.actid |1| NULL |
  12. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+-----------------------------+
  13. 7 rows inset(0.00 sec)

新系统

  1. explain select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;
  2. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+----------------------------------+
  3. | id | select_type | table | type | possible_keys | key | key_len |ref| rows |Extra|
  4. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+----------------------------------+
  5. |1| PRIMARY |<derived2>|ref|<auto_key0>|<auto_key0>|153|const|10|Usingwhere;Using filesort |
  6. |2| DERIVED | o | range | idx_orderdatetime | idx_orderdatetime |6| NULL |46104|Using index condition;Using MRR |
  7. |2| DERIVED | mm | eq_ref | PRIMARY,idx_memberid | PRIMARY |8| mall.o.buyerid |1| NULL |
  8. |2| DERIVED | ms |ref| idx_userid | idx_userid |9| mall.o.salerid |1| NULL |
  9. |2| DERIVED | mmt | eq_ref | PRIMARY,idx_merchantid | PRIMARY |8| mall.o.salerid |1| NULL |
  10. |2| DERIVED | ma | eq_ref | PRIMARY | PRIMARY |8| mall.o.activityid |1| NULL |
  11. |2| DERIVED | md |ref| idx_activityid | idx_activityid |8| mall.ma.actid |1| NULL |
  12. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+----------------------------------+
  13. 7 rows inset(0.00 sec)

两边的执行计划不同的地方就是新系统使用了MRR,数据库的版本都是5.6.20之后的小版本号没有差很多应该不会出现这种情况。 
想到了optimizer_switch这个参数可以设置mrr特性,是不是有人修改了他,对比了两边optimizer_switch这个参数发现mrr_cost_based这个值设置的不同。快速的将参数设置为一样再次查询:

  1. set optimizer_switch='mrr_cost_based=on';
  2. Query OK,0 rows affected (0.00 sec)
  3. select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;

立刻就返回数据了。

小结

mrr_cost_based代表是否使用基于代价的方式去计算使用MRR特性,新的系统中将他设置为off代表不使用基于代价方式而是使用基于规则的,这样设置的原因是考虑到MySQL基于代价的方式比较保守不能使用到MRR这个特性。本身设置这个参数是没有任何问题,只不过是正好将遇mrr_cost_based设置为off时碰到了这么诡异BUG,希望可以帮助到遇到同样问题的朋友们。

参数描述

MySQL中不同的版本优化器会有很多新特性,比如MRR、BKA等,optimizer_switch这个参数就是控制查询优化器怎样使用这些特性。很多情况下我们会根据自身的需求去设置optimizer_switch满足我们的需求。前段时间客户的环境中遇到一个奇怪的问题,select count(*)显示返回是有数据但是select * 返回是空结果集,最终的原因就是因为optimizer_switch设置引起了一个BUG。这里和大家分享下防止大家也遇到同样的坑。

案例分析

环境描述

数据库版本MySQL5.6.35

SQL语句

  1. select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;

分析过程

当时凌晨4点左右客户打来电话告知数据库查询不到数据了非常着急,我们赶到了现场,当时的现象是这样的:

  1. select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;

这条语句查询返回的结果集是空,但是开发人员和我们说数据库中是有数据的,我当时不相信就执行了一下:

  1. select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;
  2. Emptyset(0.41 sec)
  3. select count(*)from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;
  4. +----------+
  5. | count(*)|
  6. +----------+
  7. |475|
  8. +----------+
  9. 1 row inset(0.41 sec)

当时也是比较慌张了,count(*)显示返回475条记录但是select *却返回空结果集。。。 
想了一下SQL语句有一层嵌套,我看看里面这个SQL是否有问题,测试后发现内层语句可以正常返回,加上外层语句时就会出现这种情况。询问了应用人员系统刚迁移过来,在原系统没有这种情况,快速连到原系统上执行同样的语句对比一下两边的执行计划: 
原系统

  1. explain select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;
  2. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+-----------------------------+
  3. | id | select_type | table | type | possible_keys | key | key_len |ref| rows |Extra|
  4. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+-----------------------------+
  5. |1| PRIMARY |<derived2>|ref|<auto_key0>|<auto_key0>|153|const|10|Usingwhere;Using filesort |
  6. |2| DERIVED | o | range | idx_orderdatetime | idx_orderdatetime |6| NULL |46104|Using index condition |
  7. |2| DERIVED | mm | eq_ref | PRIMARY,idx_memberid | PRIMARY |8| mall.o.buyerid |1| NULL |
  8. |2| DERIVED | ms |ref| idx_userid | idx_userid |9| mall.o.salerid |1| NULL |
  9. |2| DERIVED | mmt | eq_ref | PRIMARY,idx_merchantid | PRIMARY |8| mall.o.salerid |1| NULL |
  10. |2| DERIVED | ma | eq_ref | PRIMARY | PRIMARY |8| mall.o.activityid |1| NULL |
  11. |2| DERIVED | md |ref| idx_activityid | idx_activityid |8| mall.ma.actid |1| NULL |
  12. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+-----------------------------+
  13. 7 rows inset(0.00 sec)

新系统

  1. explain select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;
  2. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+----------------------------------+
  3. | id | select_type | table | type | possible_keys | key | key_len |ref| rows |Extra|
  4. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+----------------------------------+
  5. |1| PRIMARY |<derived2>|ref|<auto_key0>|<auto_key0>|153|const|10|Usingwhere;Using filesort |
  6. |2| DERIVED | o | range | idx_orderdatetime | idx_orderdatetime |6| NULL |46104|Using index condition;Using MRR |
  7. |2| DERIVED | mm | eq_ref | PRIMARY,idx_memberid | PRIMARY |8| mall.o.buyerid |1| NULL |
  8. |2| DERIVED | ms |ref| idx_userid | idx_userid |9| mall.o.salerid |1| NULL |
  9. |2| DERIVED | mmt | eq_ref | PRIMARY,idx_merchantid | PRIMARY |8| mall.o.salerid |1| NULL |
  10. |2| DERIVED | ma | eq_ref | PRIMARY | PRIMARY |8| mall.o.activityid |1| NULL |
  11. |2| DERIVED | md |ref| idx_activityid | idx_activityid |8| mall.ma.actid |1| NULL |
  12. +----+-------------+------------+--------+------------------------+-------------------+---------+-------------------+-------+----------------------------------+
  13. 7 rows inset(0.00 sec)

两边的执行计划不同的地方就是新系统使用了MRR,数据库的版本都是5.6.20之后的小版本号没有差很多应该不会出现这种情况。 
想到了optimizer_switch这个参数可以设置mrr特性,是不是有人修改了他,对比了两边optimizer_switch这个参数发现mrr_cost_based这个值设置的不同。快速的将参数设置为一样再次查询:

  1. set optimizer_switch='mrr_cost_based=on';
  2. Query OK,0 rows affected (0.00 sec)
  3. select*from(select o.orderid,o.orderdatetime,o.orderstatus,o.price,o.expway,o.paytype,o.fee,o.ordertype,o.realid,mm.account,ms.shopname,mmt.organcode, o.activitype,o.channelcode, ma.activitytag,md.tagtip from mall_order o left join mall_member mm on o.buyerid=mm.memberid left join mall_shop ms on o.salerid=ms.userid left join mall_merchant mmt on mmt.merchantid=o.salerid left join mall_activity ma on o.activityid=ma.actid left join mall_direct_activity md on ma.actid=md.actid where1=1and o.orderdatetime >='2017-03-01 01:40:03'and o.orderdatetime <='2017-03-25 01:40:03')as tab where tab.organcode ='805000' order by orderdatetime desc limit 10;.

立刻就返回数据了。

小结

mrr_cost_based代表是否使用基于代价的方式去计算使用MRR特性,新的系统中将他设置为off代表不使用基于代价方式而是使用基于规则的,这样设置的原因是考虑到MySQL基于代价的方式比较保守不能使用到MRR这个特性。本身设置这个参数是没有任何问题,只不过是正好将遇mrr_cost_based设置为off时碰到了这么诡异BUG,希望可以帮助到遇到同样问题的朋友们。

optimizer_switch引起的诡异问题的更多相关文章

  1. 你还可以再诡异点吗——SQL日志文件不断增长

    前言 今天算是遇到了一个罕见的案例. SQL日志文件不断增长的各种实例不用多说,园子里有很多牛人有过介绍,如果我再阐述这些陈谷子芝麻,想必已会被无数次吐槽. 但这次我碰到的问题确实比较诡异,其解决方式 ...

  2. Delphi编程时候诡异地出现ORA-00937错误,记录解决它的思路和方法

    首先需要说明,这个问题的出现需要几个前提:使用微软的Oracle驱动(使用Oracle自己的驱动不会出现这个问题).使用绑定变量法,使用Format等方式拼接SQL也不会出现这个问题,还有一些诡异的规 ...

  3. 诡异的localhost无法连接

    上午试了localhost发现提示无法连接,ping了下localhost,能够ping通. 重启了Apache,还是无法解决. 试着停止了Apache服务,然后再连接localhost,发现浏览器提 ...

  4. 记SQL SERVER一次诡异的优化

    最近做的项目快上线了,在做了一次压力测试后发现了不少问题,基本都是因为数据量达到一定级别时(预测系统上线10年后的数据量)SQL查询超时,其中有些是因为索引缺失.有些是因为写法不好,这些在有经验的人眼 ...

  5. 诡异的C语言实参求值顺序

    学了这么久的C语言,竟然第一次碰到这么诡异的实参求值顺序问题,大跌眼镜.果然阅读面太少了! #include<iostream> void foo(int a, int b, int c) ...

  6. SSH框架使用中存在的诡异异常

    背景 相信大多数人目前都在使用Spring + Struts2/SpringMVC + Hibernate来构建项目的整体架构,但是在使用中经藏会遇到一些诡异的问题,不知道如果解决,今天我遇到了一个非 ...

  7. Oracle诡异结果调查备忘 - A investigation memo of weird Oracle database search results

    最近需要维护一个差不多十多年前开发的ASP.Net程序,遇到了各种奇奇怪怪的问题,把其中比较难查明的问题记录如下: 问题一: 同样的SQL查询在不同服务器上查询结果不同.在QA环境下,结果完全正常,而 ...

  8. 遭遇flash播放mp3诡异问题

    在部分ie10+flash player 播放mp3,播放第二句话时,中断无法正常播放,(客户的机器上),自己公司的机器测试了几个,都没发现这个问题.其它浏览器(chrome,firefox)也没发现 ...

  9. 番外特别篇之 为什么我不建议你直接使用UIImage传值?--从一个诡异的相册九图连读崩溃bug谈起

    关于"番外特别篇" 所谓"番外特别篇",就是系列文章更新期间内,随机插入的一篇文章.目前我正在更新的系列文章是 实现iOS图片等资源文件的热更新化.但是,这两天 ...

随机推荐

  1. 限制IP远程访问

    方法一:通过hosts.allow和hosts.deny文件进行ip限制 在/etc/目录下,同时存在hosts.allow和hosts.deny文件 如果我们希望某些ip不能访问,那么我们可以打开h ...

  2. 三星笔记本安装系统时报错:image failed to verify with * access denied* press any key to continue.

    安装系统从光盘启动报错: 出现黑屏,并且有一个提示框image failed to verify with *access denied*press any key to continue 原因:三星 ...

  3. leecode 978. Longest Turbulent Subarray(最长连续波动序列,DP or 滚动数组)

    传送门:点我 978. Longest Turbulent Subarray A subarray A[i], A[i+1], ..., A[j] of A is said to be turbule ...

  4. ds.Tables[0].Rows.RemoveAt(i)数据库表格删除行

    不要在循环里使用myDataTable.Rows.RemoveAt(i).因为每删除一行后.i的值会增加,但行数会是减少了.这么做一定会出错.因此要遍历数据,使用Remove方式时,要倒序的遍历int ...

  5. chase

    chase 英[tʃeɪs] 美[tʃes] vt. 追求; 追捕; 追寻; 镂刻; n. 追捕; 打猎; 猎物(指鸟兽等); 槽; vi. 追逐,追赶; 追寻; 追求(常与after连用); [口语 ...

  6. c中堆栈的理解

    一直对堆栈的使用以及全局变量.静态全局变量.局部变量.静态局部变量.初始化的全局变量.未初始化的全局变量.初始化的局部变量.未初始化的局部变量理解的不是很清楚,今天抽个时间来总结以下这方面的知识: 1 ...

  7. vue初学:基础概念

    一.vue使用步骤: 1.引包vue.js 2.html中写要操作的DOM节点 3.创建vue对象:new Vue({options}); 4.配置options:el:(要操作的对象,用选择器,同j ...

  8. Java使用点滴

    1.查找某个字符在字符串中第几次出现的位置 /** * 查找某个字符在字符串中第几次出现的位置 * @param string 要匹配的字符串 * @param i 第几次出现 * @param ch ...

  9. 使用BootStrap框架中的轮播插件

    在使用bootstrap框架中的轮播插件时,效果做出来后,无法通过点击小圆行的按钮来选择特定的图片. 后面发现是最开始的<div>标签中少写了一个id.一开始<div>标签是这 ...

  10. wheelView实现滚动选择 三方开源的封装控件 spannableString autofitTextView、PinnedSectionListView SwipeListView等等

    wheelView多用于popupwindow用来滚动选择条目 github上的开源三方控件     spannableString   autofitTextView.PinnedSectionLi ...