设为首页 收藏本站
查看: 314|回复: 0

[经验分享] MySQL order by后对其他索引的干扰,导致优化器走错索引

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2014-12-29 08:24:56 | 显示全部楼层 |阅读模式
MySQL version:5.5.36
xxx@172.17.62.39 5.5.36-log xxx 10:19:54>show index from FD_FINANCE_ACC_HIS;
+--------------------+------------+------------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table              | Non_unique | Key_name               | Seq_in_index | Column_name  | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+--------------------+------------+------------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| FD_FINANCE_ACC_HIS |          0 | PRIMARY                |            1 | ID           | A         |    62268963 |     NULL | NULL   |      | BTREE      |         |               |
| FD_FINANCE_ACC_HIS |          0 | accno_confirmdate_uniq |            1 | CUST_ACC_NO  | A         |     1037816 |     NULL | NULL   |      | BTREE      |         |               |
| FD_FINANCE_ACC_HIS |          0 | accno_confirmdate_uniq |            2 | CONFIRM_DATE | A         |    62268963 |     NULL | NULL   | YES  | BTREE      |         |               |
| FD_FINANCE_ACC_HIS |          1 | CONFIRM_DATE_idx       |            1 | CONFIRM_DATE | A         |          20 |     NULL | NULL   | YES  | BTREE      |         |               |
| FD_FINANCE_ACC_HIS |          1 | CREATETIME_idx         |            1 | CREATE_TIME  | A         |          20 |     NULL | NULL   | YES  | BTREE      |         |               |
+--------------------+------------+------------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
sql语句:
xxx@172.17.62.39 5.5.36-log xxx 10:19:34>desc SELECT facc.ID, facc.CREATE_TIME, facc.CONFIRM_DATE, facc.CUST_ACC_NO, facc.TOTAL_VOL, facc.TOTAL_DSB_INCOME, facc.CURDAY_DSB_INCOME, iden.CUST_NAME, iden.JD_PIN, iden.WALLET_ID, facc.SEVEN_PROFIT, facc.MILLION_PROFIT, facc.MHT_CODE FROM FD_FINANCE_ACC_HIS facc left join FD_FINANCE_IDEN as iden on facc.CUST_ACC_NO = iden.CUST_ACC_NO where 1=1 and facc.CONFIRM_DATE <= '2014-11-10' and iden.WALLET_ID = '1000001849776' order by facc.CREATE_TIME desc limit 100;
+----+-------------+-------+-------+----------------------------------------------+----------------+---------+-------+------+-------------+
| id | select_type | table | type  | possible_keys                                | key            | key_len | ref   | rows | Extra       |
+----+-------------+-------+-------+----------------------------------------------+----------------+---------+-------+------+-------------+
|  1 | SIMPLE      | iden  | const | PRIMARY,walletid_uniq,CUSTACCNO_IDENTYPE_idx | walletid_uniq  | 99      | const |    1 |             |
|  1 | SIMPLE      | facc  | index | accno_confirmdate_uniq,CONFIRM_DATE_idx      | CREATETIME_idx | 9       | NULL  |  200 | Using where |
+----+-------------+-------+-------+----------------------------------------------+----------------+---------+-------+------+-------------+
2 rows in set (0.00 sec)
sql执行时间60.011
从执行计划看,优化器明显走了order by 后的索引,但是CREATETIME_idx 选择性不好啊,坏了,
liuqirong@172.17.62.39 5.5.36-log funddb1 10:21:13>select count(distinct CREATE_TIME) from FD_FINANCE_ACC_HIS;
+-----------------------------+
| count(distinct CREATE_TIME) |
+-----------------------------+
|                         252 |
+-----------------------------+
1 row in set (0.01 sec)

