MYSQL調優實戰


一:基礎數據准備

DROP TABLE IF EXISTS `tbl_user`;
CREATE TABLE `tbl_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `email` varchar(20) DEFAULT NULL,
  `age` tinyint(4) DEFAULT NULL,
  `type` int(11) DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;

INSERT INTO `tbl_user` VALUES 
('1', 'admin', 'admin@126.com', '18', '1', '2018-07-09 11:08:57'), 
('2', 'mengday', 'mengday@163.com', '31', '2', '2018-07-09 11:09:00'), 
('3', 'mengdee', 'mengdee@163.com', '20', '2', '2018-07-09 11:09:04'), 
('4', 'root', 'root@163.com', '31', '1', '2018-07-09 14:36:19'), 
('5', 'zhangsan', 'zhangsan@126.com', '20', '1', '2018-07-09 14:37:28'), 
('6', 'lisi', 'lisi@gmail.com', '20', '1', '2018-07-09 14:37:31'), 
('7', 'wangwu', 'wangwu@163.com', '18', '1', '2018-07-09 14:37:34'), 
('8', 'zhaoliu', 'zhaoliu@163.com', '22', '1', '2018-07-11 18:29:24'), 
('9', 'fengqi', 'fengqi@163.com', '19', '1', '2018-07-11 18:29:32');


DROP TABLE IF EXISTS `tbl_userinfo`;
CREATE TABLE `tbl_userinfo` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `address` varchar(255) DEFAULT NULL,
  `user_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_userId` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

INSERT INTO `tbl_userinfo` VALUES 
('1', '上海市', '1'), 
('2', '北京市', '2'), 
('3', '杭州', '3'), 
('4', '深圳', '4'), 
('5', '廣州', '5'), 
('6', '海南', '6');

二:五百萬數據插入

上面插入幾條測試數據,在使用索引時還需要插入更多的數據作為測試數據,下面就通過存儲過程插入500W條數據作為測試數據

-- 修改mysql默認的結束符號,默認是分號;但是在函數和存儲過程中會使用到分號導致解析不正確
DELIMITER $$

-- 隨機生成一個指定長度的字符串
CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255) 
BEGIN 
 # 定義三個變量
 DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';
 DECLARE return_str VARCHAR(255) DEFAULT '';
 DECLARE i INT DEFAULT 0;

 WHILE i < n DO 
   SET return_str = CONCAT(return_str, SUBSTRING(chars_str, FLOOR(1+RAND()*52), 1));
   SET i = i + 1;
 END WHILE;
 RETURN return_str;
END $$

-- 創建插入的存儲過程
CREATE PROCEDURE insert_user(IN START INT(10), IN max_num INT(10))
BEGIN
    DECLARE i INT DEFAULT 0; 
    SET autocommit = 0;  
    REPEAT
        SET i = i + 1;
        INSERT INTO tbl_user VALUES ((START+i) ,rand_string(8), CONCAT(rand_string(6), '@random.com'), 1+FLOOR(RAND()*100), 3, NOW());
        UNTIL i = max_num
    END REPEAT;
   COMMIT;
END $$

-- 將命令結束符修改回來
DELIMITER ;

-- 調用存儲過程,插入500萬數據,需要等待一會時間,等待執行完成
CALL insert_user(100001,5000000);
-- Query OK, 0 rows affected (7 min 49.89 sec) 

SELECT COUNT(*) FROM tbl_user;

三:使用索引和不使用索引的比較

使用索引之前的查詢

 

 

 

 

 然后給username創建索引再次查詢(數據庫卡死了,我用sqlyog做)

創建索引用了40秒,屬實有點慢

 

 

 然后再查詢試試,基本是秒查了,效率提升很明顯

 

 

 之前再黑窗口加的索引也上去了

 

然后刪除一個索引,byusername

 

 

 

 

四:explain命令

 

 

explain參數詳解

 

 

 

 

 

 

 

 

 查看索引的使用情況:show status like 'Handler_read%'

Handler_read_key: 越高越好
Handler_read_rnd_next:越低越好

查詢優化器:

  • 重新定義表的關聯順序(優化器會根據統計信息來決定表的關聯順序)
  • 將外連接轉化成內連接(當外連接等於內連接)
  • 使用等價變換規則(如去掉1=1)
  • 優化count()、min()、max()
  • 子查詢優化
  • 提前終止查詢
  • in條件優化

mysql可以通過 EXPLAIN EXTENDED 和 SHOW WARNINGS 來查看mysql優化器改寫后的sql語句

下圖提示我們別用*查詢,應該寫具體那一列

 

 

五:走索引的情況和不走索引的情況

1. in走索引

in操作能避免則避免,若實在避免不了,需要仔細評估in后邊的集合元素數量,控制在1000個之內。

 

 

2. 范圍查詢走索引

 

 但是條件必須是一個具體的值,如果條件為 now() 當前時間,則會導致全表掃描

 

 

3. 模糊查詢只有左前綴使用索引

 

 

4. 反向條件不走索引 != 、 <> 、 NOT IN、IS NOT NULL

 

 一個優化的實例:

# 常見的對not in的優化,使用左連接加上is null的條件過濾
SELECT id, username, age FROM tbl_user WHERE id NOT IN (SELECT user_id FROM tbl_order);


SELECT u.id, u.username, u.age
FROM tbl_user u
LEFT JOIN tbl_order o ON u.id = o.user_id
WHERE o.user_id IS NULL;

5. 對條件計算(使用函數或者算數表達式)不走索引

使用函數計算不走索引,無論是對字段使用了函數還是值使用了函數都不走索引,解決辦法通過應用程序計算好,將計算的結果傳遞給sql,而不是讓數據庫去計算

 

 

 

 

6. 查詢時必須使用正確的數據類型

如果索引字段是字符串類型,那么查詢條件的值必須使用引號,否則不走索引

7. or 使用索引和不使用索引的情況

or 只有兩邊都有索引才走索引,如果都沒有或者只有一個是不走索引的

8. 用union少用or

盡量避免使用or,因為大部分or連接的兩個條件同時都進行索引的情況幾率比較小,應使用uninon代替,這樣能走索引的走索引,不能走索引的就全表掃描。

 

9. 能用union all就不用union

union all 不去重復,union去重復,union使用了臨時表,應盡量避免使用臨時表

 

10. 復合索引

對於復合索引,如果單獨使用右邊的索引字段作為條件時不走索引的。即復合索引如果不滿足最左原則leftmost不會走復合索引

暫未完成,更新還會繼續


免責聲明!

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



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