zoukankan      html  css  js  c++  java
  • 关于MySQL IN LIKE OR使用索引的问题

    以前在网上看了一些资料,有些人说话不严谨,导致一直被误导,最近在实际开发中发现一些结论有问题,因此特地整理了一下,防止下次继续犯错。

    以下前提是有对这个字段建立索引(简直废话,没建的肯定不会使用索引啊)

    首先建立一张表:

    CREATE DATABASE `test_lkc` CHARATER SET utf8 COLLATE utf8_general_ci;

    CREATE
    TABLE `students` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `stuno` varchar(9) NOT NULL DEFAULT '' COMMENT '学号', `name` varchar(64) NOT NULL DEFAULT '' COMMENT '姓名', `major` varchar(255) NOT NULL DEFAULT '' COMMENT '专业', `class` int(10) unsigned NOT NULL DEFAULT '1' COMMENT '班级', `id_card` varchar(18) NOT NULL DEFAULT '' COMMENT '身份证号码', `memo` varchar(255) NOT NULL DEFAULT '' COMMENT '备注', PRIMARY KEY (`id`), UNIQUE KEY `stuno` (`stuno`) USING BTREE, UNIQUE KEY `id_card` (`id_card`) USING BTREE, KEY `major_class` (`major`,`class`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

     数据我是用php批量生成的

    <?php
    $pdo = new PDO("mysql:host=127.0.0.1;dbname=test_lkc","root","root");
    //数据
    $addList = [];
    $majorList = ['CN','EN','JP','KO','RU','SV','CU','DE','FR','RO'];
    $prefixList = ['A','B','C','D','E','F','G','H','I','J'];
    for ($i=0;$i<1000;$i++){
        $row = [];
        $id = sprintf('%03d',$i);
        $row['stuno'] = $prefixList[$i/100] . '2017' . sprintf('%04d',$i + 1);
        $row['name'] = $prefixList[$id[0]] . $prefixList[$id[1]] . $prefixList[$id[2]];
        $row['major'] = $majorList[$id[0]];
        $row['class'] = $i%3 + 1;
        $row['id_card'] = '320106194910290' . $id;
    
        $addList[] = $row;
    }
    
    $res = addAll($pdo,$addList);
    var_dump($res);
    
    function addAll($pdo,$addList){
        //字段
        $sql = "INSERT INTO `students` (`" . implode("`,`",array_keys($addList[0])) . "`) VALUES ";
        //拼接SQL语句
        foreach ($addList as $value){
            $sql .= "('";
            $sql .= implode("','", $value);
            $sql .= "'),";
        }
        $sql = rtrim($sql,',');
    
        $res = $pdo->exec($sql);
        return $res ? $res : $pdo->errorInfo();
    }

    1.IN到底会不会使用索引?

    答:会!

    explain select * from students where id_card IN ('320106194910290999','320106194910290998');

    如果没有走索引,那么可能是你的使用姿势不对,比如

    (1)字符串类型没有加单引号,

    explain select * from students where id_card IN (320106194910290999,320106194910290998);

    (2)或者mysql认为使用全表扫描要比使用索引快(我自己遇到的是数据太少或者查询出来的结果很多的时候会出现,比如图中预估的行数是952),则不使用索引

    explain select * from students where major IN ('RO','CN');

    2.OR到底会不会使用索引?

    答:会!

    explain select * from students where id = 1 or stuno = 'A20170002';

    如果没有走索引,那么肯定又是你的使用姿势不对,比如说

    (1)两个条件里面其中一个字段没有建立索引;

    explain select * from students where id = 1 or name = 'AAB';

    (2)字符串类型的没有加单引号;

    explain select * from students where id = 1 or id_card = 320106194910290999;

    (3)mysql认为使用全表扫描要比使用索引快,则不使用索引

    explain select * from students where id = 1 or major = 'CN';

    3.LIKE会不会使用索引

    答:LIKE 'xxx%'会;

    (1)LIKE'%xxx'或者LIKE'%xxx%'不会

    explain select * from students where stuno like 'A2017%';

    explain select * from students where stuno like '%20170001';

    (2)mysql认为使用全表扫描要比使用索引快,则不使用索引

    explain select * from students where major like 'C%';

     

    说来惭愧,我自己被错误的结论误导了那么久,希望大家引以为戒,网络上的答案也不一定就是对的,还是要自己多试试。实践才是检验真理的唯一标准

    在查询语句前面加explain ,根据type和key来分析查询到底有没有使用索引

    type排行:
        连接类型
        system          表只有一行
        const           表最多只有一行匹配,通用用于主键或者唯一索引比较时
        eq_ref          每次与之前的表合并行都只在该表读取一行,这是除了system,const之外最好的一种,
                        特点是使用=,而且索引的所有部分都参与join且索引是主键或非空唯一键的索引
        ref             如果每次只匹配少数行,那就是比较好的一种,使用=或<=>,可以是左覆盖索引或非主键或非唯一键
        fulltext        全文搜索
        ref_or_null     与ref类似,但包括NULL
        index_merge     表示出现了索引合并优化(包括交集,并集以及交集之间的并集),但不包括跨表和全文索引。
                        这个比较复杂,目前的理解是合并单表的范围索引扫描(如果成本估算比普通的range要更优的话)
        unique_subquery 在in子查询中,就是value in (select...)把形如“select unique_key_column”的子查询替换。
                        PS:所以不一定in子句中使用子查询就是低效的!
        index_subquery  同上,但把形如”select non_unique_key_column“的子查询替换
        range           常数值的范围
        index           a.当查询是索引覆盖的,即所有数据均可从索引树获取的时候(Extra中有Using Index);
                        b.以索引顺序从索引中查找数据行的全表扫描(无 Using Index);
                        c.如果Extra中Using Index与Using Where同时出现的话,则是利用索引查找键值的意思;
                        d.如单独出现,则是用读索引来代替读行,但不用于查找
        all             全表扫描
  • 相关阅读:
    jquery 视觉特效(幻灯片效果)
    jquery 视觉特效(图片内容滑动浏览器)
    jquery之stop()的用法
    网站图片幻灯片效果之左右箭头的制作
    数据库三范式
    jquery 视觉特效(当鼠标悬停时,显示大图)
    jQuery EasyUI 1.2.6 新特性
    VM虚拟机网络设置
    Win7:修改注册表来更改“桌面”、“我的文档”、“收藏夹”的位置
    jQuery EasyUI API 中文文档 数字滑块(Slider)
  • 原文地址:https://www.cnblogs.com/liaokaichang/p/7516080.html
Copyright © 2011-2022 走看看