一、什麼是慢日誌
慢日誌:用來記錄執行比較慢的一些sql
二、優化大致思路
- 根據慢日誌定位慢查詢sql
- 使用explain等工具分析sql
- 修改sql或者儘量讓sql走索引
三、例子詳解
環境:Navicat for MySQL,MySQL8.0+,win10
博主這裏爲了方便測試,提前插入了50萬條數據(花了挺久的,選錯引擎了,用的InnoDb,貌似用myisam會很快)下邊給出腳本內容
/*
Navicat MySQL Data Transfer
Source Server : test
Source Server Version : 80014
Source Host : localhost:3306
Source Database : mysql_study
Target Server Type : MYSQL
Target Server Version : 80014
File Encoding : 65001
Date: 2020-04-21 11:50:48
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for person_info_large
-- ----------------------------
DROP TABLE IF EXISTS `person_info_large`;
CREATE TABLE `person_info_large` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`age` int(11) NOT NULL,
PRIMARY KEY (`id`,`age`),
KEY `idx_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=501946 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Procedure structure for add_vote_memory
-- ----------------------------
DROP PROCEDURE IF EXISTS `add_vote_memory`;
DELIMITER ;;
CREATE DEFINER=`root`@`localhost` PROCEDURE `add_vote_memory`(IN `n` int)
BEGIN
DECLARE i INT DEFAULT 1;
WHILE (i <= n ) DO
INSERT into person_info_large (name,age) VALUEs (rand_string(20),FLOOR(RAND() * 100));
set i=i+1;
END WHILE;
END
;;
DELIMITER ;
-- ----------------------------
-- Function structure for rand_string
-- ----------------------------
DROP FUNCTION IF EXISTS `rand_string`;
DELIMITER ;;
CREATE DEFINER=`root`@`localhost` FUNCTION `rand_string`(`n` int) RETURNS varchar(255) CHARSET utf8
NO SQL
BEGIN
DECLARE chars_str varchar(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
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()*62 ),1));
SET i = i +1;
END WHILE;
RETURN return_str;
END
;;
DELIMITER ;
裏面有一個函數和一個存儲過程,用來插入大量數據的,覺得慢可以百度另一種引擎方法。
在插入數據之前,最好去my.ini裏面加上一句max_heap_table_size = 1024M
,避免無法存那麼多。找不到my.ini的可以百度一下。
調用存儲過程直接:CALL add_vote_memory(500000);
,時間比較久,可以耐心等待一下
我們先查詢一些變量:SHOW VARIABLES LIKE "%quer%";
,我的是已經修改好的
設置語句用SET GLOBAL name =
設置long_query_time
後不會立馬生效,需要關閉當前連接,重新進去,我們再次查詢,看是否改變,不行的話,就直接改my.ini文件進行修改這三項,修改完後記得重新啓動mysql服務。
我們寫一個查詢:SELECT name from person_info_large ORDER BY name DESC;
可以看到,查詢時間超過了1秒,我們可以查詢一下慢查詢sql:show status like '%slow_queries%';
已經記錄了一條,我們可以去慢查詢日誌看一下
裏面有慢查詢sql,以上就是定位的方法。
explain工具分析sql
只需要在sql前面加一個explain
即可,具體的explain語法可以網上查詢一下,這裏不再細說
執行沒走索引的查詢加排序:explain SELECT name from person_info_large ORDER BY name DESC;
,結果如下
可以看到出現了ALL和Using filesort字樣,一般我們都是要改sql,讓其走索引的,目前的需求只是查詢name,於是我們可以加一個普通索引:alter table person_info_large add index idx_name(name);
(注:添加索引是DDL語言,不會算成慢查詢日誌裏)執行之後,走索引查詢一次:SELECT name from person_info_large ORDER BY name DESC;
嗯,0.492秒,是的,你沒有看錯,提高了72%,雖然只是個小測試,我們繼續用explain分析一下
測試count(id)會走主鍵還是普通索引
執行explain select count(id) from person_info_large;
,結果如下:
它走的是普通索引,爲什麼呢?
- 這是因爲mysql的優化器會選擇索引並且選擇更加嚴格的索引,即數據形式簡單的索引,優化器認爲主鍵裏面存放的不僅僅是id,還有其他的數據,故,優化器選擇idx_name
但是這樣一定是最優嗎?我們對走兩個索引的耗時測試一下
- 走主鍵索引:
select count(id) from person_info_large force index(PRIMARY);
- 走普通索引:
select count(id) from person_info_large;
兩個我試了幾次,走主鍵的確快些,所以,優化器考慮的只是一部分,更多的還是要看自己實際業務中根據實際情況來優化。