快速生成數字輔助表

        數字輔助表只有一個整數列,包含從1到N個整數序列值,N通常很大。對MySQL來講,數字輔助表是一個強大的工具,編寫SQL語句時經常用數據表與數字輔助表做笛卡爾積來創建額外的行。建議創建一個持久的數據輔助表,並根據需要填充一定數據量的值。        實際上如何填充數字輔助表無關緊要,因爲只需要運行這個過程一次,不過還是可以對此過程進行優化。假設需要爲如下數字輔助表生成數據:

create table nums (a bigint unsigned not null primary key) engine=innodb;

方案一:平凡低效

drop procedure if exists pcreatenums;
delimiter //
create procedure pcreatenums(cnt bigint)
begin
    declare s int default 1;
    set session autocommit=0;
    while s<=cnt do
        insert into nums values(s);
        set s=s+1;
    end while;
    commit;
end;
//

        這個存儲過程沒很簡單,就是一個循環,每次插入一條數據,以生成的數據行數作爲循環次數。在我的環境中執行這個過程生成1000000行需要執行接近1分24秒。效率不高的原因在於insert語句被執行了1000000次。
 

mysql> call pcreatenums(1000000);
Query OK, 0 rows affected (1 min 24.39 sec)

方法二:高效迭代

drop procedure if exists pcreatenums;
delimiter //
create procedure pcreatenums(cnt int)
begin
    declare s int default 1;
    set session autocommit=0;
    insert into nums select s;
    while s<=cnt do
        insert into nums select a+s from nums where a+s <=cnt;
        set s=s*2;
    end while;
    commit;
end;
//

        這次執行只用了不到不到17秒。

mysql> call pcreatenums(1000000);
Query OK, 0 rows affected (16.53 sec)

        在這個存儲過程中,變量 s 保存插入nums表的行數。循環開始前先插入 1 條數據,然後當 s 小於等於所要生成的數據行數時執行循環。在每次迭代中,該過程把nums表當前所有行的值加上 s 後再插nums表中。這樣每次循環插入的行數以2的冪次方遞增,insert語句只被執行了21次,其中還包括作爲種子數據的第一次插入。因此這個過程的執行速度很快。

方法三:一次生成

set session cte_max_recursion_depth=1000000;
insert into nums 
with recursive temp (n) as (select 1 union all select n+1 from temp where n < 1000000) select n from temp;

        這種方法利用MySQL 8 提供的CTE(Common Table Expressions)功能,用遞歸一次性生成所有數據,只需要不到13秒,性能進一步提高了四分之一。

mysql> insert into nums 
    -> with recursive temp (n) as (select 1 union all select n+1 from temp where n < 1000000) select n from temp;
Query OK, 1000000 rows affected (12.28 sec)
Records: 1000000  Duplicates: 0  Warnings: 0

        CTE可以實現類似Oracle中connect by的遞歸功能,但功能更強大,能夠解決非常複雜的查詢問題。https://dev.mysql.com/doc/refman/8.0/en/with.html是MySQL官方文檔對CTE的說明。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章