亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

MySQL 關于查詢時掃描行數與索引的疑問

MySQL 關于查詢時掃描行數與索引的疑問

慕無忌1623718 2019-04-07 11:19:09
測試表:CREATETABLE`table_1`(`id`int(10)unsignedNOTNULLAUTO_INCREMENT,`title`textNOTNULL,`category_id`int(10)unsignedNOTNULL,PRIMARYKEY(`id`))ENGINE=InnoDB;其中id字段是自增主鍵插入30行用于測試的數據:insertintotable_1(`category_id`)values(1);insertintotable_1(`category_id`)values(1);insertintotable_1(`category_id`)values(1);insertintotable_1(`category_id`)values(2);insertintotable_1(`category_id`)values(2);insertintotable_1(`category_id`)values(2);insertintotable_1(`category_id`)values(2);insertintotable_1(`category_id`)values(2);insertintotable_1(`category_id`)values(2);insertintotable_1(`category_id`)values(2);insertintotable_1(`category_id`)values(2);insertintotable_1(`category_id`)values(2);insertintotable_1(`category_id`)values(2);insertintotable_1(`category_id`)values(2);insertintotable_1(`category_id`)values(2);insertintotable_1(`category_id`)values(2);insertintotable_1(`category_id`)values(2);insertintotable_1(`category_id`)values(2);insertintotable_1(`category_id`)values(2);insertintotable_1(`category_id`)values(2);insertintotable_1(`category_id`)values(2);insertintotable_1(`category_id`)values(3);insertintotable_1(`category_id`)values(3);insertintotable_1(`category_id`)values(3);insertintotable_1(`category_id`)values(4);insertintotable_1(`category_id`)values(4);insertintotable_1(`category_id`)values(4);insertintotable_1(`category_id`)values(5);insertintotable_1(`category_id`)values(5);insertintotable_1(`category_id`)values(5);執行查詢:mysql>explainselect*from`table_1`orderby`id`DESClimit0,5;+----+-------------+---------+-------+---------------+---------+---------+------+------+-------+|id|select_type|table|type|possible_keys|key|key_len|ref|rows|Extra|+----+-------------+---------+-------+---------------+---------+---------+------+------+-------+|1|SIMPLE|table_1|index|NULL|PRIMARY|4|NULL|5||+----+-------------+---------+-------+---------------+---------+---------+------+------+-------+1rowinset這個很好理解,因為id是主鍵,查詢中只使用了orderbyid,查詢涉及記錄行數rows5,因為limit0,5mysql>explainselect*from`table_1`where`category_id`=2orderby`id`DESClimit0,5;+----+-------------+---------+-------+---------------+---------+---------+------+------+-------------+|id|select_type|table|type|possible_keys|key|key_len|ref|rows|Extra|+----+-------------+---------+-------+---------------+---------+---------+------+------+-------------+|1|SIMPLE|table_1|index|NULL|PRIMARY|4|NULL|5|Usingwhere|+----+-------------+---------+-------+---------------+---------+---------+------+------+-------------+1rowinset這個就無法理解了,為什么使用了wherecategory_id=2,用一個非索引字段where,該查詢涉及的記錄數仍然是5?將category_id=2改為任何數字,rows都為5,實際記錄前幾條并不是category_id=2,按理應該先跳過category_id!=2的然后篩選出符合的結果返回,這樣涉及的行數應該大于5啊更無法理解的是,如果使用該表category_id建立索引,同樣該SQL執行結果:mysql>explainselect*from`table_1`where`category_id`=2orderby`id`DESClimit0,5;+----+-------------+---------+------+---------------+-------------+---------+-------+------+-------------+|id|select_type|table|type|possible_keys|key|key_len|ref|rows|Extra|+----+-------------+---------+------+---------------+-------------+---------+-------+------+-------------+|1|SIMPLE|table_1|ref|category_id|category_id|4|const|18|Usingwhere|+----+-------------+---------+------+---------------+-------------+---------+-------+------+-------------+1rowinset也就是wherecategory_id=2涉及行數成了category_id=2記錄的總數!也就是18條那么如果數據庫中有1千萬條數據,均分至category_id1-10的話,這時候需要執行:select*from`table_1`where`category_id`=2orderby`id`DESClimit0,5;是否需要建立category_id索引呢?如果建立每次都要掃描100萬條索引記錄嗎?如果不建立任何索引,該SQL是否會存在性能問題?
查看完整描述

2 回答

?
米琪卡哇伊

TA貢獻1998條經驗 獲得超6個贊

《高性能mysql》第三版p698
ROWS列
這一列是Mysql估計為了找到所需的行而要讀取的行數。
......
根據表的統計信息和索引的選用情況,這個估算值可能很不準確。
由于你的category_id沒有索引,mysql認為他可能要把每一條都遍歷一次,才可以找到,所以rows是5(因為是估計的)。
category_id要不要加索引,我覺得和你category_id的數量有關。如果category_id就只有兩條的話(比如sex性別,只有男和女),那么加索引完全是浪費資源,如果category過多,那就加上吧。
                            
查看完整回答
反對 回復 2019-04-07
?
侃侃無極

TA貢獻2051條經驗 獲得超10個贊

第一個問題為什么還是5呢,因為explain后面的sql并沒有真正執行,mysql只是根據這條sql預測的,所以這個值肯定是不準確的估計值,而此時mysql預估的值就是limit的5,最好情況5行就夠,因為sql沒有執行,mysql沒法給你預估出別的值,只能是sql里存在的值。
第二個問題category_id建立索引后預估的值變成了category_id=2的行數,這是因為mysql執行sql會按照sql中索引的順序來使用,即這條sql會使用category_id的索引,而不會使用id的索引(新版本mysql可能兩個索引都會使用),通過category_id的索引得到所有category_id=2的行后要整體進行orderby,所以預估的值就是category_id=2的的行數,因為前面說過explain不會真正執行sql,所以category_id=2的值應該是存在索引中的(猜的)。
第三個問題,通過前面說的,可以了解到,mysql不會真正掃描100萬條索引記錄的(當然如果mysql不能使用orderby的索引還是要掃描100萬條索引記錄的),你可以先不建立索引,如果性能不夠再建立索引,這要求你的mysql可以在線DDL
                            
查看完整回答
反對 回復 2019-04-07
  • 2 回答
  • 0 關注
  • 1539 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號