zoukankan      html  css  js  c++  java
  • MySQL中in子查询会导致无法使用索引问题(转)

    MySQL的测试环境

    测试表如下

    create table test_table2
    (
      id int auto_increment primary key,
      pay_id int,
      pay_time datetime,
      other_col varchar(100)
    )

    建一个存储过程插入测试数据,测试数据的特点是pay_id可重复,这里在存储过程处理成,循环插入300W条数据的过程中,每隔100条数据插入一条重复的pay_id,时间字段在一定范围内随机

    CREATE DEFINER=`root`@`%` PROCEDURE `test_insert`(IN `loopcount` INT)
      LANGUAGE SQL
      NOT DETERMINISTIC
      CONTAINS SQL
      SQL SECURITY DEFINER
      COMMENT ''
    BEGIN
      declare cnt int;
      set cnt = 0;
      while cnt< loopcount do
        insert into test_table2 (pay_id,pay_time,other_col) values (cnt,date_add(now(), interval floor(300*rand()) day),uuid());
        if (cnt mod 100 = 0) then
          insert into test_table2 (pay_id,pay_time,other_col) values (cnt,date_add(now(), interval floor(300*rand()) day),uuid());
        end if;
        set cnt = cnt + 1; 
      end while;
    END

    执行 call test_insert(3000000); 插入303000行数据

    两种子查询的写法

    查询大概的意思是查询某个时间段之内的业务Id大于1的数据,于是就出现两种写法。

    第一种写法如下:IN子查询中是某段时间内业务统计大于1的业务Id,外层按照IN子查询的结果进行查询,业务Id的列pay_id上有索引,逻辑也比较简单,这种写法,在数据量大的时候确实效率比较低,用不到索引

    select * from test_table2 force index(idx_pay_id)
    where pay_id in (
      select pay_id from test_table2
      where pay_time>="2016-06-01 00:00:00"
        AND pay_time<="2017-07-03 12:59:59"
      group by pay_id
      having count(pay_id) > 1
    );

    执行结果:2.23秒

    第二种写法,与子查询进行join关联,这种写法相当于上面的in子查询写法,下面测试发现,效率确实有不少的提高

    select tpp1.* from test_table2 tpp1,
    (
       select pay_id
       from test_table2
       WHERE pay_time>="2016-07-01 00:00:00"
       AND pay_time<="2017-07-03 12:59:59"
       group by pay_id
       having count(pay_id) > 1
    ) tpp2
    where tpp1.pay_id=tpp2.pay_id

    执行结果:0.48秒

    in子查询的执行计划,发现外层查询是一个全表扫描的方式,没有用到pay_id上的索引

    join自查的执行计划,外层(tpp1别名的查询)是用到pay_id上的索引的。

    后面想对第一种查询方式使用强制索引,虽然是不报错的,但是发现根本没用

    如果子查询是直接的值,则是可以正常使用索引的。

    见MySQL对in子查询的支持,做的确实不怎么样。

    另外:加一个使用临时表的情况,虽然比不少join方式查询的,但是也比直接使用in子查询效率要高,这种情况下,也是可以使用到索引的,不过这种简单的情况,是没有必要使用临时表的。

    总结:在MySQL数据中,截止5.7.18版本,对in子查询,仍要慎用。

    参考:

    http://www.jb51.net/article/117412.htm(以上内容转自此篇文章)

  • 相关阅读:
    hi.baidu.com 百度流量统计
    Autofac is designed to track and dispose of resources for you.
    IIS Manager could not load type for module provider 'SharedConfig' that is declared in administration.config
    How to create and manage configuration backups in Internet Information Services 7.0
    定制swagger的UI
    NSwag在asp.net web api中的使用,基于Global.asax
    NSwag Tutorial: Integrate the NSwag toolchain into your ASP.NET Web API project
    JS变量对象详解
    JS执行上下文(执行环境)详细图解
    JS内存空间详细图解
  • 原文地址:https://www.cnblogs.com/EasonJim/p/8108388.html
Copyright © 2011-2022 走看看