MySQL 存儲過程簡單瞭解&數據庫優化簡單方式

原文地址: https://blog.csdn.net/H_Rhui/article/details/96920260css

最近看到觸發器以後,就想了解一下 存儲過程。觸發器是一種和表關聯的特殊的存儲過程。mysql

一:存儲過程定義:

MySQL 5.0 版本開始支持存儲過程。sql

存儲過程(Stored Procedure)是一種在數據庫中存儲複雜程序,以便外部程序調用的一種數據庫對象。數據庫

存儲過程是爲了完成特定功能的SQL語句集,經編譯建立並保存在數據庫中,用戶可經過指定存儲過程的名字並給定參數(須要時)來調用執行。express

存儲過程思想上很簡單,就是數據庫 SQL 語言層面的代碼封裝與重用。編程

二:存儲過程使用:

  • 存儲過程就是具備名字的一段代碼,用來完成一個特定的功能。
  • 建立的存儲過程保存在數據庫的數據字典中。

1. 語法格式:

聲明語句結束符,能夠自定義:
DELIMITER $$ 或 DELIMITER // 
 
聲明存儲過程:
CREATE PROCEDURE demo_in_parameter(IN p_in int)    
存儲過程的開始和結束符號:
BEGIN …… END
變量賦值:
SET @p_in=1
變量定義:
DECLARE l_int int unsigned default 5000000;
 
建立過程體:
create function 存儲函數名(參數)

  

存儲過程體緩存

  • 存儲過程體包含在過程調用時必須執行的語句,例如: dml、ddl 語句, if-then-else 和 while-do 語句、聲明變量的 declare 語句等
  • 過程體格式: 已 begin 開始,end 結束(可嵌套)
  •  
    BEGIN
      BEGIN
        BEGIN
          statements; 
        END
      END
    END
    

      

  • 注意:每一個嵌套塊及其中的每條語句,必須以分號結束,表示過程體結束的begin-end塊(又叫作複合語句compound statement),則不須要分號。安全

    爲語句塊貼標籤: 服務器

  • 一、加強代碼的可讀性
  • 二、在某些語句(例如:leave和iterate語句),須要用到標籤
    [begin_label:] BEGIN
      [statement_list]
    END [end_label]
    

      

例如: 網絡

label1: BEGIN
  label2: BEGIN
    label3: BEGIN
      statements; 
    END label3 ;
  END label2;
END label1

  

2. 存儲過程的參數

MySQL存儲過程的參數用在存儲過程的定義,共有三種參數類型,IN,OUT,INOUT,形式如:

CREATEPROCEDURE 存儲過程名([[IN |OUT |INOUT ] 參數名 數據類型...])
  • IN 輸入參數:表示調用者向過程傳入值(傳入值能夠是字面量或變量)
  • OUT 輸出參數:表示過程向調用者傳出值(能夠返回多個值)(傳出值只能是變量)
  • INOUT 輸入輸出參數:既表示調用者向過程傳入值,又表示過程向調用者傳出值(值只能是變量)

1)in 輸入參數

mysql> delimiter $$
mysql> create procedure in_param(in p_in int)
    -> begin
    ->   select p_in;
    ->   set p_in=2;
    ->    select P_in;
    -> end$$
mysql> delimiter ;
 
mysql> set @p_in=1;
 
mysql> call in_param(@p_in);
+------+
| p_in |
+------+
|    1 |
+------+
 
+------+
| P_in |
+------+
|    2 |
+------+
 
mysql> select @p_in;
+-------+
| @p_in |
+-------+
|     1 |
+-------+

  

以上能夠看出,p_in 在存儲過程當中被修改,但並不影響 @p_id 的值,由於前者爲局部變量、後者爲全局變量。

使用 Navicat 建立存儲過程:

  1. 新建函數,選擇過程
  2. 選擇模式,定義參數
  3. 編輯過程體;如:
     
    BEGIN
     
    SELECT p_in;
     
    SET p_in = 2;
     
    SELECT p_in;
     
    END
    

      

  4. 保存存儲過程,點擊運行按鈕運行輸入參數。或者經過  sql 命令執行存儲過程。 call in_param(1);

 

 

2) out輸出參數

mysql> delimiter //
 
mysql> create procedure out_param(out p_out int)
 
-> begin
 
-> select p_out;
 
-> set p_out=2;
 
-> select p_out;
 
-> end
 
-> //
 
mysql> delimiter ;
 
 
 
mysql> set @p_out=1;
 
 
 
mysql> call out_param(@p_out);
 
+-------+
 
| p_out |
 
+-------+
 
| NULL |
 
