數據庫之定位並優化慢查詢SQL

一、什麼是慢日誌

慢日誌:用來記錄執行比較慢的一些sql

二、優化大致思路

  1. 根據慢日誌定位慢查詢sql
  2. 使用explain等工具分析sql
  3. 修改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;
    在這裏插入圖片描述
    兩個我試了幾次,走主鍵的確快些,所以,優化器考慮的只是一部分,更多的還是要看自己實際業務中根據實際情況來優化。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章