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 条件字段建立复合索引!