xxx@172.17.62.39 5.5.36-log xxx 10:21:50>select count(*) from FD_FINANCE_ACC_HIS;
+----------+
| count(*) |
+----------+
| 62276038 |
+----------+
1 row in set (14.48 sec)
1.第一种优化方式:force index(accno_confirmdate_uniq ),但是这种方式,一旦后期有索引变更(如把force index索引删掉),sql语句将报错。
liuqirong@172.17.62.39 5.5.36-log funddb1 10:19:45>desc SELECT facc.ID, facc.CREATE_TIME, facc.CONFIRM_DATE, facc.CUST_ACC_NO, facc.TOTAL_VOL, facc.TOTAL_DSB_INCOME, facc.CURDAY_DSB_INCOME, iden.CUST_NAME, iden.JD_PIN, iden.WALLET_ID, facc.SEVEN_PROFIT, facc.MILLION_PROFIT, facc.MHT_CODE FROM FD_FINANCE_ACC_HIS facc force index(`accno_confirmdate_uniq`) left join FD_FINANCE_IDEN as iden on facc.CUST_ACC_NO = iden.CUST_ACC_NO where 1=1 and facc.CONFIRM_DATE <= '2014-11-10' and iden.WALLET_ID = '1000001849776' order by facc.CREATE_TIME desc limit 100;
+----+-------------+-------+-------+----------------------------------------------+------------------------+---------+-------+------+----------------+
| id | select_type | table | type  | possible_keys                                | key                    | key_len | ref   | rows | Extra          |
+----+-------------+-------+-------+----------------------------------------------+------------------------+---------+-------+------+----------------+
|  1 | SIMPLE      | iden  | const | PRIMARY,walletid_uniq,CUSTACCNO_IDENTYPE_idx | walletid_uniq          | 99      | const |    1 | Using filesort |
|  1 | SIMPLE      | facc  | ref   | accno_confirmdate_uniq                       | accno_confirmdate_uniq | 194     | const |   60 | Using where    |
+----+-------------+-------+-------+----------------------------------------------+------------------------+---------+-------+------+----------------+
这种方式不推荐,一旦force index的索引发生变更,此sql优化会报错,除非是实在没办法的情况下。
2.第二种优化方式:drop index CREATETIME_idx ,排除此索引对的干扰
alter table FD_FINANCE_ACC_HIS drop key `CREATETIME_idx `;
3.第三种优化方式:add 一新的索引
alter table FD_FINANCE_ACC_HIS add key  `accno_confirmdate_createtime_idx`(CUST_ACC_NO,CONFIRM_DATE,CREATE_TIME );
案例二:
mysql> explain select subscribeId, pin,projectId,projectTag,redoundId,subscribeStatus,freight,supportAmount,payAmount,isRedound,orderId,createTime,updateTime,expressCompany ,expressNum,remarks,consignee,deliveryAddress,contactPhone,receiptTime,payedTime,transactionId,payStatus,email,ordFrom,csRemarks,invoiceFlag,invoiceTitle,status,canceltag
-> from projectsubscribe
-> where projectId=194 and cancelTag=0 and payStatus in ( 3 , 5 , 4 , 6 )
-> order by subscribeId desc
-> limit 0,10;
+----+-------------+------------------+-------+----------------------------------------------------------------------------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------------+-------+----------------------------------------------------------------------------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | projectsubscribe | index | ind_paystatus,projectid_paystatus,idx_faster,projectId_cancelTag_subscribeId_idx | PRIMARY| 8 | NULL | 2052 | Using where |
+----+-------------+------------------+-------+----------------------------------------------------------------------------------+---------+---------+------+------+-------------+
1 row in set (0.39 sec)

发现是一个MySQL 5.6 优化器改进的一个bug:
mysql> show variables like 'eq_range_index_dive_limit';
+---------------------------+-------+
| Variable_name | Value |
+---------------------------+-------+
| eq_range_index_dive_limit | 10 |
1
2
col_name IN(val1, ..., valN)
col_name = val1 OR ... OR col_name = valN



eq_range_index_dive_limit:不同的值控制值优化器选择index dives、index statistics。
eq_range_index_dive_limit=0  总是使用index dives([v1,v1]、[v2,v2]...[vn,vn]
eq_range_index_dive_limit=N+1  总是使用index dives([v1,v1]、[v2,v2]...[vn,vn])
eq_range_index_dive_limit=其他 总是使用index statistics)。

解决方法:最后没办法,强制加hints(ignore index)。
mysql> explain select subscribeId, pin,projectId,projectTag,redoundId,subscribeStatus,freight,supportAmount,payAmount,isRedound,orderId,createTime,updateTime,expressCompany ,expressNum,remarks,consignee,deliveryAddress,contactPhone,receiptTime,payedTime,transactionId,payStatus,email,ordFrom,csRemarks,invoiceFlag,invoiceTitle,status,canceltag
-> from projectsubscribe ignore index(`PRIMARY`)
-> where projectId=194 and cancelTag=0 and payStatus in ( 3 , 5 , 4 , 6 )
-> order by subscribeId desc
-> limit 0,10;
执行计划:
+----+-------------+------------------+-------+----------------------------------------------------------------------------------+-------------------------------------+---------+------+-------+-------------+
| id | select_type | table            | type  | possible_keys                                                                    | key                                 | key_len | ref  | rows  | Extra       |
+----+-------------+------------------+-------+----------------------------------------------------------------------------------+-------------------------------------+---------+------+-------+-------------+
|  1 | SIMPLE      | projectsubscribe | range | ind_paystatus,projectid_paystatus,idx_faster,projectId_cancelTag_subscribeId_idx | projectId_cancelTag_subscribeId_idx | 12      | NULL | 19668 | Using where |
+----+-------------+------------------+-------+----------------------------------------------------------------------------------+-------------------------------------+---------+----


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-39405-1-1.html 上篇帖子: MySQL 走错索引导致驱动表选错 下篇帖子: MySQL数据库安全设置
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表