MySQL函數&存儲過程 一、是什麼 二、能幹嘛

上一篇文章中說到了定位慢sql,拿到了慢sql後,我們要怎麼重現問題呢?那麼就需要造數據。函數和存儲過程就可以幫助我們造大量的數據,用來重現生產環境的問題。

一、是什麼

函數和存儲過程都是sql的集合,就是用sql寫的一段代碼。函數與存儲過程的區別就是函數有返回值,存儲過程沒有返回值。

二、能幹嘛

其實就是相當於我們java封裝的方法啦,可以實現某個功能的代碼集,可以複用,很方便。比如我現在要往一個表裏插入1000萬的數據,如果要用函數或者存儲過程來實現,該怎麼做呢?

1. 建庫建表:

create database bigData;
use bigData;

# 部門表
create table dept(
    id int unsigned primary key auto_increment,
    deptno mediumint unsigned not null default 0,
    dname varchar(20) not null default "",
    loc varchar(13) not null default ""
);

# 員工表
create table emp(
   id int unsigned primary key auto_increment,
   empno mediumint unsigned not null default 0,
   ename varchar(20) not null default "",
   job varchar(9) not null default "",
   mgr mediumint unsigned  not null default 0,
   hiredate date not null,
   sal decimal(7,2) not null,
   comm decimal(7,2) not null,
   deptno mediumint unsigned not null default 0
);

2. 設置參數:

創建函數的時候,可能會報錯:

this function has none of deterministic……

我們得開啓一個參數,首先執行如下語句可以查看該參數:

show variables like 'log_bin_trust_function_creators';

可以看到現在是off狀態的,執行以下sql將其開啓:

set global log_bin_trust_function_creators=1;

不過之前也說過,通過這種方式設置的參數,一重啓就失效了,所以可以在配置文件的[mysqld]標籤下加上這麼一行:

log_bin_trust_function_creators=1

3. 創建函數:

  • 創建一個函數,用來產生隨機字符串,當做員工編號。
delimiter $$
create function rand_string(n int) returns varchar(255)
begin
       declare chars_str varchar(100) default 'abcdefghijklmnopqrstuvwxyz';
       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() * 52), 1));
                set i = i + 1;
       end while;
       return return_str;
end $$

解釋一下這個function:

  • 首先用delimiter $$聲明瞭兩個美元符$$表示程序的結束。因爲function裏面會有很多行sql,如果還是分號表示結束的話,那可能function遇到第一個分號的時候就認爲結束了,所以這個相當重新定義結束符號。

  • 然後創建一個名爲rand_string,輸入參數爲int類型的n,返回值爲varchar類型;

  • 接着定義了一個字符串chars_str以及返回值return_str;

  • 最後循環從chars_str中截取字符設置到return_str中。

那麼如何驗證這個函數有沒有創建成功呢?

我們知道,執行:

select now() from dual;

就會顯示當前時間,是因爲MySQL自帶了now()函數,那麼如果我執行:

select rand_string(2) from dual;

會返回字符串,那說明函數創建成功了。

  • 創建一個函數,用來生成隨機數,當做部門編號:
delimiter $$
create function rand_num() returns int(5)
begin
   declare i int default 0;
   set i = floor(100 + rand() * 10);
   return i;
end $$

假如要刪除rand_num函數,那麼就是執行:

drop function rand_num;

4. 創建存儲過程:

delimiter $$
create procedure insert_emp(in start int(10), in max_num int(10))
begin
       declare i int default 0;
       set autocommit = 0;
       repeat
       set i = i + 1;
       insert into emp (empno, ename, job, mgr, hiredate, sal, comm, deptno)
       values((start + i), rand_string(6), 'salesman', 0001, curdate(), 2000, 4000, rand_num());
       until i = max_num
       end repeat;
       commit;
end $$

這個存儲過程就是往員工表插入數據,這裏關閉了自動提交,因爲存儲過程裏面也很多語句,沒執行一次就提交一次很麻煩,所以等存儲過程執行完手動提交。然後再創建往部門表插數據的存儲過程,如下:

delimiter $$
create procedure insert_dept(in start int(10), in max_num int(10))
begin
       declare i int default 0;
       set autocommit = 0;
       repeat
       set i = i + 1;
       insert into dept (deptno, dname, loc) values ((start + i), rand_string(10), rand_string(8));
       until i = max_num
       end repeat;
       commit;
end $$

5. 調用存儲過程:

調用的sql如下:

delimiter ;
call insert_dept(100, 10);

首先將結束符改回分號,然後調用兩個存儲過程,100表示編號從100開始,10表示插入10條數據。

執行結果如下:

然後再往emp表插入50萬數據:

delimiter ;
call insert_emp(100001, 500000);

執行結果:

插50萬數據22秒就搞定了,還是很快的,接下來查詢emp表的數據:

select * from emp;

查50萬數據,耗時1.39秒,如果把慢查日誌的閥值設置爲1s,那麼該sql就會被記錄到日誌中了。

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