• MySQL优化器 limit影响的case


    测试的用例中,因为limit的大小不同,而产生了完全不同的执行计划:

    1. 测试case:  

    create table t1 (
      f1 int(11) not null,
      f2 int(11) not null,
      f3 int(11) not null,
      f4 tinyint(1) not null,
      primary key (f1),
      unique key (f2, f3),
      key (f4)
    ) engine=innodb;
    
    insert into t1 values
    (1,1,991,1), (2,1,992,1), (3,1,993,1), (4,1,994,1), (5,1,995,1),
    (6,1,996,1), (7,1,997,1), (8,1,998,1), (10,1,999,1), (11,1,9910,1),
    (16,1,9911,1), (17,1,9912,1), (18,1,9913,1), (19,1,9914,1), (20,1,9915,1),
    (21,1,9916,1), (22,1,9917,1), (23,1,9918,1), (24,1,9919,1), (25,1,9920,1),
    (26,1,9921,1), (27,1,9922,1);

    2. 两个不同limit的sql生成的执行计划:

      

      

    3. 分析过程:

      

    step 1.  获取可用的key,并计算rows

        update_ref_and_keys

          get_quick_record_count

      结果: f2, f4可用, 其分配的quick_rows=[22, 22]

      

      从上面的cardinality来看,f2,f4的过滤性都是2, 这样扫描f2,需要11行,然后根据primary回聚簇表扫描,有需要11行,所有,使用f2, f4索引的扫描需要22行。

       

    step2:穷举下执行计划,找到cost最低的

        best_access_path

          best_extension_by_limited_search

       结果: 全表扫描的代价比较低,records=17, cost=2, 所以最后join->best_position[0]记录的就是全表扫描的执行计划。

       

    step3:limit的影响

          在make_join_select的过程,对于limit进行处理,理由是:如果有limit,并且比当前best_position的记录数小,我们尝试是否有可用的index,减少扫描代价

          所以,在limit=10的时候,进行test_quick_select查找,并使用f2的索引。而limit=20的查询,不满足条件,所以继续使用全表扫描。

        

    相关注释和代码如下:      

    /*
            We plan to scan all rows.
            Check again if we should use an index.
            We could have used an column from a previous table in
            the index if we are using limit and this is the first table
          */
          if ((cond &&
                  !tab->keys.is_subset(tab->const_keys) && i > 0) ||
              (!tab->const_keys.is_clear_all() && i == join->const_tables &&
               join->unit->select_limit_cnt <
               join->best_positions[i].records_read &&
               !(join->select_options & OPTION_FOUND_ROWS)))

      

    step4: order by的影响

          函数:test_if_skip_sort_order

          limit=10:ref_key=f2:   判断有一个primary key的index可以覆盖order by查询, 但走pk的代价高于ref_key=f2。

           limit=20:ref_key=0:     判断有一个primary key的index可以覆盖order by查询,而且当前使用的是全表扫描,代价小于全表,所以选择pk。

    所以,两个limit值不同的查询,导致了不同的执行计划。

  • 相关阅读:
    面向对象串讲
    昨日回顾
    socketserver模块
    今日总结
    在centos6.5-64bit上安装wxHexEditor,以查看编译二进制文件
    spring security 关于 http.sessionManagement().maximumSessions(1);的探究
    spring boot + spring security +前后端分离【跨域】配置 + ajax的json传输数据
    window10 查看端口列表
    spring boot 解决 跨域 的两种方法 -- 前后端分离
    spring security 动态 修改当前登录用户的 权限
  • 原文地址:https://www.cnblogs.com/xpchild/p/3878417.html
Copyright © 2020-2023  润新知