日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

MySQL - 索引优化案例实操

發(fā)布時間:2025/3/21 数据库 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL - 索引优化案例实操 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 生猛干貨
  • DB Version
  • Table
  • Case 1 : 聯(lián)合索引第一個字段用范圍不一定會走索引
    • 優(yōu)化一 強(qiáng)制走索引 force index(idx_name_age_position)
    • 優(yōu)化二 覆蓋索引優(yōu)化
  • Case 2 : in和or在表數(shù)據(jù)量比較大的情況會走索引,在表記錄不多的情況下會選擇全表掃描
  • Case 3 : like KK% 一般情況都會走索引
    • 特殊例子
  • 搞定MySQL


生猛干貨

帶你搞定MySQL實(shí)戰(zhàn),輕松對應(yīng)海量業(yè)務(wù)處理及高并發(fā)需求,從容應(yīng)對大場面試


DB Version

mysql> select version(); +------------+ | version() | +------------+ | 5.7.29-log | +------------+ 1 row in set

默認(rèn)隔離級別 RR 可重復(fù)讀


Table

CREATE TABLE `employees` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(24) NOT NULL DEFAULT '' COMMENT '姓名',`age` int(11) NOT NULL DEFAULT '0' COMMENT '年齡',`position` varchar(20) NOT NULL DEFAULT '' COMMENT '職位',`hire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入職時間',PRIMARY KEY (`id`),KEY `idx_name_age_position` (`name`,`age`,`position`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='員工記錄表';

重點(diǎn)

  • 主鍵id PRIMARY KEY (id)
  • 聯(lián)合索引 KEY idx_name_age_position (name,age,position) USING BTREE
  • 我們向表里寫入10萬來條數(shù)據(jù)


    Case 1 : 聯(lián)合索引第一個字段用范圍不一定會走索引

    mysql> EXPLAIN SELECT * FROM employees WHERE name > 'LiLei' AND age = 22 AND position ='manager'; +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+ | 1 | SIMPLE | employees | NULL | range | idx_name_age_position | idx_name_age_position | 74 | NULL | 1 | 5 | Using index condition | +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+ 1 row in setmysql> EXPLAIN SELECT * FROM employees WHERE name > 'Artisan' AND age = 22 AND position ='manager'; +----+-------------+-----------+------------+------+-----------------------+------+---------+------+--------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+------+-----------------------+------+---------+------+--------+----------+-------------+ | 1 | SIMPLE | employees | NULL | ALL | idx_name_age_position | NULL | NULL | NULL | 100175 | 0.5 | Using where | +----+-------------+-----------+------------+------+-----------------------+------+---------+------+--------+----------+-------------+ 1 row in setmysql>

    當(dāng)然了,也不是所有的情況都不走索引, MySQL會基于Cost選擇一個合適的 ,如果沒有走索引,可能mysql內(nèi)部可能覺得第一個字段就用范圍,結(jié)果集應(yīng)該很大,回表效率不高,還不如就全表掃描

    如果沒有走索引想要去優(yōu)化的話怎么辦呢?


    優(yōu)化一 強(qiáng)制走索引 force index(idx_name_age_position)

    mysql> EXPLAIN SELECT * FROM employees force index(idx_name_age_position) WHERE name > 'Artisan' AND age = 22 AND position ='manager'; +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+-------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+-------+----------+-----------------------+ | 1 | SIMPLE | employees | NULL | range | idx_name_age_position | idx_name_age_position | 74 | NULL | 50087 | 1 | Using index condition | +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+-------+----------+-----------------------+ 1 row in set


    優(yōu)化二 覆蓋索引優(yōu)化

    mysql> EXPLAIN SELECT name , age , position FROM employees WHERE name > 'Artisan' AND age = 22 AND position ='manager'; +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+-------+----------+--------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+-------+----------+--------------------------+ | 1 | SIMPLE | employees | NULL | range | idx_name_age_position | idx_name_age_position | 74 | NULL | 50087 | 1 | Using where; Using index | +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+-------+----------+--------------------------+ 1 row in setmysql>

    name , age , position 是聯(lián)合索引,在索引樹上,同時索引樹上的葉子節(jié)點(diǎn)還會關(guān)聯(lián)一個主鍵id , 如果查詢 * 的話,還要根據(jù)id去主鍵索引上去查找其他字段,需要回表, 如果僅查詢二級索引樹idx_name_age_position上的字段,那就無需回表操作了,效率自然高一些。


    Case 2 : in和or在表數(shù)據(jù)量比較大的情況會走索引,在表記錄不多的情況下會選擇全表掃描

    mysql> EXPLAIN SELECT * FROM employees WHERE name in ('LiLei','HanMeimei','Lucy') AND age = 22 AND position ='manager'; +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+ | 1 | SIMPLE | employees | NULL | range | idx_name_age_position | idx_name_age_position | 140 | NULL | 3 | 100 | Using index condition | +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+ 1 row in setmysql> EXPLAIN SELECT * FROM employees WHERE (name = 'LiLei' or name = 'HanMeimei') AND age = 22 AND position ='manager'; +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+ | 1 | SIMPLE | employees | NULL | range | idx_name_age_position | idx_name_age_position | 140 | NULL | 2 | 100 | Using index condition | +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+ 1 row in set

    再搞個小表 ,和 employees 一模一樣哈,連索引也得一樣,插入3條數(shù)據(jù) 。

    CREATE TABLE `employees_2` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(24) NOT NULL DEFAULT '' COMMENT '姓名',`age` int(11) NOT NULL DEFAULT '0' COMMENT '年齡',`position` varchar(20) NOT NULL DEFAULT '' COMMENT '職位',`hire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入職時間',PRIMARY KEY (`id`),KEY `idx_name_age_position` (`name`,`age`,`position`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='員工記錄表';INSERT INTO employees_2(name,age,position,hire_time) VALUES('LiLei',22,'manager',NOW()); INSERT INTO employees_2(name,age,position,hire_time) VALUES('HanMeimei', 23,'dev',NOW()); INSERT INTO employees_2(name,age,position,hire_time) VALUES('Lucy',23,'dev',NOW());

    mysql> EXPLAIN SELECT * FROM employees_2 WHERE name in ('LiLei','HanMeimei','Lucy') AND age = 22 AND position ='manager'; +----+-------------+-------------+------------+------+-----------------------+------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------------+------------+------+-----------------------+------+---------+------+------+----------+-------------+ | 1 | SIMPLE | employees_2 | NULL | ALL | idx_name_age_position | NULL | NULL | NULL | 3 | 100 | Using where | +----+-------------+-------------+------------+------+-----------------------+------+---------+------+------+----------+-------------+ 1 row in setmysql>

    為什么呢? 就幾條數(shù)據(jù)的話, 結(jié)合B+樹的結(jié)構(gòu), MySQL認(rèn)為從根節(jié)點(diǎn)開始向下找,還不如直接從葉子節(jié)點(diǎn)從頭開始掃描快呢


    Case 3 : like KK% 一般情況都會走索引

    結(jié)合索引樹 , like KK% 可以理解為就是按照 = KK 查詢

    mysql> EXPLAIN SELECT * FROM employees WHERE name like 'LiLei%' AND age = 22 AND position ='manager'; +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+ | 1 | SIMPLE | employees | NULL | range | idx_name_age_position | idx_name_age_position | 140 | NULL | 1 | 5 | Using index condition | +----+-------------+-----------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+ 1 row in setmysql> EXPLAIN SELECT * FROM employees_2 WHERE name like 'LiLei%' AND age = 22 AND position ='manager'; +----+-------------+-------------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+ | 1 | SIMPLE | employees_2 | NULL | range | idx_name_age_position | idx_name_age_position | 140 | NULL | 1 | 33.33 | Using index condition | +----+-------------+-------------+------------+-------+-----------------------+-----------------------+---------+------+------+----------+-----------------------+ 1 row in set

    原因: 索引下推 MySQL -索引下推 Index Condition Pushdown 初探


    特殊例子

    一般情況 ,但也不絕對。看下面這個例子

    假設(shè)你這個表 的name字段 是以Artisan開頭的,從Artisan1 到Artisan100000

    再去like的話 ,mysql會基于cost,自主選擇 ,比如如下走了全表掃描。


    搞定MySQL

    總結(jié)

    以上是生活随笔為你收集整理的MySQL - 索引优化案例实操的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。