美文网首页MySQL(总)MySQL索引
关于索引不走or的思考(完结)

关于索引不走or的思考(完结)

作者: 飞翔的Tallgeese | 来源:发表于2018-03-15 15:59 被阅读1次

    原语句(金融云trade库)

    SELECT

        sum( amount )

    FROM

        tra_trade

    WHERE

        STATUS = 'success'

        AND partner_id != '*********************00008'

        AND partner_id != '*********************00074'

        AND partner_id != '*********************00009'

        AND date_format( update_time, '%y' ) = date_format( now( ), '%y' );

    存在问题

    1.存在!=,而且是3个

    2.存在对时间函数的隐式转换

    分析

    1.date_format存在函数的隐式转换,无法优化

    2.status列和partner_id列的选择性分别只有0.0000003和0.0001

    3.连续3个!=,相当于not in

    结论

    对于索引列,及时创建联合索引也不会走;

    实际测试也是如此;

    所以在前面3.13的记录里面,认为无法对其进行优化。

    转折

    忽略了查询列,查询列的选择性达到了0.11

    创建索引列和查询列的联合索引

    ALTER TABLE `trade`.`tra_trade` ADD INDEX idx_status_partnerid_amount (`status`, `partner_id`, `amount`);

    通过执行计划获知扫描行由24W行变成了4W行!

    延伸

    索引准则有一句:

    不等空值还有or,索引失效要少用

    这里很明显存在不等,反过来如果是3个等于的话,那么很明显也会存在or,但是索引确没有失效!

    首先需要明白这句话对应的条件

    tra_trade表是trade库中一张行数为24W的表,其中id,gid,trade_no选择性为1,partner_id选择性为0.0001

    create table tra_trade_test as select id,gid,merchant_order_no,trade_no,amount,seller_user_id,payer_user_id,trade_name,status,partner_id

    from tra_trade;

    create index idx_test_0 on tra_trade_test(gid);

    create index idx_test_1 on tra_trade_test(trade_no);

    create index idx_test_2 on tra_trade_test(partner_id);

    语句1

    explain

    select * from tra_trade_test where id>5000 and gid in ('*********************113e48fc','*********************113e48fe','*********************9b795a0','*********************113e4909');

    毫无意外的走索引,即使索引列的2个条件都是范围查询,扫描行数仅仅为4行

    删除gid索引

    explain

    select * from tra_trade_test where id>5000 and gid in ('*********************113e48fc','*********************113e48fe','*********************9b795a0','*********************113e4909');

    仍然走索引,扫描行数暴增到12W,key_len只有8,说明只有id走了索引,此时虽然gid上面没有了索引,但走(id的)索引代价仍然比全表要小

    语句2

    将之前删掉的索引补回去

    create index idx_test_0 on tra_trade_test(gid);

    explain

    select * from tra_trade_test where id>5000 or gid in ('*********************113e48fc','*********************113e48fe','*********************9b795a0','*********************113e4909')

    执行计划中的type类型是index_merge,扫描行数为12W,index_merge的意思是索引执行了合并,这是因为我们此时应该把id和gid组成联合索引,这样效率会更高;但此时也没有走全表

    删除gid索引

    explain

    select * from tra_trade_test where id>5000 or gid in ('*********************113e48fc','*********************113e48fe','*********************9b795a0','*********************113e4909')

    毫无疑问的走全表了(所以可以看出,准则适用的其实是这里

    语句3

    将之前删掉的索引补回去

    create index idx_test_0 on tra_trade_test(gid);

    explain

    select * from tra_trade_test

    where gid = '*********************113e48fc'

    or gid = '*********************113e48fe'

    or gid = '*********************9b795a0'

    or gid = '*********************113e4909';

    该语句等效于

    explain

    select * from tra_trade_test where gid in ('*********************113e48fc','*********************113e48fe','*********************9b795a0','*********************113e4909');

    毫无疑问的走了范围索引(可以看出,单列上存在索引,无论是否存在or,都会走索引,准则所说的情况并非这类语句

    关于not in(!=)

    语句4

    explain

    select gid from tra_trade_test

    where gid != '*********************113e48fc'

    and gid != '*********************113e48fe'

    and gid != '*********************9b795a0'

    and gid != '*********************113e4909';

    explain

    select id from tra_trade_test

    where gid != '*********************113e48fc'

    and gid != '*********************113e48fe'

    and gid != '*********************9b795a0'

    and gid != '*********************113e4909';

    上述两条都走了索引

    explain

    select trade_no from tra_trade_test

    where gid != '*********************113e48fc'

    and gid != '*********************113e48fe'

    and gid != '*********************9b795a0'

    and gid != '*********************113e4909';

    trade_no列上也建有索引,而且选择性为1,但是这条语句走了全表;

    相关文章

      网友评论

        本文标题:关于索引不走or的思考(完结)

        本文链接:https://www.haomeiwen.com/subject/dkphqftx.html