zoukankan      html  css  js  c++  java
  • optimizer_switch引起的诡异问题

    参数描述

    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,希望可以帮助到遇到同样问题的朋友们。

  • 相关阅读:
    iOS NSString的常用用法
    有序数组在数据量较少时候的查找效率比较
    【转载】gdb基本命令总结
    从一个笔误引起的思考
    常见性能优化小技巧原理
    使用T-SQL进行活动目录查询
    你需要一条怎样的牛仔裤?
    #VSTS日志# 2015/12/10 – 终于可以删除工作项了
    #VSTS定制#全新的模版定制能力
    混合使用TFVC和GIT配置库的优化方案
  • 原文地址:https://www.cnblogs.com/mydriverc/p/8296728.html
Copyright © 2011-2022 走看看