1. 程式人生 > 其它 >MySQL Mock大量資料做簡單的效能測試

MySQL Mock大量資料做簡單的效能測試

  上個迭代版本釋出後,生產環境業務同事反饋倉配訂單查詢的頁面載入時間過長。

  因為頁面原來是有的,這次開發是在原來基礎上改的,因此沒有額外做效能。測試環境只調用介面請求了少量資料去驗證功能。在對比該迭代新增功能後,定位到問題應該是這次新加的一些欄位獲取太慢了,當單日有數萬條資料,都分別從中臺不同介面去取數時,因為中颱介面是單個訂單查詢,而不支援批量查詢。開發同事於是用每個訂單去分別請求這些不同介面,就發生了業務反饋的問題。有中臺路由組的軌跡介面,有中臺訂單組的派前電聯介面,訂單組的訂單狀態介面,資料量大時請求過慢。

  讓開發同事寫了個定時任務,每隔15分鐘執行,將訂單向中臺發請求的結果返回的資料快取到redis裡做非同步處理,然後在從redis取數,理論上就能解決該問題。在用redisDesktopManager驗證訂單請求結果拿到了以後,自己不放心,再mock了5w條資料簡單看看頁面查詢和翻頁效能。

  下面記錄下生成資料的部分,備將來再次使用。可以利用mysql記憶體表插入速度快的特點,先利用函式和儲存過程在記憶體表中生成資料,然後再從記憶體表插入普通表中,這種方案插入資料是非常快的。

  首先copy訂單表的ddl,將ENGINE從InnoDB改成MEMORY,建一張記憶體表

 

CREATE TABLE `o_order_main_memory` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '訂單',
`order_id` varchar(50) COLLATE utf8mb4_bin DEFAULT '' COMMENT '訂單號(貨主單號)',
`waybill_no` varchar(50) COLLATE utf8mb4_bin DEFAULT '' COMMENT '運單號',
`client_id` varchar(50) COLLATE utf8mb4_bin DEFAULT '' COMMENT '客戶id',
`order_time` datetime DEFAULT NULL COMMENT '下單時間',
`order_type` varchar(10) COLLATE utf8mb4_bin DEFAULT '' COMMENT '  ',
`order_carrier` varchar(50) COLLATE utf8mb4_bin DEFAULT '' COMMENT '承運商',
`order_status` int NOT NULL DEFAULT '0' COMMENT '-1-取消,0-待攬收,14-攬件, 9-始發分撥,18-出分撥,10-簽收,,11-異常',
`sender_name` varchar(50) COLLATE utf8mb4_bin DEFAULT '' COMMENT '發件人',
`sender_phone` varchar(50) COLLATE utf8mb4_bin DEFAULT '' COMMENT '發件人手機號',
`sender_province_code` varchar(64) COLLATE utf8mb4_bin DEFAULT '' COMMENT '發貨區域省份編碼',
`sender_city_code` varchar(64) COLLATE utf8mb4_bin DEFAULT '' COMMENT '發貨區域城市編碼',
`sender_country_code` varchar(64) COLLATE utf8mb4_bin DEFAULT '' COMMENT '發貨區域區縣編碼',
`sender_address` varchar(255) COLLATE utf8mb4_bin DEFAULT '' COMMENT '發件人地址',
`receive_name` varchar(50) COLLATE utf8mb4_bin DEFAULT '' COMMENT '收件人姓名',
`receive_phone` varchar(50) COLLATE utf8mb4_bin DEFAULT '' COMMENT '收件人手機號',
`receiver_province_code` varchar(64) COLLATE utf8mb4_bin DEFAULT '' COMMENT '收貨區域省份編碼',
`receiver_city_code` varchar(64) COLLATE utf8mb4_bin DEFAULT '' COMMENT '收貨區域城市編碼',
`receiver_country_code` varchar(64) COLLATE utf8mb4_bin DEFAULT '' COMMENT '收貨區域區縣編碼',
`receive_address` varchar(255) COLLATE utf8mb4_bin DEFAULT '' COMMENT '收件人地址',
`warehouse_id` varchar(50) COLLATE utf8mb4_bin DEFAULT '' COMMENT '倉庫id',
`gmt_create` datetime DEFAULT NULL COMMENT '建立時間',
`gmt_modified` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改時間',
`user_create` bigint DEFAULT NULL COMMENT '建立人',
`user_modified` bigint DEFAULT NULL COMMENT '修改時間',
PRIMARY KEY (`id`),
UNIQUE KEY `un_order_id` (`order_id`) USING BTREE
) ENGINE=MEMORY AUTO_INCREMENT=10000 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

 ————————————————