+-------+
 
  #由於out是向調用者輸出參數,不接收輸入的參數,因此存儲過程裏的p_out爲null
 
+-------+
 
| p_out |
 
+-------+
 
| 2 |
 
+-------+
 
 
 
mysql> select @p_out;
 
+--------+
 
| @p_out |
 
+--------+
 
| 2 |
 
+--------+
 
  #調用了out_param存儲過程,輸出參數,改變了p_out變量的值

  

 3) inout 輸入參數

mysql> delimiter $$
 
mysql> create procedure inout_param(inout p_inout int)
 
-> begin
 
-> select p_inout;
 
-> set p_inout=2;
 
-> select p_inout;
 
-> end
 
-> $$
 
mysql> delimiter ;
 
 
 
mysql> set @p_inout=1;
 
 
 
mysql> call inout_param(@p_inout);
 
+---------+
 
| p_inout |
 
+---------+
 
| 1 |
 
+---------+
 
 
 
+---------+
 
| p_inout |
 
+---------+
 
| 2 |
 
+---------+
 
 
 
mysql> select @p_inout;
 
+----------+
 
| @p_inout |
 
+----------+
 
| 2 |
 
+----------+
 
#調用了inout_param存儲過程,接受了輸入的參數,也輸出參數,改變了變量

  

注意:

一、若是過程沒有參數,也必須在過程名後面寫上小括號例:

CREATE PROCEDURE sp_name ([proc_parameter[,...]]) ……

二、確保參數的名字不等於列的名字,不然在過程體中,參數名被當作列名來處理

建議:

  • 輸入值使用in參數。
  • 返回值使用out參數。
  • inout參數就儘可能的少用。

3. 變量

1) 變量定義

局部變量聲明必定要放在存儲過程體的開始:

datatype 爲 MySQL 的數據類型,如: int, float, date,varchar(length)

DECLARE variable_name [,variable_name...] datatype [DEFAULT value]; 

例如: 

DECLARE l_int int unsigned default 4000000;
 
DECLARE l_numeric number(8,2) DEFAULT 9.95;
 
DECLARE l_date date DEFAULT '1999-12-31';
 
DECLARE l_datetime datetime DEFAULT '1999-12-31 23:59:59';
 
DECLARE l_varchar varchar(255) DEFAULT 'This will not be padded';

  

2)變量賦值

SET 變量名 = 表達式值 [,variable_name = expression ...] 

3)用戶變量

在MySQL客戶端使用用戶變量:

mysql > SELECT 'Hello World' into @x;
 
mysql > SELECT @x;
 
+-------------+
 
| @x |
 
+-------------+
 
| Hello World |
 
+-------------+
 
mysql > SET @y='Goodbye Cruel World';
 
mysql > SELECT @y;
 
+---------------------+
 
| @y |
 
+---------------------+
 
| Goodbye Cruel World |
 
+---------------------+
 
 
 
mysql > SET @z=1+2+3;
 
mysql > SELECT @z;
 
+------+
 
| @z |
 
+------+
 
| 6 |
 
+------+

  

在存儲過程當中使用用戶變量

CREATE PROCEDURE GreetWorld( ) SELECT CONCAT(@greeting,' World');
 
SET @greeting='Hello';
 
CALL GreetWorld( );
 
-- 輸出: hello World

  

 

在存儲過程間傳遞全局範圍的用戶變量

CREATE PROCEDURE p1() SET @last_procedure='p1';
 
CREATE PROCEDURE p2() SELECT CONCAT('Last procedure was ',@last_procedure);
 
CALL p1();
 
CALL p2();
 
 
 
-- 輸出 Last procedure was p1

  

注意:

  • 一、用戶變量名通常以@開頭
  • 二、濫用用戶變量會致使程序難以理解及管理

4. 存儲過程的查詢、刪除

-- 查詢存儲過程
 
show procedure status where db='test';
 
-- 刪除存儲過程
 
DROP PROCEDURE p1;
 
DROP PROCEDURE p2;

  

5.MySQL存儲過程的控制語句

1) 變量做用域

DELIMITER //
 
CREATE PROCEDURE proc3()
 
BEGIN
 
declare x1 varchar(5) default 'outer';
 
BEGIN
 
DECLARE x1 VARCHAR (5) DEFAULT 'inner' ;
 
SELECT x1 ;
 
END;
 
SELECT x1 ;
 
END;//
 
DELIMITER ;
 
 
 
CALL proc3();
 
-- 輸出 inner
 
-- 輸出 outer

  

2). 條件語句

-- 建立表用來測試
 
