工作中遇到的99%SQL優化,這裡都能給你解決方案
前幾篇文章介紹了mysql的底層資料結構和mysql優化的神器explain。後臺有些朋友說小強只介紹概念,平時使用還是一臉懵,強烈要求小強來一篇實戰sql優化,經過週末兩天的整理和總結,sql優化實戰新鮮出爐, 大家平時學習和工作中,遇到的90% 的sql優化都會介紹到,介意篇幅過長,分成3篇文章哈。
CREATE TABLE `employees` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(24) NOT NULL DEFAULT '' COMMENT '姓名', `age` int(20) NOT NULL DEFAULT '0' COMMENT '年齡', `position` varchar(20) NOT NULL DEFAULT '' COMMENT '職位', `hire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '入職時間', PRIMARY KEY (`id`), KEY `idx_name_age_position` (`name`,`age`,`position`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='員工表'; insert into employees(name,age,position,hire_time) values('LiLei', 22, 'manager', NOW()) insert into employees(name,age,position,hire_time) values('HanMeimei', 23, 'dev', NOW()) insert into employees(name,age,position,hire_time) values('Lucy', 23, 'dev', NOW())
全值匹配
索引的欄位型別是varchar(n):2位元組儲存字串長度,如果是utf-8, 則長度是3n+2
EXPLAIN select * from employees where name='LiLei';
EXPLAIN select * from employees where name='LiLei' AND age = 22;
EXPLAIN select * from employees where name='LiLei' AND age = 22 AND position = 'manager';
最左字首法則
如果索引是多列,要最受最左字首法則。指的是查詢從索引的最左前列開始並且不跳過索引中的列。以下兩條sql根據最左字首法則,都不會走索引。
EXPLAIN select * from employees where age = 22 AND position='manager';
EXPLAIN select * from employees where position ='manager';
索引失效
不要在索引列上做任何操作(計算、函式、型別轉換),會導致索引失效而轉向全表掃描。
EXPLAIN select * from employees where name='LiLei';
EXPLAIN select * from employees where left(name, 3)='LiLei';
給hire_time增加一個普通索引:
alter table `employees` ADD INDEX `idx_hire_time`(`hire_time`) USING BTREE;
EXPLAIN select * from employees where date(hire_time) = '2019-08-25';
還原最初索引狀態
ALTER TABLE `employees` DROP INDEX `idx_hire_time`;
儲存引擎不能使用索引中範圍條件右邊的列
-- EXPLAIN SELECT * FROM employees WHERE name ='LiLei' AND age=22 AND position ='manager';
EXPLAIN SELECT * FROM employees WHERE name ='LiLei' AND age>22 AND position ='manager';
看到key_len這個索引長度是78, 也就是隻使用到了前兩個欄位name和age,postition沒有使用到索引的。
覆蓋索引
儘量使用覆蓋索引(只訪問索引的查詢(索引列包含查詢列)),減少selelct * 語句。
EXPLAIN SELECT name,age,position FROM employees WHERE name ='LiLei' AND age=22 AND position ='manager';
條件判斷
mysql在使用不等於(! = 或者 <>)的時候無法使用索引會導致全表掃描
EXPLAIN SELECT * FROM employees WHERE name !='LiLei' ;
空值判斷
is null,is not null也無法使用索引
EXPLAIN SELECT * FROM employees WHERE name is null;
like
like以萬用字元開頭(‘$abc’)mysql索引失效會變成全表掃描操作
EXPLAIN SELECT * FROM employees WHERE name LIKE '%Lei';
字串不加單引號索引失效
EXPLAIN SELECT * FROM employees WHERE name ='1000';
EXPLAIN SELECT * FROM employees WHERE name =1000;
不加單引號的字串,mysql底層會使用cust函式將其轉換為字串,此時索引失效。
or&in少使用
少用or或in,用它查詢時,mysql不一定使用索引,mysql內部優化器會根據索引比例、表大小等多個因素整體評估是否使用索引。
EXPLAIN SELECT * FROM employees WHERE name ='LiLei' or name='HanMeimei';
範圍查詢優化
給年齡新增單值索引
ALTER TABLE `employees`ADD INDEX `idx_age`(`age`) USING BTREE;
EXPLAIN select * from employees where age > 1 and age <= 2000;
沒有走索引原因:mysql內部優化器會根據檢索比例、表大小等多個因素整體評估是否使用索引。
這個例子沒有走索引可能是因為單次資料量查詢過大導致優化器最終選擇不走索引。
優化方法:可以將大的範圍拆分成多個小範圍。
還沒關注我的公眾號?
- 掃文末二維碼關注公眾號【小強的進階之路】可領取如下:
- 學習資料: 1T視訊教程:涵蓋Javaweb前後端教學視訊、機器學習/人工智慧教學視訊、Linux系統教程視訊、雅思考試視訊教程;
- 100多本書:包含C/C++、Java、Python三門程式語言的經典必看圖書、LeetCode題解大全;
- 軟體工具:幾乎包括你在程式設計道路上的可能會用到的大部分軟體;
- 專案原始碼:20個JavaWeb專案原始碼。