建立生成n個隨機數字的函式

#生成n個隨機數字
DELIMITER $$
CREATE FUNCTION randNum(n int) RETURNS VARCHAR(255)
BEGIN
DECLARE chars_str varchar(20) DEFAULT '0123456789';
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()*10 ),1));
SET i = i +1;
END WHILE;
RETURN return_str;
END $$
DELIMITER;
————————————————

建立生成號碼函式

#生成隨機手機號碼
# 定義常用的手機頭 130 131 132 133 134 135 136 137 138 139 186 187 189 151 157
#SET starts = 1+floor(rand()*15)*4; 擷取字串的開始是從 1、5、9、13 ...開始的。floor(rand()*15)的取值範圍是0~14
#SET head = substring(bodys,starts,3);在字串bodys中從starts位置擷取三位

DELIMITER $$
CREATE FUNCTION generatePhone() RETURNS varchar(20)
BEGIN
DECLARE head char(3);
DECLARE phone varchar(20);
DECLARE bodys varchar(100) default "130 131 132 133 134 135 136 137 138 139 186 187 189 151 157";
DECLARE starts int;
SET starts = 1+floor(rand()*15)*4;
SET head = trim(substring(bodys,starts,3));
SET phone = trim(concat(head,randNum(8)));
RETURN phone;
END $$
DELIMITER ;
————————————————

建立隨機字串函式

#建立隨機字串和隨機時間的函式
DELIMITER $$
CREATE FUNCTION `randStr`(n INT) RETURNS varchar(255) CHARSET utf8mb4
DETERMINISTIC
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;
————————————————

建立插入記憶體表資料的儲存過程

# 建立插入記憶體表資料儲存過程 入參n是多少就插入多少條資料

DELIMITER $$
CREATE DEFINER=`dev`@`%` PROCEDURE `add_o_order_main_memory`(IN n int)
BEGIN
DECLARE i INT DEFAULT 300;
WHILE (i <= n) DO
INSERT into o_order_main_memory (id,order_id,waybill_no,client_id,order_time,order_type,order_carrier,order_status,sender_name,sender_phone,sender_province_code,sender_city_code,sender_country_code,sender_address,receive_phone,receiver_province_code,receiver_city_code,receiver_country_code,receive_address,warehouse_id,gmt_create,gmt_modified,user_create,user_modified) VALUEs (NULL,randStr(20),randNum(15),'SNERP001','2022-03-22 08:03:05','CAINIAO','YUNDA','0','張三',generatePhone(),'420000','420100','420112','上海市青浦區華新鎮111號','李四',generatePhone(),'320000','320200','320282','江蘇省鹽城市射陽縣四明鎮222號','cangku004',now(),now(),'111','111');
SET i = i + 1;
END WHILE;
END $$
DELIMITER ;


————————————————

呼叫儲存過程插入資料

#先呼叫儲存過程往記憶體表插入一萬條資料,然後再把記憶體表的一萬條資料插入普通表

CALL add_o_order_main_memory(100);

#一次性把記憶體表的資料插入到普通表,這個過程是很快的
INSERT into o_order_main SELECT * from o_order_main_memory;
#清空記憶體表資料
delete from o_order_main_memory;

————————————————

因為我沒有更改資料庫記憶體表記憶體大小,所以單次插入記憶體表一萬條資料是沒問題的,但是單次插入記憶體表十萬條資料就不行了,會報記憶體表已滿的異常。如下圖所示

 

要麼修改記憶體表儲存大小,要麼分批執行

方法一:

修改記憶體表儲存大小

SET GLOBAL tmp_table_size=2147483648;
SET GLOBAL max_heap_table_size=2147483648;

 

方法二:

呼叫我寫的另一個儲存過程 add_o_order_main_memory_to_outside

這個儲存過程就是通過不斷迴圈插入記憶體表,再從記憶體表獲取資料插入普通表,最後刪除記憶體表,以此迴圈直至迴圈結束。

#迴圈100次,每次生成10000條資料 總共生成一百萬條資料

CALL add_o_order_main_memory_to_outside(100,10000);

 

 

 

 

 

 

過程中遇到的一個問題

執行建立函式的sql語句時,提示:This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled

在MySQL中建立函式時出現這種錯誤的解決方法:
在mysql資料庫中執行以下語句 (臨時生效,重啟後失效)
    set global log_bin_trust_function_creators=TRUE;