關於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             全表掃描

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM