MySQL快速創建800w條測試數據表&深度分頁


MySQL快速創建800w條測試數據表&深度分頁

 

 

汴水流,泗水流,流到瓜州古渡頭。

  吳山點點愁。

    思悠悠,恨悠悠,恨到歸時方始休。

      月明人倚樓。

 

一、數據插入思路

如果一條一條插入普通表的話,效率太低下,但內存表插入速度是很快的,可以先建立一張內存表,插入數據后,在導入到普通表中。

1、創建內存表

 1 CREATE TABLE `vote_record_memory` (  2 
 3 `id` INT (11) NOT NULL AUTO_INCREMENT,  4 
 5 `user_id` VARCHAR (20) NOT NULL,  6 
 7 `vote_id` INT (11) NOT NULL,  8 
 9 `group_id` INT (11) NOT NULL, 10 
11 `create_time` datetime NOT NULL, 12 
13 PRIMARY KEY (`id`), 14 
15 KEY `index_id` (`user_id`) USING HASH 16 
17 ) ENGINE = MEMORY AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8
View Code

2、創建普通表

普通表參數設置和內存表相同,否則從內存表往普通標導入數據會報錯。

 1 CREATE TABLE `vote_record` (  2 
 3 `id` INT (11) NOT NULL AUTO_INCREMENT,  4 
 5 `user_id` VARCHAR (20) NOT NULL,  6 
 7 `vote_id` INT (11) NOT NULL,  8 
 9 `group_id` INT (11) NOT NULL, 10 
11 `create_time` datetime NOT NULL, 12 
13 PRIMARY KEY (`id`), 14 
15 KEY `index_user_id` (`user_id`) USING HASH 16 
17 ) ENGINE = INNODB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8
View Code

3、創建存儲函數

產生偽隨機碼user_id 要用到存儲函數。

 1 CREATE FUNCTION `rand_string`(n INT) RETURNS varchar(255) CHARSET latin1  2 
 3 BEGIN
 4 
 5 DECLARE chars_str varchar(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';  6 
 7 DECLARE return_str varchar(255) DEFAULT '' ;  8 
 9 DECLARE i INT DEFAULT 0; 10 
11 WHILE i < n DO 12 
13 SET return_str = concat(return_str,substring(chars_str , FLOOR(1 + RAND()*62 ),1)); 14 
15 SET i = i +1; 16 
17 END WHILE; 18 
19 RETURN return_str; 20 
21 END
View Code

 4、創建存儲過程

存儲過程是保存起來的可以接受和返回用戶提供的參數的Transact-SQL 語句的集合,可以創建一個過程供永久使用。

 1 CREATE PROCEDURE `add_vote_memory`(IN n int)  2 
 3 BEGIN
 4 
 5 DECLARE i INT DEFAULT 1;  6 
 7 WHILE (i <= n ) DO  8 
 9 INSERT into vote_record_memory (user_id,vote_id,group_id,create_time ) VALUEs (rand_string(20),FLOOR(RAND() * 1000),FLOOR(RAND() * 100) ,now() ); 10 
11 set i=i+1; 12 
13 END WHILE; 14 
15 END
View Code

 5、調用存儲過程

call 就是調用存儲過程或者函數,這里調用存儲過程1000000次

CALL add_vote_memory(1000000)

6、導入數據

將內存表中的數據導入普通表。

INSERT into vote_record SELECT * from vote_record_memory

7、內存不足

如果報錯內存滿了,報錯信息如下:

1 CALL add_vote_memory(1000000) 2 > 1114 - The table 'vote_record_memory' is full
3 > 時間: 74.61s

則可以使用命令查看內存表和臨時表允許寫入的最大值:

show variables like '%%table_size%'

MySQL默認16M:

 修改默認內存配置:

set session tmp_table_size=1024*1024*1024; set session max_heap_table_size=1024*1024*1024; 

配置修改后,再執行上述調用存儲過程和數據導入步驟。

8、查看結果

查看記錄,是否有插入100W條數據。

select count(*) AS total from vote_record

9、插入800W條數據

測試插入800W條數據,call 調用存儲過程800W次。

 查看結果:

 800W條測試數據插入OK,想插入多少條測試數據就調用n次存儲過程,CALL add_vote_memory(n)。

二、MySQL深度分頁

所謂的深度分頁問題,涉及到mysql分頁的原理。通常情況下,mysql的分頁是這樣寫的:

select id, user_id, vote_id, group_id from vote_record limit 200, 10

SQL意思就是從vote_reccord 表里查200到210這10條數據即【201,210】,mysql會把前210條數據都查出來,拋棄前200條,返回10條。當分頁所以深度不大的時候當然沒問題,隨着分頁的深入,sql可能會變成這樣:

select id, user_id, vote_id, group_id from vote_record limit 7999900, 10

這個時候,mysql會查出來7999920條數據,拋棄前7999900條,如此大的數據量,速度一定快不起來。

那如何解決呢?一般情況下,最簡單的方式是增加一個條件,利用表的覆蓋索引來加速分頁查詢:

select id, user_id, vote_id, group_id from vote_record where id > 7999900 limit 10

我們都知道,利用了索引查詢的語句中如果只包含了那個索引列(覆蓋索引),那么這種情況會查詢很快。

因為利用索引查找有優化算法,且數據就在查詢索引上面,不用再去找相關的數據地址了,這樣節省了很多時間。上述vote_record 表的id字段是主鍵,自然就包含了默認的主鍵索引,這樣,mysql會走主鍵索引,直接連接到7999900處,然后查出來10條數據。但是這個方式需要接口的調用方配合改造,把上次查詢出來的最大id以參數的方式傳給接口提供方,會有一定溝通成本。

1、測試深度分頁

優化前,查詢耗時2.362s,隨着數據的增大耗時會更多,limit語句的查詢時間與起始記錄的位置成正比。

 優化后,耗時0.012s,性能提升了196.8倍。

 

 

 

 

汴水流,泗水流,流到瓜州古渡頭。

吳山點點愁。

思悠悠,恨悠悠,恨到歸時方始休。

月明人倚樓。

 

 

 

 


免責聲明!

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



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