关于 mysql 索引的一个奇怪的问题/mysql 选择错误索引 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
MySQL 5.5 Community Server
MySQL 5.6 Community Server
Percona Configuration Wizard
XtraBackup 搭建主从复制
Great Sites on MySQL
Percona
MySQL Performance Blog
Severalnines
推荐管理工具
Sequel Pro
phpMyAdmin
推荐书目
MySQL Cookbook
MySQL 相关项目
MariaDB
Drizzle
参考文档
http://mysql-python.sourceforge.net/MySQLdb.html
ovear
V2EX    MySQL

关于 mysql 索引的一个奇怪的问题/mysql 选择错误索引

  •  
  •   ovear 2015-08-11 21:27:10 +08:00 4110 次点击
    这是一个创建于 3788 天前的主题,其中的信息可能已经有所发展或是发生改变。

    OAQ 踩坑踩的伤心死了,不知道有没有大神遇到过(:з」∠)
    情景如下
    表thread有以下几个字段
    id int primary key
    fid int '所属板块
    reply int '回复的帖子id 0为帖子 其他为回复帖子的id
    lastUpdate datetime

    有索引如下
    1、联合索引 fid, reply, lastUpdate
    2、单独索引 lastUpdate

    当执行select * from thread where fid = 1 and reply = 0 order by lastUpdate desc;的时候
    mysql使用的是却是lastUpdate的单独索引,所以会进行超大量的全表搜寻。
    但是我已经为此类查询建立了合适的联合索引,但是mysql依然是不依不挠使用 lastUpdate 单独索引这是为什么呢?thx~

    在网上查到一个相同问题的,但是却没有解决这个问题
    https://github.com/ericdum/mujiang.info/issues/5

    不知道各位有没有遇到过呢?

    17 条回复    2015-08-12 18:40:00 +08:00
    jhdxr
        1
    jhdxr  
       2015-08-11 21:41:28 +08:00
    可以force index / ignor index啊
    jhdxr
        2
    jhdxr  
       2015-08-11 21:42:09 +08:00
    哦你贴的连接里也有提到这儿了。
    既然要让别人分析,为什么不把两种情况的explain贴出来看下呢。。。
    hellogbk
        3
    hellogbk  
       2015-08-11 21:43:00 +08:00
    不懂,
    你用force index让查询强制使用联合索引试试
    zts1993
        4
    zts1993  
       2015-08-11 21:59:26 +08:00
    联合索引 fid, reply 这样。?
    ovear
        5
    ovear  
    OP
       2015-08-11 22:27:33 +08:00
    @jhdxr 但是感觉这样有点奇怪=。=,我觉得应该是自己什么地方出问题了
    explain晚点我补上=。=,目前线上环境不敢乱动

    @hellogbk 恩 强制是可以的,联合索引已经试过了

    @zts1993 这样也会跑到lastUpdate去 OAQ
    F281M6Dh8DXpD1g2
        6
    F281M6Dh8DXpD1g2  
       2015-08-11 22:57:49 +08:00
    cost based optimizer 当然是选cost最低的,你可以 explain extended看下,
    或者用performance schema
    ovear
        7
    ovear  
    OP
       2015-08-11 23:41:23 +08:00
    @liprais 但是实际上似乎是我选择索引更优呢~

    mysql> explain EXTENDED SELECT * FROM `thread` force index(lastUpdate) WHERE `replyto` = 0 AND `fid` = 4 ORDER BY lastReply desc LIMIT 0,20;
    +----+-------------+------------+-------+---------------+------------+---------+------+------+----------+-------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    +----+-------------+------------+-------+---------------+------------+---------+------+------+----------+-------------+
    | 1 | SIMPLE | thread | index | NULL | lastUpdate | 6 | NULL | 20 | 9668555 | Using where |
    +----+-------------+------------+-------+---------------+------------+---------+------+------+----------+-------------+
    1 row in set

    mysql> explain EXTENDED SELECT * FROM `thread` force index(unionIndex) WHERE `replyto` = 0 AND `fid` = 4 ORDER BY lastReply desc LIMIT 0,20;
    +----+-------------+------------+------+-----------------+-----------------+---------+-------------+--------+----------+-------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    +----+-------------+------------+------+-----------------+-----------------+---------+-------------+--------+----------+-------------+
    | 1 | SIMPLE | thread | ref | unionIndex | unionIndex | 5 | const,const | 106756 | 100 | Using where |
    +----+-------------+------------+------+-----------------+-----------------+---------+-------------+--------+----------+-------------+
    1 row in set

    mysql>

    这里是explain结果在我电脑模拟出的结果,但是模拟的时候似乎选择的是 联合索引
    感觉很奇怪,不知道大神能看出原因么?
    bobbychen
        8
    bobbychen  
       2015-08-12 08:59:32 +08:00
    @ovear 你把order部分去掉之后看看,用的是什么索引
    ovear
        9
    ovear  
    OP
       2015-08-12 11:38:32 +08:00
    @bobbychen 去掉了的话,目前是使用
    reply, fid, status, lastReply
    bobbychen
        10
    bobbychen  
       2015-08-12 11:54:21 +08:00
    @ovear恩,因为查询还包括order和group by等,mysql优化器会综合考虑这些来选择index
    ovear
        11
    ovear  
    OP
       2015-08-12 12:59:59 +08:00
    @bobbychen =。=感觉选了个花费资源最多的。。用lastReply扫表每次都要扫50多W
    不知道有没有解决方法呢~
    bobbychen
        12
    bobbychen  
       2015-08-12 13:07:17 +08:00
    @ovear 可以这样建reply, fid, lastReply,status
    ovear
        13
    ovear  
    OP
       2015-08-12 13:09:54 +08:00
    @bobbychen 恩已经建立了一个了~但是还会走lastReply的单独索引,我都无奈了OAQ
    bobbychen
        14
    bobbychen  
       2015-08-12 13:11:37 +08:00
    @ovear 呵呵,建议看一看《高性能mysql》,你也许可以找到答案
    ovear
        15
    ovear  
    OP
       2015-08-12 15:21:56 +08:00
    @bobbychen 好的谢谢这位菊苣啦_(:з」∠)_
    jhdxr
        16
    jhdxr  
       2015-08-12 16:05:47 +08:00
    @ovear `explain extened` 请配合 `show warnings`使用。看你的的explain感觉很奇怪,虽然 ref 是优于 index 的,但你用lastupdate的rows才20,下面的联合索引要106756,很明显是应该用lastupdate的。

    另外我有一点不解的是,根据手册(https://dev.mysql.com/doc/refman/5.1/en/explain-extended.html) filtered 应该是个百分比,不知道你上面那个为什么会那么大。。。
    ovear
        17
    ovear  
    OP
       2015-08-12 18:40:00 +08:00
    @jhdxr 先感谢一下菊苣_(:з」∠)_

    我也觉得奇怪,因为这个值如果使用强制索引会变得非常大。。而自动选择却不会。。在我自己的开发机上无法复现,我在线上操作了一下,得到的结果感觉很奇怪

    1、强制使用lastReply
    mysql> explain EXTENDED SELECT * FROM `thread` force index(lastReply) WHERE `reply` = 0 AND `fid` = 4 ORDER BY lastReply desc LIMIT 0,20;

    +----+-------------+------------+-------+---------------+-----------+---------+------+------+----------+-------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    +----+-------------+------------+-------+---------------+-----------+---------+------+------+----------+-------------+
    | 1 | SIMPLE | thread | index | NULL | LastReply | 6 | NULL | 20 | 31195690 | Using where |
    +----+-------------+------------+-------+---------------+-----------+---------+------+------+----------+-------------+
    1 row in set

    2、强制使用联合索引
    mysql> explain EXTENDED SELECT * FROM `thread` force index(adminForumGroup) WHERE `reply` = 0 AND `fid` = 4 ORDER BY lastReply desc LIMIT 0,20;

    +----+-------------+------------+------+-----------------+-----------------+---------+-------------+--------+----------+-------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    +----+-------------+------------+------+-----------------+-----------------+---------+-------------+--------+----------+-------------+
    | 1 | SIMPLE | thread | ref | adminForumGroup | adminForumGroup | 5 | const,const | 250311 | 100 | Using where |
    +----+-------------+------------+------+-----------------+-----------------+---------+-------------+--------+----------+-------------+
    1 row in set

    3、自动选择到LastReply
    mysql> explain EXTENDED SELECT * FROM `thread` WHERE `reply` = 0 AND `fid` = 4 ORDER BY lastReply desc LIMIT 0,20;
    +----+-------------+------------+-------+--------------------------------------------------------------------+-----------+---------+------+-------+----------+-------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    +----+-------------+------------+-------+--------------------------------------------------------------------+-----------+---------+------+-------+----------+-------------+
    | 1 | SIMPLE | thread | index | balalba很多 | LastReply | 6 | NULL | 83106 | 116.44 | Using where |
    +----+-------------+------------+-------+--------------------------------------------------------------------+-----------+---------+------+-------+----------+-------------+
    1 row in set

    我刚刚也看了下 show warnings,语句里面把 * 换成了一堆 as,除此之外没有任何差别,不知道菊苣怎么看呢_(:з」∠)_

    还有一个比较惊讶的是,使用lastReply竟然rows只有20行。。很不可思议
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2946 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 13:47 PVG 21:47 LAX 05:47 JFK 08:47
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86