CREATE TABLE `t` (
 
`s` int(11) DEFAULT NULL
 
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
 
 
 
-- 初始化一條數據
 
INSERT INTO `test`.`t` (`s`) VALUES (0);
 
 
 
 
 
DELIMITER //
 
CREATE PROCEDURE proc2(IN parameter int)
 
BEGIN
 
declare var int;
 
set var=parameter+1;
 
if var=0 THEN
 
INSERT INTO t VALUES(1);
 
end if;
 
if parameter=0 then
 
update t set s=s+1;
 
else
 
update t set s=s+2;
 
end if;
 
END;//
 
DELIMITER ;
 
 
 
// 調用存儲過程
 
CALL proc2(1);
 
 
 
// 刪除存儲過程
 
drop PROCEDURE proc2;

  

 

三:初步學習總結:

存儲過程優勢:

  • 存儲過程可封裝,並隱藏複雜的商業邏輯。
  • 存儲過程能夠回傳值,並能夠接受參數。
  • 存儲過程能夠用在數據檢驗,強制實行商業邏輯等。
  • 存儲過程只在建立時編譯,之後每次執行存儲過程都不須要再從新編譯,而普通的sql語句每執行一次就編譯一次,所以使用存儲過程能夠大大提升數據庫的執行速度。
  • 存儲過程建立一次能夠屢次調用,能夠減小咱們開發人員的工做量
  • 安全性高,存儲過程能夠屏蔽對底層數據庫對象的直接訪問。
  • 提升咱們的效率,下降咱們的網絡負載(一般狀況下,複雜的業務邏輯須要執行多條sql語句,這些語句分別都須要客戶端去鏈接服務器端,這個時候就會產生大量的網絡傳輸,這個時候,結合業務,放在存儲過程當中只須要一次鏈接)
  • 安全性高,存儲過程能夠屏蔽對底層數據庫對象的直接訪問。
     

存儲過程缺點:

  • 存儲過程,每每定製化於特定的數據庫上,由於支持的編程語言不一樣。當切換到其餘廠商的數據庫系統時,須要重寫原有的存儲過程。
  • 存儲過程沒法使用 SELECT 指令來運行,由於它是子程序,與查看錶,數據表或用戶定義函數不一樣。
  • 存儲過程的性能調校與撰寫,受限於各類數據庫系統。

 

四:數據庫優化簡談

1. 查詢和定位慢查詢

查詢是否開啓了慢查詢:

show variables like '%slow%'; -- Mysql 默認是關閉的

-- 開啓慢查詢
 
set global slow_query_log=1;
 
 
 
-- 查看統計的時長
 
show variables like 'long_query_time';
 
 
 
--修改統計的時長爲一秒。 請注意,修改以後,當前會話無效,從新鏈接以後能夠看到修改效果
 
set global long_query_time=1;

  

2. 選擇合適的數據庫引擎

-- 查看當前安裝的數據庫 支持哪些 引擎
 
show engines;
 
 
 
-- 查看當前數據庫使用的哪一種引擎
 
SHOW VARIABLES LIKE 'storage_engine';

  

經常使用的存儲引擎 :Myisam   innodb(目前應該是默認使用 innodb)    memory

Myisam 存儲引擎:MyISAM基於ISAM存儲引擎,並對其進行擴展。它是在Web、數據倉儲和其餘應用環境下最常使用的存儲引擎之一。MyISAM擁有較高的插入、查詢速度,但不支持事物。
Innodb 存儲引擎:InnoDB是事務型數據庫的首選引擎,支持事務安全表(ACID),支持行鎖定和外鍵
Memory :MEMORY存儲引擎將表中的數據存儲到內存中,當咱們的數據頻繁變化的時候,並且不須要入庫,這個時候用memory存儲引擎。
 

3. 使用索引

  • 對於建立多列索引的時候(複合索引),記住,若是不是使用的第一部分就不會使用索引
  • 對於使用like語句的時候沒若是查詢是‘%aaa’ 不會使用索引,’aaa%’ 會使用索引
  • 當你的sql語句有or的時候,只要是有條件沒有使用索引,其餘條件即便帶索引也不會使用。
  • 若是列類型是字符串,那必定要在條件中講數據使用引號引發來,不然就不能使用索引
  • Mysql若是感受我遍歷整個表都比使用索引快,那麼它自動就不使用索引了

 

優化小技巧

1. 對查詢進行優化,要儘可能避免全表掃描,首先應考慮在 where 及 order by 涉及的列上創建索引。2. 應儘可能避免在 where 子句中對字段進行 null 值判斷,不然將致使引擎放棄使用索引而進行全表掃描3.  應儘可能避免在 where 子句中使用 != 或 <> 操做符,不然將引擎放棄使用索引而進行全表掃描。4.  應儘可能避免在 where 子句中使用 or 來鏈接條件,若是一個字段有索引,一個字段沒有索引,將致使引擎放棄使用索引而進行全表掃描,如select id from t where num=10 or Name = 'admin'能夠這樣查詢:select id from t where num = 10 union all select id from t where Name = 'admin'5.    select count(*) from table;這樣不帶任何條件的count會引發全表掃描,而且沒有任何業務意義,是必定要杜絕的。調優參數:6.    back_log:back_log值指出在MySQL暫時中止回答新請求以前的短期內多少個請求能夠被存在堆棧中。也就是說,若是MySql的鏈接數據達到max_connections時,新來的請求將會被存在堆棧中,以等待某一鏈接釋放資源,該堆棧的數量即back_log,若是等待鏈接的數量超過back_log,將不被授予鏈接資源。7.    wait_timeout:數據庫鏈接閒置時間,閒置鏈接會佔用內存資源。8.    max_user_connection: 最大鏈接數,默認爲0無上限,最好設一個合理上限9.    thread_concurrency:併發線程數,設爲CPU核數的兩倍10.    skip_name_resolve:禁止對外部鏈接進行DNS解析,消除DNS解析時間,但須要全部遠程主機用IP訪問11.    key_buffer_size:索引塊的緩存大小,增長會提高索引處理速度,對MyISAM表性能影響最大。對於內存4G左右,可設爲256M或384M,經過查詢show status like 'key_read%',保證key_reads / key_read_requests在0.1%如下最好12.    innodb_buffer_pool_size:緩存數據塊和索引塊,對InnoDB表性能影響最大。經過查詢show status like 'Innodb_buffer_pool_read%',保證(Innodb_buffer_pool_read_requests – Innodb_buffer_pool_reads) / Innodb_buffer_pool_read_requests越高越好13.    innodb_additional_mem_pool_size:InnoDB存儲引擎用來存放數據字典信息以及一些內部數據結構的內存空間大小,當數據庫對象很是多的時候,適當調整該參數的大小以確保全部數據都能存放在內存中提升訪問效率,當太小的時候,MySQL會記錄Warning信息到數據庫的錯誤日誌中,這時就須要該調整這個參數大小14.    innodb_log_buffer_size:InnoDB存儲引擎的事務日誌所使用的緩衝區,通常來講不建議超過32MB15.    query_cache_size:緩存MySQL中的ResultSet,也就是一條SQL語執行的結果集,因此僅僅只能針對select語句。當某個表的數據有任何任何變化,都會致使全部引用了該表的select語句在Query Cache中的緩存數據失效。因此,當咱們的數據變化很是頻繁的狀況下,使用Query Cache可能會得不償失。根據命中率(Qcache_hits/(Qcache_hits+Qcache_inserts)*100))進行調整,通常不建議太大,256MB可能已經差很少了,大型的配置型靜態數據可適當調大.能夠經過命令show status like 'Qcache_%'查看目前系統Query catch使用大小16.    read_buffer_size:MySql讀入緩衝區大小。對錶進行順序掃描的請求將分配一個讀入緩衝區,MySql會爲它分配一段內存緩衝區。若是對錶的順序掃描請求很是頻繁,能夠經過增長該變量值以及內存緩衝區大小提升其性能17.    sort_buffer_size:MySql執行排序使用的緩衝大小。若是想要增長ORDER BY的速度,首先看是否可讓MySQL使用索引而不是額外的排序階段。若是不能,能夠嘗試增長sort_buffer_size變量的大小18.    read_rnd_buffer_size:MySql的隨機讀緩衝區大小。當按任意順序讀取行時(例如,按照排序順序),將分配一個隨機讀緩存區。進行排序查詢時,MySql會首先掃描一遍該緩衝,以免磁盤搜索,提升查詢速度,若是須要排序大量數據,可適當調高該值。但MySql會爲每一個客戶鏈接發放該緩衝空間,因此應儘可能適當設置該值,以免內存開銷過大。19.    record_buffer:每一個進行一個順序掃描的線程爲其掃描的每張表分配這個大小的一個緩衝區。若是你作不少順序掃描,可能想要增長該值20.    thread_cache_size:保存當前沒有與鏈接關聯可是準備爲後面新的鏈接服務的線程,能夠快速響應鏈接的線程請求而無需建立新的21.    table_cache:相似於thread_cache_size,但用來緩存表文件,對InnoDB效果不大,主要用於MyISAM 

相關文章
相關標籤/搜索