一次mysql order by 优化案例

1.  desc SELECT ActionID, UserID, CreateUser, ActionType, ActionName, ActionComment, CreateDate, PointsRulesID,Reason,ObjectID,ByUserID,ByUserName,SubjectID FROM  wikiuseractionlog Where CreateDate>'0001-01-01 00:00:00 '  and ActionType in(10,9,19,20)  ORDER BY CreateDate DESC limit 93060,20;

    

| id | select_type | table             | type | possible_keys          | key  | key_len | ref  | rows  | Extra                       |

+----+-------------+-------------------+------+------------------------+------+---------+------+-------+-----------------------------+

|  1 | SIMPLE      | wikiuseractionlog | ALL  | idx_date_type,idx_date | NULL | NULL    | NULL | 91859 | Using where; Using filesort


看执行计划,没有用上索引,虽然我建了一个复合索引idx_date_type(createdate,actiontype)和一个列索引idx_date(createdate),要使上面的语句走索引只要有下面几点:

1)需要将日期‘0001-01-01 00:00:00’改成2014-01-01 00:00:00  (2013以下都不行,不知道为什么)!!补充:DBA群有大神说:select 的结果集占全表的20%,就会走全表 ,而不走索引! 我想可能是MYSQL优化器根据CBO成本估算,如果select数据量大,估计走索引的成本会比走全表的还大,所以才会全表扫描而不走索引!


2)需将createdate和actiontype做复合索引!一般情况下order by的字段如果要走索引优化,就需要将where条件下条件字段与order by的字段做联合索引!比如: select * from test_0719 order by name;这种条件下没有where 条件字段,就算name上有索引,也还是会发生文件排序,那这种条件下,要么是增加一个where 条件字段,然后把这个字段与name做联合索引!要么是把name字段也添加到where 条件下!   


3) limit 93060,20  这种语句应该避免,如果此表不是非常大!93060行就已经占据了全表比较大的量,那mysql优化器可能就不会选择索引,就算有索引也不会走!而是选择全表扫描!因为要取的数据量非常大!mysql优化器很可能会认为走索引的成本比走全表扫描的成本还大!  同上面第一点!


mysql> desc SELECT ActionID, UserID, CreateUser, ActionType, ActionName, ActionComment, CreateDate, PointsRulesID,Reason,ObjectID,ByUserID,ByUserName,SubjectID FROM  wikiuseractionlog  ORDER BY CreateDate;

+----+-------------+-------------------+------+---------------+------+---------+------+-------+----------------+

| id | select_type | table             | type | possible_keys | key  | key_len | ref  | rows  | Extra          |

+----+-------------+-------------------+------+---------------+------+---------+------+-------+----------------+

|  1 | SIMPLE      | wikiuseractionlog | ALL  | NULL          | NULL | NULL    | NULL | 95220 | Using filesort |

+----+-------------+-------------------+------+---------------+------+---------+------+-------+----------------+

1 row in set (0.00 sec)


mysql> desc SELECT ActionID, UserID, CreateUser, ActionType, ActionName, ActionComment, CreateDate, PointsRulesID,Reason,ObjectID,ByUserID,ByUserName,SubjectID FROM  wikiuseractionlog Where CreateDate>'2014-01-01 00:00:00 '  ORDER BY CreateDate DESC  limit 93060,20;

+----+-------------+-------------------+-------+------------------------+---------------+---------+------+------+-------------+

| id | select_type | table             | type  | possible_keys          | key           | key_len | ref  | rows | Extra       |

+----+-------------+-------------------+-------+------------------------+---------------+---------+------+------+-------------+

|  1 | SIMPLE      | wikiuseractionlog | range | idx_date_type,idx_date | idx_date_type | 8       | NULL | 3737 | Using where 


4)此种情况下虽然有单独的索引idx_date(createdate),但发现依旧用不上索引,原因是order by的字段也必须出现在where 条件里,此处的原因大概也就是,排序操作是在最后的,首先提取数据的时候,如果where条件里的字段有索引,在提取出来的时候就已经做了排序操作了,此后再order by的时候就不用filesort了,不然则,在最后提取出来的数据里order by的时候,自然就要做filesort了!!



5)下面第一个例子用不上索引!第二个则可以!将ActionType in(10,9,19,20) 改成or 也不行!此处涉及到in 优化,可以尝试改成union all

mysql> desc SELECT ActionID, UserID, CreateUser, ActionType, ActionName, ActionComment, PointsRulesID,Reason,ObjectID,ByUserID,ByUserName,SubjectID FROM  wikiuseractionlog Where ActionType in(10,9,19,20)  ORDER BY CreateDate;

+----+-------------+-------------------+------+---------------+------+---------+------+-------+-----------------------------+

| id | select_type | table             | type | possible_keys | key  | key_len | ref  | rows  | Extra                       |

+----+-------------+-------------------+------+---------------+------+---------+------+-------+-----------------------------+

|  1 | SIMPLE      | wikiuseractionlog | ALL  | idx_type_date | NULL | NULL    | NULL | 90747 | Using where; Using filesort |

+----+-------------+-------------------+------+---------------+------+---------+------+-------+-----------------------------+

1 row in set (0.00 sec)


mysql> desc SELECT ActionID, UserID, CreateUser, ActionType, ActionName, ActionComment, PointsRulesID,Reason,ObjectID,ByUserID,ByUserName,SubjectID FROM  wikiuseractionlog Where ActionType ='10'  ORDER BY CreateDate;

+----+-------------+-------------------+------+---------------+---------------+---------+-------+-------+-------------+

| id | select_type | table             | type | possible_keys | key           | key_len | ref   | rows  | Extra       |

+----+-------------+-------------------+------+---------------+---------------+---------+-------+-------+-------------+

|  1 | SIMPLE      | wikiuseractionlog | ref  | idx_type_date | idx_type_date | 3       | const | 45373 | Using where |

+----+-------------+-------------------+------+---------------+---------------+---------+-------+-------+-------------+

1 row in set (0.00 sec)


总结:1

order by 后的字段,如果要走索引,须与where 条件里的某字段建立复合索引!!或者说orcer by后的字段如果要走索引排序,它要么与where 条件里的字段建立复合索引【这里建立复合索引的时候,需要注意复合索引的列顺序为(where字段,order by 字段),这样才能满足最左列原则,原因可能是order by字段并能算在where 查询条件中!】,要么它自身要在where 条件里被引用到!

总结:2

表a       id为普通字段,上面建有索引 

select * from a order by id   (用不上索引)

select id from a order by id (能用上索引)

select * from a where id=XX order by id  (能用上索引)

意思是说order by 要避免使用文件系统排序,要么把order by的字段出现在select 后,要么使用order by字段出现在where 条件里,要么把order by字段与where 条件字段建立复合索引!



你可能感兴趣的:(优化,mysql)