MySQL order by后对其他索引的干扰,导致优化器走错索引

MySQL version:5.5.36

[email protected] 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语句:

[email protected] 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 选择性不好啊,坏了,

[email protected] 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)

[email protected] 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语句将报错。

[email protected] 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 |

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)。

时间: 2024-11-14 16:04:51

MySQL order by后对其他索引的干扰,导致优化器走错索引的相关文章

MySQL之 index merge 走错索引案例

条件:MySQL 版本:percona server 5.5.18 sql优化案例一: [email protected] 5.5.18-log cayenne 11:30:37>desc select id, grant_credit_task_id, product_id, product_code, user_id, member_id, user_credit_money, product_credit_money, real_product_credit_money, credit_s

Sql Server查询性能优化之走出索引的误区

据了解绝大多数开发人员对于索引的理解都是一知半解,局限于大多数日常工作没有机会.也什么没有必要去关心.了解索引,实在哪天某个查询太慢了找到查询条件建个索引就ok,哪天又有个查询慢了,再建立个索引就是,或者干脆把整个查询SQL直接发给DBA,让DBA直接帮忙优化了,所以造成的状况就是开发人员对于索引的理解.认识很局限,以下就把我个人对于索引的理解及浅薄认识和大家分享下,希望能解除一些大家的疑惑,一起走出索引的误区 误区1.在表上建立了索引,在查询时用到了索引的列,索引就一定会生效 首先明确下这样的

MySQL优化器不使用索引的情况

优化器选择不适用索引的情况 有时候,有乎其并没有选择索引而去查找数据,而是通过扫描聚集索引,也就是直接进行全表的扫描来得到数据.这种情况多发生于范围查找.JOIN链接操作等情况.例如 SELECT * FROM orderdetails WHERE orderid>10000 and orderid<102000; 通过SHOW INDEX FROM orderdetails可以看到 可以看到orderdetails有(orderID,ProductID)的联合主键.此外还有对于列OrderI

MySQL 走错索引导致驱动表选错

原sql: select count(*) from mpay_order mpayOrder inner join mrecharge_order_info orderinfo on mpayOrder.order_num = orderinfo.order_num inner join mpay_trade mpayTrade on mpayOrder.order_num = mpayTrade.order_num where TRUE and left(mpayTrade.trade_nu

空表情况下,优化器不用预定索引一次现象

错误描述:表行如下,表中数据为空,进行执行分析时候,发现优化器没有按照预定那样走第二条索引,很奇怪 mysql> show create table answer_survey_info\G *************************** 1. row *************************** Table: answer_survey_info Create Table: CREATE TABLE `answer_survey_info` ( `answerId` bigi

oracle走错索引不出结果

有一个脚本跑了很久不出结果,优化之后瞬间出结果.原语句如下: SQL> explain plan for 2 select * 3 from crm_dg.tb_ba_channelstaff a, 4 crm_dg.tb_ba_subscription_hist b, 5 crm_dg.tb_cm_serv c 6 where a.subs_id = b.subs_id 7 and b.serv_id = c.serv_id 8 and a.create_date >= to_date('2

mysql索引使用策略及优化

原文地址:http://blog.codinglabs.org/articles/theory-of-mysql-index.html 索引使用策略及优化 MySQL的优化主要分为结构优化(Scheme optimization)和查询优化(Query optimization).本章讨论的高性能索引策略主要属于结构优化范畴.本章的内容完全基于上文的理论基础,实际上一旦理解了索引背后的机制,那么选择高性能的策略就变成了纯粹的推理,并且可以理解这些策略背后的逻辑. 示例数据库 为了讨论索引策略,需

mysql 索引使用策略及优化

索引使用策略及优化 MySQL的优化主要分为结构优化(Scheme optimization)和查询优化(Query optimization).本章讨论的高性能索引策略主要属于结构优化范畴.本章的内容完全基于上文的理论基础,实际上一旦理解了索引背后的机制,那么选择高性能的策略就变成了纯粹的推理,并且可以理解这些策略背后的逻辑. 示例数据库 为了讨论索引策略,需要一个数据量不算小的数据库作为示例.本文选用MySQL官方文档中提供的示例数据库之一:employees.这个数据库关系复杂度适中,且数

mysql为什么有些时候会选错索引

1.基本概念 在MySQL中一张表其实是可以支持多个索引的.但是,你写SQL语句的时候,并没有主动指定使用哪个索引.也就是说,使用哪个索引是由MySQL来确定的. 一般在数据库使用的时候回遇到这样的问题,一条本来可以执行很快的语句,却由于MySQL选错了索引,导致执行速度变得很慢. 举例说明: 我们先建一个简单的表,表里有a.b两个字段,并分别建上索引: CREATE TABLE `t` ( `id` int(11) NOT NULL, `a` int(11) DEFAULT NULL, `b`