免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 3583 | 回复: 18
打印 上一主题 下一主题

MySQL 选择索引疑惑 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-03-28 13:40 |只看该作者 |倒序浏览
希望大家指点

表结构如下所示:
mysql> show create table book\G
*************************** 1. row ***************************
     Table: book
Create Table: CREATE TABLE `book` (
`book_id` int(11) NOT NULL AUTO_INCREMENT,
`status` int(11) NOT NULL,
`level` int(11) NOT NULL,
`update_time` datetime DEFAULT NULL,
...... snip .......
PRIMARY KEY (`book_id`),
KEY `S_L_U` (`status`,`level`,`update_time`),
KEY `S_U` (`status`,`update_time`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
status 有6个取值,level只有2个取值。该表总共有72550行数据,status=2的有28527行数据,level=0的有72330行数据,level=1的有220行数据。

我有个Query是这样的:
select  update_time from book  where status = 2  order by update_time
desc limit offset,row_count

按照原理,该Query应该是使用S_U索引的。
当offset比较小的时候,该Query使用S_U(status,update_time)索引。
mysql> explain select  update_time from book  where status = 2  order
by update_time desc limit 100,50\G
*************************** 1. row ***************************
         id: 1
select_type: SIMPLE
      table: book
       type: range
possible_keys: S_L_U,S_U
        key: S_U
    key_len: 4
        ref: NULL
       rows: 27893
      Extra: Using where; Using index
1 row in set (0.00 sec)

但是随着offset的增大,该Query会选择使用S_L_U(status,level,update_time)索引。而且从explain的输出来看,Extra列显示还有using
index,但是我strace了这个sql的过程,发现该Query进行了50次的表数据读取,这个是第一个不理解的地方,还有为啥不选择S_U索引,S_U索引能够覆盖update_time,不是连排序都省了吗??
mysql> explain select  update_time from book  where status = 2  order
by update_time desc limit 28000,50\G
*************************** 1. row ***************************
         id: 1
select_type: SIMPLE
      table: book
       type: ref
possible_keys: S_L_U,S_U
        key: S_L_U
    key_len: 4
        ref: const
       rows: 19199
      Extra: Using where; Using index; Using filesort
1 row in set (0.00 sec)

mysql> select  update_time from book  where status = 2  order by
update_time desc limit 28000,50;
+---------------------+
| update_time         |
+---------------------+
| 2008-08-11 17:08:17 |
  ...... snip ......
| 2008-08-11 14:00:39 |
+---------------------+
50 rows in set (0.03 sec)

如果使用force index 执行使用S_U索引的话,反而没有使用S_L_U索引速度快,这个是为啥呢?
mysql> explain select  update_time from book force index(S_U) where
status = 2  order by update_time desc limit 28000,50\G
*************************** 1. row ***************************
         id: 1
select_type: SIMPLE
      table: book
       type: ref
possible_keys: S_U
        key: S_U
    key_len: 4
        ref: const
       rows: 27893
      Extra: Using where; Using index
1 row in set (0.00 sec)

mysql> select  update_time from book force index(S_U) where status = 2
order by update_time desc limit 28000,50;
+---------------------+
| update_time         |
+---------------------+
| 2008-08-11 17:08:17 |
...... snip ......
| 2008-08-11 14:00:39 |
+---------------------+
50 rows in set (0.10 sec)

论坛徽章:
4
CU大牛徽章
日期:2013-03-13 15:32:35CU大牛徽章
日期:2013-03-13 15:38:15CU大牛徽章
日期:2013-03-13 15:38:52戌狗
日期:2013-12-27 15:08:11
2 [报告]
发表于 2012-03-28 14:57 |只看该作者
where条件只有一个status
不用联合索引,直接用status做个索引呢
另外order by update_time --这个字段是没有索引的

论坛徽章:
0
3 [报告]
发表于 2012-03-28 16:55 |只看该作者
感谢2楼,但是update_time是可以使用索引的。期待其他回答。

论坛徽章:
0
4 [报告]
发表于 2012-03-28 22:36 |只看该作者
小版主杀手 发表于 2012-03-28 14:57
where条件只有一个status
不用联合索引,直接用status做个索引呢
另外order by update_time --这个字段是 ...


status要和update_time做个联合索引。

否则在status和update_time分别单独建立个索引,

会先选择索引status把记录扫描出来,然后对字段update_time逐行进行排序操作。

用explain优化器查看,应该会出现Using filesort

论坛徽章:
4
CU大牛徽章
日期:2013-03-13 15:32:35CU大牛徽章
日期:2013-03-13 15:38:15CU大牛徽章
日期:2013-03-13 15:38:52戌狗
日期:2013-12-27 15:08:11
5 [报告]
发表于 2012-03-29 11:00 |只看该作者
yuanxb1985 发表于 2012-03-28 16:55
感谢2楼,但是update_time是可以使用索引的。期待其他回答。


记得手册上有关于优化器的选择介绍

每个表的索引被查询,并且使用最好的索引,除非优化器认为使用表扫描更有效。是否使用扫描取决于是否最好的索引跨越超过30%的表。优化器更加复杂,其估计基于其它因素,例如表大小、行数和I/O块大小,因此固定比例不再决定选择使用索引还是扫描。

论坛徽章:
6
数据库技术版块每日发帖之星
日期:2015-10-11 06:20:00数据库技术版块每日发帖之星
日期:2015-10-12 06:20:00数据库技术版块每日发帖之星
日期:2015-10-15 06:20:00数据库技术版块每日发帖之星
日期:2015-10-30 06:20:00综合交流区版块每月发帖之星
日期:2015-12-02 14:59:01数据库技术版块每日发帖之星
日期:2015-12-15 06:20:00
6 [报告]
发表于 2012-03-29 11:29 |只看该作者
try:
  1. explain select  update_time from book  where status = 2  order by
  2. update_time desc,status desc  limit 28000,50;
复制代码

论坛徽章:
0
7 [报告]
发表于 2012-03-29 19:04 |只看该作者
只要有ORDER BY ,MYSQL就会用临时表!ODERY BY 中的字段用不到索引中!
为什么用S_L_U是因为MYSQL会选择最优的索引来查询!最优的索引一般都会看影响的行数!
S_L_U影响的行数明显比S_U少!

你可以再加个status索引看看!

论坛徽章:
0
8 [报告]
发表于 2012-03-30 09:55 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
9 [报告]
发表于 2012-03-30 10:05 |只看该作者
首先谢谢你的回复。但是,你的说法是不对的。请自行查看手册相应说明。回复 7# witer666


   

论坛徽章:
0
10 [报告]
发表于 2012-03-30 10:08 |只看该作者
首先感谢回复。另外,建立单个update_time索引,是可以对order by update_time 的排序做优化,但是当order by 和 limit一起使用,尤其是在offset较大的时候,使用索引排序,不如全表扫描的性能好。回复 8# kerlion


   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP