<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一條 SQL 語句引發(fā)的思考

          共 1575字,需瀏覽 4分鐘

           ·

          2021-07-14 17:24

          大家好,我是小林。

          昨晚有位讀者問了我這個(gè)問題:

          他創(chuàng)建了一張數(shù)據(jù)庫表,表里的字段只有主鍵索引(id)和聯(lián)合索引(a,b,c),然后他執(zhí)行的 select * from t where c = 0; 這條語句發(fā)現(xiàn)走的是索引,他就感覺很困惑,困惑在于兩點(diǎn):

          • 第一點(diǎn), where c 這個(gè)條件并不符合聯(lián)合索引的最左匹配原則,怎么就查詢的時(shí)候走了索引呢?

          • 第二點(diǎn),在這個(gè)數(shù)據(jù)表加了非索引字段,執(zhí)行同樣的查詢語句后,怎么變成走的是全表掃描呢?

          我先跟大家解釋下,什么是最左匹配原則?

          這個(gè)數(shù)據(jù)庫表創(chuàng)建了(a,b,c)這個(gè)聯(lián)合索引,要能使其生效必須保證 where 條件里最左邊是 a 字段,比如以下這幾種情況:

          • where a = 0;

          • where a = 0 and b = 0;

          • where a = 0 and c = 0;

          • where a = 0 and b = 0 and c = 0;

          • where a = 0 and c = 0 and b = 0;

          而如果 where 條件里最左邊的字段不是 a 時(shí),就無法使用到聯(lián)合索引,比如以下這種情況,就是不符合最左匹配規(guī)則:

          • where b = 0;

          • where c = 0;

          • where b = 0 and c =0;

          • where c = 0 and b = 0;

          知道了聯(lián)合索引的最左匹配原則后,再來看看第一個(gè)問題。

          為什么  select * from t where c = 0; 這條不符合聯(lián)合索引的最左匹配原則的查詢語句走了索引查詢呢?

          剛開始看到這個(gè)問題的時(shí)候,我一時(shí)也想不到原因,只能大概猜測(cè)這條語句可以覆蓋索引,所以就走了索引查詢。

          今早我就發(fā)了個(gè)朋友圈,因?yàn)槲遗笥讶τ胁畈欢?1W 人,覺得朋友圈肯定有大佬能解答這個(gè)問題。

          果然朋友圈大佬真的多,一個(gè)上午就有 50 多個(gè)人留言解答了這個(gè)問題,我看完后思路也清晰了。

          我也把解答思路整理了下,這里貼出來。

          首先,這張表的字段沒有「非索引」字段,所以 select * 相當(dāng)于 select id,a,b,c,然后這個(gè)查詢的內(nèi)容和條件 都在聯(lián)合索引樹里,因?yàn)槁?lián)合索引樹的葉子節(jié)點(diǎn)包含「索引列+主鍵」,所以查聯(lián)合索引樹就能查到全部結(jié)果了,這個(gè)就是覆蓋索引。

          但是執(zhí)行計(jì)劃里的 type 是 index,這代表著是通過全掃描聯(lián)合索引樹的方式查詢到數(shù)據(jù)的,這是因?yàn)?where c 并不符合聯(lián)合索引最左匹配原則。

          那么,如果寫了個(gè)符合最左原則的 select 語句,那么 type 就是 ref,這個(gè)效率就比 index 全掃描要高一些。

          那為什么選擇全掃描聯(lián)合索引樹,而不掃描全表(聚集索引樹)呢?

          因?yàn)槁?lián)合索引樹的記錄比要小的多,而且這個(gè) select * 不用執(zhí)行回表操作,所以直接遍歷聯(lián)合索引樹要比遍歷聚集索引樹要小的多,因此 MySQL 選擇了全掃描聯(lián)合索引樹。

          再來回答第二個(gè)問題。

          為什么這個(gè)數(shù)據(jù)表加了非索引字段,執(zhí)行同樣的查詢語句后,怎么變成走的是全表掃描呢?

          因?yàn)榧恿似渌侄魏螅?code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(248, 35, 117);background: rgb(248, 248, 248);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;">select * from t where c = 0; 查詢的內(nèi)容就不能在聯(lián)合索引樹里找到了,而且條件也不符合最左匹配原則,這樣既不能覆蓋索引也不能執(zhí)行回表操作,所以這時(shí)只能通過掃描全表來查詢到所有的數(shù)據(jù)。


          好了,問題就說完了,不知道大家 get 到了嗎?

          這篇說的比較粗略,沒有詳細(xì)介紹一些索引的概念,比如聚集索引、聯(lián)合表索引、覆蓋索引、回表操作這些東西。

          可能沒有點(diǎn)索引基礎(chǔ)的同學(xué)看的有點(diǎn)懵逼,小林后面在出一篇更詳細(xì)的。

          想看的記得點(diǎn)個(gè)贊,鼓勵(lì)下我!

          瀏覽 40
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美亚洲日本韩国高清色图 | 亚洲日韩网址 | 黄色视频日韩 | re久久综合热 | 波多野吉衣208在线 |