2020重新出發(fā)陪蜻,MySql基礎(chǔ)邦马,MySql視圖&索引&存儲(chǔ)過程&觸發(fā)器

@[toc]

視圖是什么

視圖在數(shù)據(jù)庫(kù)中的作用類似于窗戶,用戶可以通過這個(gè)窗口看到只對(duì)自己有用的數(shù)據(jù)宴卖。既保障了數(shù)據(jù)的安全性滋将,又大大提高了查詢效率

MySQL 視圖(View)是一種虛擬存在的表症昏,同真實(shí)表一樣随闽,視圖也由列和行構(gòu)成,但視圖并不實(shí)際存在于數(shù)據(jù)庫(kù)中肝谭。行和列的數(shù)據(jù)來自于定義視圖的查詢中所使用的表掘宪,并且還是在使用視圖時(shí)動(dòng)態(tài)生成的。

數(shù)據(jù)庫(kù)中只存放了視圖的定義分苇,并沒有存放視圖中的數(shù)據(jù)添诉,這些數(shù)據(jù)都存放在定義視圖查詢所引用的真實(shí)表中。使用視圖查詢數(shù)據(jù)時(shí)医寿,數(shù)據(jù)庫(kù)會(huì)從真實(shí)表中取出對(duì)應(yīng)的數(shù)據(jù)栏赴。因此,視圖中的數(shù)據(jù)是依賴于真實(shí)表中的數(shù)據(jù)的靖秩。一旦真實(shí)表中的數(shù)據(jù)發(fā)生改變须眷,顯示在視圖中的數(shù)據(jù)也會(huì)發(fā)生改變。

視圖可以從原有的表上選取對(duì)用戶有用的信息沟突,那些對(duì)用戶沒用花颗,或者用戶沒有權(quán)限了解的信息,都可以直接屏蔽掉惠拭,作用類似于篩選扩劝。這樣做既使應(yīng)用簡(jiǎn)單化庸论,也保證了系統(tǒng)的安全。

例如棒呛,下面的數(shù)據(jù)庫(kù)中有一張公司部門表 department聂示。表中包括部門號(hào)(d_id)、部門名稱(d_name)簇秒、功能(function)和辦公地址(address)鱼喉。department 表的結(jié)構(gòu)如下:

mysql> DESC department;
+----------+-------------+------+-----+---------+-------+
| Field    | Type        | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| d_id     | int(4)      | NO   | PRI | NULL    |       |
| d_name   | varchar(20) | NO   | UNI    | NULL    |       |
| function | varchar(50) | YES  |     | NULL    |       |
| address  | varchar(50) | YES  |     | NULL    |       |
+----------+-------------+------+-----+---------+-------+
4 rows in set (0.02 sec)

還有一張員工表 worker。表中包含了員工的工作號(hào)(num)趋观、部門號(hào)(d_id)扛禽、姓名(name)、性別(sex)皱坛、出生日期(birthday)和家庭住址(homeaddress)编曼。worker 表的結(jié)構(gòu)如下:

mysql> DESC worker;
+-------------+-------------+------+-----+---------+-------+
| Field       | Type        | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+-------+
| num         | int(10)     | NO   | PRI | NULL    |       |
| d_id        | int(4)      | YES  |MUL     | NULL    |       |
| name        | varchar(20) | NO   |     | NULL    |       |
| sex         | varchar(4)  | NO   |     | NULL    |       |
| birthday    | datetime    | YES  |     | NULL    |       |
| homeaddress | varchar(50) | YES  |     | NULL    |       |
+-------------+-------------+------+-----+---------+-------+
6 rows in set (0.01 sec)

由于各部門領(lǐng)導(dǎo)的權(quán)力范圍不同,因此麸恍,各部門的領(lǐng)導(dǎo)只能看到該部門的員工信息灵巧;而且,領(lǐng)導(dǎo)可能不關(guān)心員工的生日和家庭住址抹沪。為了達(dá)到這個(gè)目的刻肄,可以為各部門的領(lǐng)導(dǎo)建立一個(gè)視圖,通過該視圖融欧,領(lǐng)導(dǎo)只能看到本部門員工的指定信息敏弃。

  • 例如,為生產(chǎn)部門建立一個(gè)名為 product view 的視圖噪馏。通過視圖 product view麦到,生產(chǎn)部門的領(lǐng)導(dǎo)只能看到生產(chǎn)部門員工的工作號(hào)、姓名和性別等信息欠肾。這些 department 表的信息和 worker 表的信息依然存在于各自的表中瓶颠,而視圖 product_view 中不保存任何數(shù)據(jù)信息。當(dāng) department 表和 worker 表的信息發(fā)生改變時(shí)刺桃,視圖 product_view 顯示的信息也會(huì)發(fā)生相應(yīng)的變化粹淋。

技巧:如果經(jīng)常需要從多個(gè)表查詢指定字段的數(shù)據(jù),可以在這些表上建立一個(gè)視圖瑟慈,通過這個(gè)視圖顯示這些字段的數(shù)據(jù)桃移。

MySQL 的視圖不支持輸入?yún)?shù)的功能,因此交互性上還有欠缺葛碧。但對(duì)于變化不是很大的操作借杰,使用視圖可以很大程度上簡(jiǎn)化用戶的操作。

視圖并不同于數(shù)據(jù)表进泼,它們的區(qū)別在于以下幾點(diǎn):

  • 視圖不是數(shù)據(jù)庫(kù)中真實(shí)的表蔗衡,而是一張?zhí)摂M表纤虽,其結(jié)構(gòu)和數(shù)據(jù)是建立在對(duì)數(shù)據(jù)中真實(shí)表的查詢基礎(chǔ)上的。
  • 存儲(chǔ)在數(shù)據(jù)庫(kù)中的查詢操作 SQL 語(yǔ)句定義了視圖的內(nèi)容粘都,列數(shù)據(jù)和行數(shù)據(jù)來自于視圖查詢所引用的實(shí)際表廓推,引用視圖時(shí)動(dòng)態(tài)生成這些數(shù)據(jù)刷袍。
  • 視圖沒有實(shí)際的物理記錄翩隧,不是以數(shù)據(jù)集的形式存儲(chǔ)在數(shù)據(jù)庫(kù)中的,它所對(duì)應(yīng)的數(shù)據(jù)實(shí)際上是存儲(chǔ)在視圖所引用的真實(shí)表中的呻纹。
  • 視圖是數(shù)據(jù)的窗口堆生,而表是內(nèi)容。表是實(shí)際數(shù)據(jù)的存放單位雷酪,而視圖只是以不同的顯示方式展示數(shù)據(jù)淑仆,其數(shù)據(jù)來源還是實(shí)際表。
  • 視圖是查看數(shù)據(jù)表的一種方法哥力,可以查詢數(shù)據(jù)表中某些字段構(gòu)成的數(shù)據(jù)蔗怠,只是一些 SQL 語(yǔ)句的集合。從安全的角度來看吩跋,視圖的數(shù)據(jù)安全性更高寞射,使用視圖的用戶不接觸數(shù)據(jù)表,不知道表結(jié)構(gòu)见坑。
  • 視圖的建立和刪除只影響視圖本身旷档,不影響對(duì)應(yīng)的基本表聘芜。

視圖的優(yōu)點(diǎn)

視圖與表在本質(zhì)上雖然不相同,但視圖經(jīng)過定義以后侵浸,結(jié)構(gòu)形式和表一樣,可以進(jìn)行查詢氛谜、修改掏觉、更新和刪除等操作。同時(shí)值漫,視圖具有如下優(yōu)點(diǎn):

1) 定制用戶數(shù)據(jù)澳腹,聚焦特定的數(shù)據(jù)

在實(shí)際的應(yīng)用過程中,不同的用戶可能對(duì)不同的數(shù)據(jù)有不同的要求惭嚣。

例如遵湖,當(dāng)數(shù)據(jù)庫(kù)同時(shí)存在時(shí),如學(xué)生基本信息表晚吞、課程表和教師信息表等多種表同時(shí)存在時(shí)延旧,可以根據(jù)需求讓不同的用戶使用各自的數(shù)據(jù)。學(xué)生查看修改自己基本信息的視圖槽地,安排課程人員查看修改課程表和教師信息的視圖迁沫,教師查看學(xué)生信息和課程信息表的視圖芦瘾。

2) 簡(jiǎn)化數(shù)據(jù)操作

在使用查詢時(shí),很多時(shí)候要使用聚合函數(shù)集畅,同時(shí)還要顯示其他字段的信息近弟,可能還需要關(guān)聯(lián)到其他表,語(yǔ)句可能會(huì)很長(zhǎng)挺智,如果這個(gè)動(dòng)作頻繁發(fā)生的話祷愉,可以創(chuàng)建視圖來簡(jiǎn)化操作。

3) 提高數(shù)據(jù)的安全性

視圖是虛擬的赦颇,物理上是不存在的二鳄。可以只授予用戶視圖的權(quán)限媒怯,而不具體指定使用表的權(quán)限订讼,來保護(hù)基礎(chǔ)數(shù)據(jù)的安全。

4) 共享所需數(shù)據(jù)

通過使用視圖扇苞,每個(gè)用戶不必都定義和存儲(chǔ)自己所需的數(shù)據(jù)欺殿,可以共享數(shù)據(jù)庫(kù)中的數(shù)據(jù),同樣的數(shù)據(jù)只需要存儲(chǔ)一次鳖敷。

5) 更改數(shù)據(jù)格式

通過使用視圖脖苏,可以重新格式化檢索出的數(shù)據(jù),并組織輸出到其他應(yīng)用程序中哄陶。

6) 重用 SQL 語(yǔ)句

視圖提供的是對(duì)查詢操作的封裝帆阳,本身不包含數(shù)據(jù),所呈現(xiàn)的數(shù)據(jù)是根據(jù)視圖定義從基礎(chǔ)表中檢索出來的屋吨,如果基礎(chǔ)表的數(shù)據(jù)新增或刪除蜒谤,視圖呈現(xiàn)的也是更新后的數(shù)據(jù)。視圖定義后至扰,編寫完所需的查詢鳍徽,可以方便地重用該視圖。

要注意區(qū)別視圖和數(shù)據(jù)表的本質(zhì)敢课,即視圖是基于真實(shí)表的一張?zhí)摂M的表阶祭,其數(shù)據(jù)來源均建立在真實(shí)表的基礎(chǔ)上。

使用視圖的時(shí)候直秆,還應(yīng)該注意以下幾點(diǎn):

  • 創(chuàng)建視圖需要足夠的訪問權(quán)限濒募。
  • 創(chuàng)建視圖的數(shù)目沒有限制。
  • 視圖可以嵌套圾结,即從其他視圖中檢索數(shù)據(jù)的查詢來創(chuàng)建視圖瑰剃。
  • 視圖不能索引,也不能有關(guān)聯(lián)的觸發(fā)器筝野、默認(rèn)值或規(guī)則晌姚。
  • 視圖可以和表一起使用粤剧。
  • 視圖不包含數(shù)據(jù),所以每次使用視圖時(shí)挥唠,都必須執(zhí)行查詢中所需的任何一個(gè)檢索操作抵恋。如果用多個(gè)連接和過濾條件創(chuàng)建了復(fù)雜的視圖或嵌套了視圖,可能會(huì)發(fā)現(xiàn)系統(tǒng)運(yùn)行性能下降得十分嚴(yán)重宝磨。因此弧关,在部署大量視圖應(yīng)用時(shí),應(yīng)該進(jìn)行系統(tǒng)測(cè)試懊烤。

提示:ORDER BY 子句可以用在視圖中梯醒,但若該視圖檢索數(shù)據(jù)的 SELECT 語(yǔ)句中也含有 ORDER BY 子句,則該視圖中的 ORDER BY 子句將被覆蓋腌紧。

MySQL創(chuàng)建視圖

創(chuàng)建視圖是指在已經(jīng)存在的 MySQL 數(shù)據(jù)庫(kù)表上建立視圖。視圖可以建立在一張表中畜隶,也可以建立在多張表中壁肋。

基本語(yǔ)法

可以使用 CREATE VIEW 語(yǔ)句來創(chuàng)建視圖。

語(yǔ)法格式如下:

CREATE VIEW <視圖名> AS <SELECT語(yǔ)句>

語(yǔ)法說明如下籽慢。

  • <視圖名>:指定視圖的名稱浸遗。該名稱在數(shù)據(jù)庫(kù)中必須是唯一的,不能與其他表或視圖同名箱亿。
  • <SELECT語(yǔ)句>:指定創(chuàng)建視圖的 SELECT 語(yǔ)句跛锌,可用于查詢多個(gè)基礎(chǔ)表或源視圖。

對(duì)于創(chuàng)建視圖中的 SELECT 語(yǔ)句的指定存在以下限制:

  • 用戶除了擁有 CREATE VIEW 權(quán)限外届惋,還具有操作中涉及的基礎(chǔ)表和其他視圖的相關(guān)權(quán)限髓帽。
  • SELECT 語(yǔ)句不能引用系統(tǒng)或用戶變量。
  • SELECT 語(yǔ)句不能包含 FROM 子句中的子查詢脑豹。
  • SELECT 語(yǔ)句不能引用預(yù)處理語(yǔ)句參數(shù)郑藏。

視圖定義中引用的表或視圖必須存在。但是瘩欺,創(chuàng)建完視圖后必盖,可以刪除定義引用的表或視圖【愣觯可使用 CHECK TABLE 語(yǔ)句檢查視圖定義是否存在這類問題歌粥。

視圖定義中允許使用 ORDER BY 語(yǔ)句,但是若從特定視圖進(jìn)行選擇拍埠,而該視圖使用了自己的 ORDER BY 語(yǔ)句失驶,則視圖定義中的 ORDER BY 將被忽略。

視圖定義中不能引用 TEMPORARY 表(臨時(shí)表)械拍,不能創(chuàng)建 TEMPORARY 視圖突勇。

WITH CHECK OPTION 的意思是装盯,修改視圖時(shí),檢查插入的數(shù)據(jù)是否符合 WHERE 設(shè)置的條件甲馋。

查詢視圖

視圖一經(jīng)定義之后埂奈,就可以如同查詢數(shù)據(jù)表一樣,使用 SELECT 語(yǔ)句查詢視圖中的數(shù)據(jù)定躏,語(yǔ)法和查詢基礎(chǔ)表的數(shù)據(jù)一樣账磺。

視圖用于查詢主要應(yīng)用在以下幾個(gè)方面:

  • 使用視圖重新格式化檢索出的數(shù)據(jù)。
  • 使用視圖簡(jiǎn)化復(fù)雜的表連接痊远。
  • 使用視圖過濾數(shù)據(jù)垮抗。

DESCRIBE 可以用來查看視圖,語(yǔ)法如下:

DESCRIBE 視圖名碧聪;

注意:DESCRIBE 一般情況下可以簡(jiǎn)寫成 DESC冒版,輸入這個(gè)命令的執(zhí)行結(jié)果和輸入 DESCRIBE 是一樣的。

MySQL查看視圖

創(chuàng)建好視圖后逞姿,可以通過查看視圖的語(yǔ)句來查看視圖的字段信息以及詳細(xì)信息辞嗡。

查看視圖的字段信息

查看視圖的字段信息與查看數(shù)據(jù)表的字段信息一樣,都是使用 DESCRIBE 關(guān)鍵字來查看的滞造。具體語(yǔ)法如下:

DESCRIBE 視圖名;

或簡(jiǎn)寫成:

DESC 視圖名;

查看視圖的字段內(nèi)容與查看表的字段內(nèi)容顯示的格式是相同的续室。因此,更能說明視圖實(shí)際上也是一張數(shù)據(jù)表了谒养,不同的是挺狰,視圖中的數(shù)據(jù)都來自于數(shù)據(jù)庫(kù)中已經(jīng)存在的表。

查看視圖的詳細(xì)信息

在 MySQL 中买窟,SHOW CREATE VIEW 語(yǔ)句可以查看視圖的詳細(xì)定義丰泊。其語(yǔ)法如下所示:

SHOW CREATE VIEW 視圖名;

所有視圖的定義都是存儲(chǔ)在 information_schema 數(shù)據(jù)庫(kù)下的 views 表中,也可以在這個(gè)表中查看所有視圖的詳細(xì)信息蔑祟,SQL 語(yǔ)句如下:

SELECT * FROM information_schema.views;

不過趁耗,通常情況下都是使用 SHOW CREATE VIEW 語(yǔ)句。

MySQL修改視圖

修改視圖是指修改 MySQL 數(shù)據(jù)庫(kù)中存在的視圖疆虚,當(dāng)基本表的某些字段發(fā)生變化時(shí)苛败,可以通過修改視圖來保持與基本表的一致性。

基本語(yǔ)法

可以使用 ALTER VIEW 語(yǔ)句來對(duì)已有的視圖進(jìn)行修改径簿。

語(yǔ)法格式如下:

ALTER VIEW <視圖名> AS <SELECT語(yǔ)句>

語(yǔ)法說明如下:

  • <視圖名>:指定視圖的名稱罢屈。該名稱在數(shù)據(jù)庫(kù)中必須是唯一的,不能與其他表或視圖同名篇亭。
  • <SELECT 語(yǔ)句>:指定創(chuàng)建視圖的 SELECT 語(yǔ)句缠捌,可用于查詢多個(gè)基礎(chǔ)表或源視圖。

需要注意的是,對(duì)于 ALTER VIEW 語(yǔ)句的使用曼月,需要用戶具有針對(duì)視圖的 CREATE VIEW 和 DROP 權(quán)限谊却,以及由 SELECT 語(yǔ)句選擇的每一列上的某些權(quán)限。

修改視圖的定義哑芹,除了可以通過 ALTER VIEW 外炎辨,也可以使用 DROP VIEW 語(yǔ)句先刪除視圖,再使用 CREATE VIEW 語(yǔ)句來實(shí)現(xiàn)聪姿。

修改視圖內(nèi)容

視圖是一個(gè)虛擬表碴萧,實(shí)際的數(shù)據(jù)來自于基本表,所以通過插入末购、修改和刪除操作更新視圖中的數(shù)據(jù)破喻,實(shí)質(zhì)上是在更新視圖所引用的基本表的數(shù)據(jù)。

注意:對(duì)視圖的修改就是對(duì)基本表的修改盟榴,因此在修改時(shí)曹质,要滿足基本表的數(shù)據(jù)定義。

某些視圖是可更新的曹货。也就是說咆繁,可以使用 UPDATE、DELETE 或 INSERT 等語(yǔ)句更新基本表的內(nèi)容顶籽。對(duì)于可更新的視圖,視圖中的行和基本表的行之間必須具有一對(duì)一的關(guān)系银觅。

還有一些特定的其他結(jié)構(gòu)礼饱,這些結(jié)構(gòu)會(huì)使得視圖不可更新。更具體地講究驴,如果視圖包含以下結(jié)構(gòu)中的任何一種镊绪,它就是不可更新的:

  • 聚合函數(shù) SUM()、MIN()洒忧、MAX()蝴韭、COUNT() 等。
  • DISTINCT 關(guān)鍵字熙侍。
  • GROUP BY 子句榄鉴。
  • HAVING 子句。
  • UNION 或 UNION ALL 運(yùn)算符蛉抓。
  • 位于選擇列表中的子查詢庆尘。
  • FROM 子句中的不可更新視圖或包含多個(gè)表。
  • WHERE 子句中的子查詢巷送,引用 FROM 子句中的表驶忌。
  • ALGORITHM 選項(xiàng)為 TEMPTABLE(使用臨時(shí)表總會(huì)使視圖成為不可更新的)的時(shí)候。

MySQL刪除視圖

刪除視圖是指刪除 MySQL 數(shù)據(jù)庫(kù)中已存在的視圖笑跛。刪除視圖時(shí)付魔,只能刪除視圖的定義聊品,不會(huì)刪除數(shù)據(jù)。

基本語(yǔ)法

可以使用 DROP VIEW 語(yǔ)句來刪除視圖几苍。

語(yǔ)法格式如下:

DROP VIEW <視圖名1> [ , <視圖名2> …]

其中:<視圖名>指定要?jiǎng)h除的視圖名翻屈。DROP VIEW 語(yǔ)句可以一次刪除多個(gè)視圖,但是必須在每個(gè)視圖上擁有 DROP 權(quán)限擦剑。

索引是什么

索引是一種特殊的數(shù)據(jù)庫(kù)結(jié)構(gòu)妖胀,由數(shù)據(jù)表中的一列或多列組合而成,可以用來快速查詢數(shù)據(jù)表中有某一特定值的記錄惠勒。

通過索引赚抡,查詢數(shù)據(jù)時(shí)不用讀完記錄的所有信息,而只是查詢索引列纠屋。否則涂臣,數(shù)據(jù)庫(kù)系統(tǒng)將讀取每條記錄的所有信息進(jìn)行匹配。

可以把索引比作新華字典的音序表售担。例如赁遗,要查“庫(kù)”字,如果不使用音序族铆,就需要從字典的 400 頁(yè)中逐頁(yè)來找岩四。但是,如果提取拼音出來哥攘,構(gòu)成音序表剖煌,就只需要從 10 多頁(yè)的音序表中直接查找。這樣就可以大大節(jié)省時(shí)間逝淹。

因此耕姊,使用索引可以很大程度上提高數(shù)據(jù)庫(kù)的查詢速度,還有效的提高了數(shù)據(jù)庫(kù)系統(tǒng)的性能栅葡。

為什么要使用索引

索引就是根據(jù)表中的一列或若干列按照一定順序建立的列值與記錄行之間的對(duì)應(yīng)關(guān)系表茉兰,實(shí)質(zhì)上是一張描述索引列的列值與原表中記錄行之間一 一對(duì)應(yīng)關(guān)系的有序表。

索引是 MySQL 中十分重要的數(shù)據(jù)庫(kù)對(duì)象欣簇,是數(shù)據(jù)庫(kù)性能調(diào)優(yōu)技術(shù)的基礎(chǔ)规脸,常用于實(shí)現(xiàn)數(shù)據(jù)的快速檢索。

在 MySQL 中醉蚁,通常有以下兩種方式訪問數(shù)據(jù)庫(kù)表的行數(shù)據(jù):

順序訪問

順序訪問是在表中實(shí)行全表掃描燃辖,從頭到尾逐行遍歷,直到在無(wú)序的行數(shù)據(jù)中找到符合條件的目標(biāo)數(shù)據(jù)网棍。

順序訪問實(shí)現(xiàn)比較簡(jiǎn)單黔龟,但是當(dāng)表中有大量數(shù)據(jù)的時(shí)候,效率非常低下。例如氏身,在幾千萬(wàn)條數(shù)據(jù)中查找少量的數(shù)據(jù)時(shí)巍棱,使用順序訪問方式將會(huì)遍歷所有的數(shù)據(jù),花費(fèi)大量的時(shí)間蛋欣,顯然會(huì)影響數(shù)據(jù)庫(kù)的處理性能航徙。

索引訪問

索引訪問是通過遍歷索引來直接訪問表中記錄行的方式。

使用這種方式的前提是對(duì)表建立一個(gè)索引陷虎,在列上創(chuàng)建了索引之后到踏,查找數(shù)據(jù)時(shí)可以直接根據(jù)該列上的索引找到對(duì)應(yīng)記錄行的位置,從而快捷地查找到數(shù)據(jù)尚猿。索引存儲(chǔ)了指定列數(shù)據(jù)值的指針窝稿,根據(jù)指定的排序順序?qū)@些指針排序。

  • 例如凿掂,在學(xué)生基本信息表 tb_students 中伴榔,如果基于 student_id 建立了索引,系統(tǒng)就建立了一張索引列到實(shí)際記錄的映射表庄萎。當(dāng)用戶需要查找 student_id 為 12022 的數(shù)據(jù)的時(shí)候踪少,系統(tǒng)先在 student_id 索引上找到該記錄,然后通過映射表直接找到數(shù)據(jù)行糠涛,并且返回該行數(shù)據(jù)援奢。因?yàn)閽呙杷饕乃俣纫话氵h(yuǎn)遠(yuǎn)大于掃描實(shí)際數(shù)據(jù)行的速度寒砖,所以采用索引的方式可以大大提高數(shù)據(jù)庫(kù)的工作效率自沧。

簡(jiǎn)而言之,不使用索引廊酣,MySQL 就必須從第一條記錄開始讀完整個(gè)表锉罐,直到找出相關(guān)的行。表越大绕娘,查詢數(shù)據(jù)所花費(fèi)的時(shí)間就越多脓规。如果表中查詢的列有一個(gè)索引,MySQL 就能快速到達(dá)一個(gè)位置去搜索數(shù)據(jù)文件险领,而不必查看所有數(shù)據(jù)侨舆,這樣將會(huì)節(jié)省很大一部分時(shí)間。

索引的優(yōu)缺點(diǎn)

索引有其明顯的優(yōu)勢(shì)绢陌,也有其不可避免的缺點(diǎn)挨下。

優(yōu)點(diǎn)

索引的優(yōu)點(diǎn)如下:

  • 通過創(chuàng)建唯一索引可以保證數(shù)據(jù)庫(kù)表中每一行數(shù)據(jù)的唯一性。
  • 可以給所有的 MySQL 列類型設(shè)置索引脐湾。
  • 可以大大加快數(shù)據(jù)的查詢速度臭笆,這是使用索引最主要的原因。
  • 在實(shí)現(xiàn)數(shù)據(jù)的參考完整性方面可以加速表與表之間的連接。
  • 在使用分組和排序子句進(jìn)行數(shù)據(jù)查詢時(shí)也可以顯著減少查詢中分組和排序的時(shí)間

缺點(diǎn)

增加索引也有許多不利的方面愁铺,主要如下:

  • 創(chuàng)建和維護(hù)索引組要耗費(fèi)時(shí)間鹰霍,并且隨著數(shù)據(jù)量的增加所耗費(fèi)的時(shí)間也會(huì)增加。
  • 索引需要占磁盤空間茵乱,除了數(shù)據(jù)表占數(shù)據(jù)空間以外茂洒,每一個(gè)索引還要占一定的物理空間。如果有大量的索引瓶竭,索引文件可能比數(shù)據(jù)文件更快達(dá)到最大文件尺寸督勺。
  • 當(dāng)對(duì)表中的數(shù)據(jù)進(jìn)行增加、刪除和修改的時(shí)候斤贰,索引也要?jiǎng)討B(tài)維護(hù)智哀,這樣就降低了數(shù)據(jù)的維護(hù)速度。

使用索引時(shí)腋舌,需要綜合考慮索引的優(yōu)點(diǎn)和缺點(diǎn)盏触。

索引可以提高查詢速度,但是會(huì)影響插入記錄的速度块饺。因?yàn)樵薇纾蛴兴饕谋碇胁迦胗涗洉r(shí),數(shù)據(jù)庫(kù)系統(tǒng)會(huì)按照索引進(jìn)行排序授艰,這樣就降低了插入記錄的速度辨嗽,插入大量記錄時(shí)的速度影響會(huì)更加明顯。

MySQL索引類型詳解

索引的類型和存儲(chǔ)引擎有關(guān)淮腾,每種存儲(chǔ)引擎所支持的索引類型不一定完全相同糟需。MySQL 索引可以從存儲(chǔ)方式、邏輯角度和實(shí)際使用的角度來進(jìn)行分類谷朝。

存儲(chǔ)方式區(qū)分

根據(jù)存儲(chǔ)方式的不同洲押,MySQL 中常用的索引在物理上分為 B-樹索引和 HASH 索引兩類,兩種不同類型的索引各有其不同的適用范圍圆凰。

B-樹索引

B-樹索引又稱為 BTREE 索引杈帐,目前大部分的索引都是采用 B-樹索引來存儲(chǔ)的。

B-樹索引是一個(gè)典型的數(shù)據(jù)結(jié)構(gòu)专钉,其包含的組件主要有以下幾個(gè):

  • 葉子節(jié)點(diǎn):包含的條目直接指向表里的數(shù)據(jù)行挑童。葉子節(jié)點(diǎn)之間彼此相連,一個(gè)葉子節(jié)點(diǎn)有一個(gè)指向下一個(gè)葉子節(jié)點(diǎn)的指針跃须。
  • 分支節(jié)點(diǎn):包含的條目指向索引里其他的分支節(jié)點(diǎn)或者葉子節(jié)點(diǎn)站叼。
  • 根節(jié)點(diǎn):一個(gè) B-樹索引只有一個(gè)根節(jié)點(diǎn),實(shí)際上就是位于樹的最頂端的分支節(jié)點(diǎn)尽楔。

基于這種樹形數(shù)據(jù)結(jié)構(gòu)投储,表中的每一行都會(huì)在索引上有一個(gè)對(duì)應(yīng)值。因此翔试,在表中進(jìn)行數(shù)據(jù)查詢時(shí)轻要,可以根據(jù)索引值一步一步定位到數(shù)據(jù)所在的行。

B-樹索引可以進(jìn)行全鍵值垦缅、鍵值范圍和鍵值前綴查詢冲泥,也可以對(duì)查詢結(jié)果進(jìn)行 ORDER BY 排序。但 B-樹索引必須遵循左邊前綴原則壁涎,要考慮以下幾點(diǎn)約束:

  • 查詢必須從索引的最左邊的列開始凡恍。
  • 查詢不能跳過某一索引列,必須按照從左到右的順序進(jìn)行匹配怔球。
  • 存儲(chǔ)引擎不能使用索引中范圍條件右邊的列嚼酝。

哈希索引

哈希(Hash)一般翻譯為“散列”,也有直接音譯成“哈暇固常”的闽巩,就是把任意長(zhǎng)度的輸入(又叫作預(yù)映射,pre-image)通過散列算法變換成固定長(zhǎng)度的輸出担汤,該輸出就是散列值涎跨。

哈希索引也稱為散列索引或 HASH 索引。MySQL 目前僅有 MEMORY 存儲(chǔ)引擎和 HEAP 存儲(chǔ)引擎支持這類索引崭歧。其中隅很,MEMORY 存儲(chǔ)引擎可以支持 B-樹索引和 HASH 索引,且將 HASH 當(dāng)成默認(rèn)索引率碾。

HASH 索引不是基于樹形的數(shù)據(jù)結(jié)構(gòu)查找數(shù)據(jù)叔营,而是根據(jù)索引列對(duì)應(yīng)的哈希值的方法獲取表的記錄行。哈希索引的最大特點(diǎn)是訪問速度快所宰,但也存在下面的一些缺點(diǎn):

  • MySQL 需要讀取表中索引列的值來參與散列計(jì)算绒尊,散列計(jì)算是一個(gè)比較耗時(shí)的操作。也就是說仔粥,相對(duì)于 B-樹索引來說垒酬,建立哈希索引會(huì)耗費(fèi)更多的時(shí)間。
  • 不能使用 HASH 索引排序件炉。
  • HASH 索引只支持等值比較,如“=”“IN()”或“<=>”矮湘。
  • HASH 索引不支持鍵的部分匹配斟冕,因?yàn)樵谟?jì)算 HASH 值的時(shí)候是通過整個(gè)索引值來計(jì)算的。

邏輯區(qū)分

根據(jù)索引的具體用途缅阳,MySQL 中的索引在邏輯上分為以下 5 類:

普通索引

普通索引是 MySQL 中最基本的索引類型磕蛇,它沒有任何限制景描,唯一任務(wù)就是加快系統(tǒng)對(duì)數(shù)據(jù)的訪問速度。

普通索引允許在定義索引的列中插入重復(fù)值和空值秀撇。

創(chuàng)建普通索引時(shí)超棺,通常使用的關(guān)鍵字是 INDEX 或 KEY。

唯一索引

唯一索引與普通索引類似呵燕,不同的是創(chuàng)建唯一性索引的目的不是為了提高訪問速度棠绘,而是為了避免數(shù)據(jù)出現(xiàn)重復(fù)。

唯一索引列的值必須唯一再扭,允許有空值氧苍。如果是組合索引,則列值的組合必須唯一泛范。

創(chuàng)建唯一索引通常使用 UNIQUE 關(guān)鍵字让虐。

主鍵索引

顧名思義,主鍵索引就是專門為主鍵字段創(chuàng)建的索引罢荡,也屬于索引的一種赡突。

主鍵索引是一種特殊的唯一索引,不允許值重復(fù)或者值為空区赵。

創(chuàng)建主鍵索引通常使用 PRIMARY KEY 關(guān)鍵字惭缰。不能使用 CREATE INDEX 語(yǔ)句創(chuàng)建主鍵索引。

空間索引

空間索引是對(duì)空間數(shù)據(jù)類型的字段建立的索引惧笛,使用 SPATIAL 關(guān)鍵字進(jìn)行擴(kuò)展从媚。

創(chuàng)建空間索引的列必須將其聲明為 NOT NULL,空間索引只能在存儲(chǔ)引擎為 MyISAM 的表中創(chuàng)建患整。

空間索引主要用于地理空間數(shù)據(jù)類型 GEOMETRY拜效。對(duì)于初學(xué)者來說,這類索引很少會(huì)用到各谚。

全文索引

全文索引主要用來查找文本中的關(guān)鍵字紧憾,只能在 CHAR、VARCHAR 或 TEXT 類型的列上創(chuàng)建昌渤。在 MySQL 中只有 MyISAM 存儲(chǔ)引擎支持全文索引赴穗。

全文索引允許在索引列中插入重復(fù)值和空值。

不過對(duì)于大容量的數(shù)據(jù)表膀息,生成全文索引非常消耗時(shí)間和硬盤空間般眉。

創(chuàng)建全文索引使用 FULLTEXT 關(guān)鍵字。

實(shí)際使用區(qū)分

索引在邏輯上分為以上 5 類潜支,但在實(shí)際使用中甸赃,索引通常被創(chuàng)建成單列索引和組合索引。

單列索引

單列索引就是索引只包含原表的一個(gè)列冗酿。在表中的單個(gè)字段上創(chuàng)建索引埠对,單列索引只根據(jù)該字段進(jìn)行索引络断。

單列索引可以是普通索引,也可以是唯一性索引项玛,還可以是全文索引貌笨。只要保證該索引只對(duì)應(yīng)一個(gè)字段即可。

多列索引

組合索引也稱為復(fù)合索引或多列索引襟沮。相對(duì)于單列索引來說锥惋,組合索引是將原表的多個(gè)列共同組成一個(gè)索引。多列索引是在表的多個(gè)字段上創(chuàng)建一個(gè)索引臣嚣。該索引指向創(chuàng)建時(shí)對(duì)應(yīng)的多個(gè)字段净刮,可以通過這幾個(gè)字段進(jìn)行查詢。但是硅则,只有查詢條件中使用了這些字段中第一個(gè)字段時(shí)淹父,索引才會(huì)被使用。

提示:一個(gè)表可以有多個(gè)單列索引怎虫,但這些索引不是組合索引暑认。一個(gè)組合索引實(shí)質(zhì)上為表的查詢提供了多個(gè)索引,以此來加快查詢速度大审。

  • 比如蘸际,在一個(gè)表中創(chuàng)建了一個(gè)組合索引(c1,c2徒扶,c3)粮彤,在實(shí)際查詢中,系統(tǒng)用來實(shí)際加速的索引有三個(gè):?jiǎn)蝹€(gè)索引(c1)姜骡、雙列索引(c1导坟,c2)和多列索引(c1,c2圈澈,c3)惫周。

MySQL創(chuàng)建索引

創(chuàng)建索引是指在某個(gè)表的一列或多列上建立一個(gè)索引,可以提高對(duì)表的訪問速度康栈。創(chuàng)建索引對(duì) MySQL數(shù)據(jù)庫(kù)的高效運(yùn)行來說是很重要的递递。

基本語(yǔ)法

MySQL 提供了三種創(chuàng)建索引的方法:

使用 CREATE INDEX 語(yǔ)句

可以使用專門用于創(chuàng)建索引的 CREATE INDEX 語(yǔ)句在一個(gè)已有的表上創(chuàng)建索引,但該語(yǔ)句不能創(chuàng)建主鍵啥么。

語(yǔ)法格式:

CREATE <索引名> ON <表名> (<列名> [<長(zhǎng)度>] [ ASC | DESC])

語(yǔ)法說明如下:

  • <索引名>:指定索引名登舞。一個(gè)表可以創(chuàng)建多個(gè)索引,但每個(gè)索引在該表中的名稱是唯一的悬荣。
  • <表名>:指定要?jiǎng)?chuàng)建索引的表名逊躁。
  • <列名>:指定要?jiǎng)?chuàng)建索引的列名。通秤缥酰可以考慮將查詢語(yǔ)句中在 JOIN 子句和 WHERE 子句里經(jīng)常出現(xiàn)的列作為索引列稽煤。
  • <長(zhǎng)度>:可選項(xiàng)。指定使用列前的 length 個(gè)字符來創(chuàng)建索引囚戚。使用列的一部分創(chuàng)建索引有利于減小索引文件的大小酵熙,節(jié)省索引列所占的空間。在某些情況下驰坊,只能對(duì)列的前綴進(jìn)行索引匾二。索引列的長(zhǎng)度有一個(gè)最大上限 255 個(gè)字節(jié)(MyISAM 和 InnoDB 表的最大上限為 1000 個(gè)字節(jié)),如果索引列的長(zhǎng)度超過了這個(gè)上限拳芙,就只能用列的前綴進(jìn)行索引察藐。另外,BLOB 或 TEXT 類型的列也必須使用前綴索引舟扎。
  • ASC|DESC:可選項(xiàng)分飞。ASC指定索引按照升序來排列,DESC指定索引按照降序來排列睹限,默認(rèn)為ASC譬猫。

使用 CREATE TABLE 語(yǔ)句

索引也可以在創(chuàng)建表(CREATE TABLE)的同時(shí)創(chuàng)建。在 CREATE TABLE 語(yǔ)句中添加以下語(yǔ)句羡疗。語(yǔ)法格式:

CONSTRAINT PRIMARY KEY [索引類型] (<列名>,…)

在 CREATE TABLE 語(yǔ)句中添加此語(yǔ)句染服,表示在創(chuàng)建新表的同時(shí)創(chuàng)建該表的主鍵。

語(yǔ)法格式:

KEY | INDEX [<索引名>] [<索引類型>] (<列名>,…)

在 CREATE TABLE 語(yǔ)句中添加此語(yǔ)句叨恨,表示在創(chuàng)建新表的同時(shí)創(chuàng)建該表的索引柳刮。

語(yǔ)法格式:

UNIQUE [ INDEX | KEY] [<索引名>] [<索引類型>] (<列名>,…)

在 CREATE TABLE 語(yǔ)句中添加此語(yǔ)句,表示在創(chuàng)建新表的同時(shí)創(chuàng)建該表的唯一性索引痒钝。

語(yǔ)法格式:

FOREIGN KEY <索引名> <列名>

在 CREATE TABLE 語(yǔ)句中添加此語(yǔ)句秉颗,表示在創(chuàng)建新表的同時(shí)創(chuàng)建該表的外鍵。

在使用 CREATE TABLE 語(yǔ)句定義列選項(xiàng)的時(shí)候午乓,可以通過直接在某個(gè)列定義后面添加 PRIMARY KEY 的方式創(chuàng)建主鍵站宗。而當(dāng)主鍵是由多個(gè)列組成的多列索引時(shí),則不能使用這種方法益愈,只能用在語(yǔ)句的最后加上一個(gè) PRIMARY KRY(<列名>梢灭,…) 子句的方式來實(shí)現(xiàn)。

使用 ALTER TABLE 語(yǔ)句

CREATE INDEX 語(yǔ)句可以在一個(gè)已有的表上創(chuàng)建索引蒸其,ALTER TABLE 語(yǔ)句也可以在一個(gè)已有的表上創(chuàng)建索引敏释。在使用 ALTER TABLE 語(yǔ)句修改表的同時(shí),可以向已有的表添加索引摸袁。具體的做法是在 ALTER TABLE 語(yǔ)句中添加以下語(yǔ)法成分的某一項(xiàng)或幾項(xiàng)钥顽。

語(yǔ)法格式:

ADD INDEX [<索引名>] [<索引類型>] (<列名>,…)

在 ALTER TABLE 語(yǔ)句中添加此語(yǔ)法成分,表示在修改表的同時(shí)為該表添加索引靠汁。

語(yǔ)法格式:

ADD PRIMARY KEY [<索引類型>] (<列名>,…)

在 ALTER TABLE 語(yǔ)句中添加此語(yǔ)法成分蜂大,表示在修改表的同時(shí)為該表添加主鍵闽铐。

語(yǔ)法格式:

ADD UNIQUE [ INDEX | KEY] [<索引名>] [<索引類型>] (<列名>,…)

在 ALTER TABLE 語(yǔ)句中添加此語(yǔ)法成分,表示在修改表的同時(shí)為該表添加唯一性索引奶浦。

語(yǔ)法格式:

ADD FOREIGN KEY [<索引名>] (<列名>,…)

在 ALTER TABLE 語(yǔ)句中添加此語(yǔ)法成分兄墅,表示在修改表的同時(shí)為該表添加外鍵。

創(chuàng)建普通索引

創(chuàng)建普通索引時(shí)澳叉,通常使用 INDEX 關(guān)鍵字隙咸。

例子:創(chuàng)建一個(gè)表 tb_stu_info,在該表的 height 字段創(chuàng)建普通索引成洗。輸入的 SQL 語(yǔ)句和執(zhí)行過程如下所示五督。

mysql> CREATE TABLE tb_stu_info
    -> (
    -> id INT NOT NULL,
    -> name CHAR(45) DEFAULT NULL,
    -> dept_id INT DEFAULT NULL,
    -> age INT DEFAULT NULL,
    -> height INT DEFAULT NULL,
    -> INDEX(height)
    -> );
Query OK,0 rows affected (0.40 sec)
mysql> SHOW CREATE TABLE tb_stu_info\G
*************************** 1. row ***************************
       Table: tb_stu_info
Create Table: CREATE TABLE `tb_stu_info` (
  `id` int(11) NOT NULL,
  `name` char(45) DEFAULT NULL,
  `dept_id` int(11) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `height` int(11) DEFAULT NULL,
  KEY `height` (`height`)
) ENGINE=InnoDB DEFAULT CHARSET=gb2312
1 row in set (0.01 sec)

創(chuàng)建唯一索引

創(chuàng)建唯一索引瓶殃,通常使用 UNIQUE 參數(shù)充包。

例子:創(chuàng)建一個(gè)表 tb_stu_info2,在該表的 id 字段上使用 UNIQUE 關(guān)鍵字創(chuàng)建唯一索引碌燕。輸入的 SQL 語(yǔ)句和執(zhí)行過程如下所示误证。

mysql> CREATE TABLE tb_stu_info2
    -> (
    -> id INT NOT NULL,
    -> name CHAR(45) DEFAULT NULL,
    -> dept_id INT DEFAULT NULL,
    -> age INT DEFAULT NULL,
    -> height INT DEFAULT NULL,
    -> UNIQUE INDEX(height)
    -> );
Query OK,0 rows affected (0.40 sec)
mysql> SHOW CREATE TABLE tb_stu_info2\G
*************************** 1. row ***************************
       Table: tb_stu_info2
Create Table: CREATE TABLE `tb_stu_info2` (
  `id` int(11) NOT NULL,
  `name` char(45) DEFAULT NULL,
  `dept_id` int(11) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `height` int(11) DEFAULT NULL,
  UNIQUE KEY `height` (`height`)
) ENGINE=InnoDB DEFAULT CHARSET=gb2312
1 row in set (0.00 sec)

MySQL查看索引

索引創(chuàng)建完成后修壕,可以利用 SQL 語(yǔ)句查看已經(jīng)存在的索引愈捅。在 MySQL 中,可以使用 SHOW INDEX 語(yǔ)句查看表中創(chuàng)建的索引慈鸠。

查看索引的語(yǔ)法格式如下:

SHOW INDEX FROM <表名> [ FROM <數(shù)據(jù)庫(kù)名>]

語(yǔ)法說明如下:

  • <表名>:指定需要查看索引的數(shù)據(jù)表名蓝谨。
  • <數(shù)據(jù)庫(kù)名>:指定需要查看索引的數(shù)據(jù)表所在的數(shù)據(jù)庫(kù),可省略青团。比如譬巫,SHOW INDEX FROM student FROM test; 語(yǔ)句表示查看 test 數(shù)據(jù)庫(kù)中 student 數(shù)據(jù)表的索引。

其中各主要參數(shù)說明如下:

參數(shù) 說明
Table 表示創(chuàng)建索引的數(shù)據(jù)表名督笆,這里是 tb_stu_info2 數(shù)據(jù)表芦昔。
Non_unique 表示該索引是否是唯一索引。若不是唯一索引娃肿,則該列的值為 1咕缎;若是唯一索引,則該列的值為 0料扰。
Key_name 表示索引的名稱凭豪。
Seq_in_index 表示該列在索引中的位置,如果索引是單列的,則該列的值為 1;如果索引是組合索引氓仲,則該列的值為每列在索引定義中的順序由蘑。
Column_name 表示定義索引的列字段。
Collation 表示列以何種順序存儲(chǔ)在索引中梢薪。在 MySQL 中耻讽,升序顯示值“A”(升序)有决,若顯示為 NULL拼余,則表示無(wú)分類郑趁。
Cardinality 索引中唯一值數(shù)目的估計(jì)值∽怂眩基數(shù)根據(jù)被存儲(chǔ)為整數(shù)的統(tǒng)計(jì)數(shù)據(jù)計(jì)數(shù),所以即使對(duì)于小型表捆憎,該值也沒有必要是精確的舅柜。基數(shù)越大躲惰,當(dāng)進(jìn)行聯(lián)合時(shí)致份,MySQL 使用該索引的機(jī)會(huì)就越大。
Sub_part 表示列中被編入索引的字符的數(shù)量础拨。若列只是部分被編入索引氮块,則該列的值為被編入索引的字符的數(shù)目;若整列被編入索引诡宗,則該列的值為 NULL滔蝉。
Packed 指示關(guān)鍵字如何被壓縮。若沒有被壓縮塔沃,值為 NULL蝠引。
Null 用于顯示索引列中是否包含 NULL。若列含有 NULL蛀柴,該列的值為 YES螃概。若沒有,則該列的值為 NO鸽疾。
Index_type 顯示索引使用的類型和方法(BTREE吊洼、FULLTEXT、HASH制肮、RTREE)冒窍。
Comment 顯示評(píng)注。

MySQL修改和刪除索引

刪除索引是指將表中已經(jīng)存在的索引刪除掉弄企。不用的索引建議進(jìn)行刪除超燃,因?yàn)樗鼈儠?huì)降低表的更新速度,影響數(shù)據(jù)庫(kù)的性能拘领。對(duì)于這樣的索引意乓,應(yīng)該將其刪除。

在 MySQL 中修改索引可以通過刪除原索引,再根據(jù)需要?jiǎng)?chuàng)建一個(gè)同名的索引届良,從而實(shí)現(xiàn)修改索引的操作笆凌。

基本語(yǔ)法

當(dāng)不再需要索引時(shí),可以使用 DROP INDEX 語(yǔ)句或 ALTER TABLE 語(yǔ)句來對(duì)索引進(jìn)行刪除士葫。

使用 DROP INDEX 語(yǔ)句

語(yǔ)法格式:

DROP INDEX <索引名> ON <表名>

語(yǔ)法說明如下:

  • <索引名>:要?jiǎng)h除的索引名乞而。
  • <表名>:指定該索引所在的表名。

使用 ALTER TABLE 語(yǔ)句

根據(jù) ALTER TABLE 語(yǔ)句的語(yǔ)法可知慢显,該語(yǔ)句也可以用于刪除索引爪模。具體使用方法是將 ALTER TABLE 語(yǔ)句的語(yǔ)法中部分指定為以下子句中的某一項(xiàng)。

  • DROP PRIMARY KEY:表示刪除表中的主鍵荚藻。一個(gè)表只有一個(gè)主鍵屋灌,主鍵也是一個(gè)索引。
  • DROP INDEX index_name:表示刪除名稱為 index_name 的索引应狱。
  • DROP FOREIGN KEY fk_symbol:表示刪除外鍵共郭。

注意:如果刪除的列是索引的組成部分,那么在刪除該列時(shí)疾呻,也會(huì)將該列從索引中刪除除嘹;如果組成索引的所有列都被刪除,那么整個(gè)索引將被刪除岸蜗。

索引失效

索引可以提高查詢的速度尉咕,但并不是使用帶有索引的字段查詢時(shí),索引都會(huì)起作用散吵。使用索引有幾種特殊情況龙考,在這些情況下,有可能使用帶有索引的字段查詢時(shí)矾睦,索引并沒有起作用晦款,下面重點(diǎn)介紹這幾種特殊情況。

  1. 查詢語(yǔ)句中使用LIKE關(guān)鍵字:在查詢語(yǔ)句中使用 LIKE 關(guān)鍵字進(jìn)行查詢時(shí)枚冗,如果匹配字符串的第一個(gè)字符為“%”缓溅,索引不會(huì)被使用。如果“%”不是在第一個(gè)位置赁温,索引就會(huì)被使用坛怪。
  2. 查詢語(yǔ)句中使用多列索引:多列索引是在表的多個(gè)字段上創(chuàng)建一個(gè)索引,只有查詢條件中使用了這些字段中的第一個(gè)字段股囊,索引才會(huì)被使用袜匿。
  3. 查詢語(yǔ)句中使用OR關(guān)鍵字:查詢語(yǔ)句只有 OR 關(guān)鍵字時(shí),如果 OR 前后的兩個(gè)條件的列都是索引稚疹,那么查詢中將使用索引居灯。如果 OR 前后有一個(gè)條件的列不是索引,那么查詢中將不使用索引。

MySQL索引的設(shè)計(jì)原則

索引的設(shè)計(jì)可以遵循一些已有的原則怪嫌,創(chuàng)建索引的時(shí)候應(yīng)盡量考慮符合這些原則义锥,便于提升索引的使用效率,更高效的使用索引岩灭。

  1. 選擇唯一性索引:唯一性索引的值是唯一的拌倍,可以更快速的通過該索引來確定某條記錄。
    • 例如噪径,學(xué)生表中學(xué)號(hào)是具有唯一性的字段柱恤。為該字段建立唯一性索引可以很快的確定某個(gè)學(xué)生的信息。如果使用姓名的話找爱,可能存在同名現(xiàn)象膨更,從而降低查詢速度。
  2. 為經(jīng)常需要排序缴允、分組和聯(lián)合操作的字段建立索引:經(jīng)常需要 ORDER BY、GROUP BY珍德、DISTINCT 和 UNION 等操作的字段练般,排序操作會(huì)浪費(fèi)很多時(shí)間。如果為其建立索引锈候,可以有效地避免排序操作薄料。
  3. 為常作為查詢條件的字段建立索引:如果某個(gè)字段經(jīng)常用來做查詢條件,那么該字段的查詢速度會(huì)影響整個(gè)表的查詢速度泵琳。因此摄职,為這樣的字段建立索引,可以提高整個(gè)表的查詢速度获列。
    • 注意:常查詢條件的字段不一定是所要選擇的列谷市,換句話說,最適合索引的列是出現(xiàn)在 WHERE 子句中的列击孩,或連接子句中指定的列迫悠,而不是出現(xiàn)在 SELECT 關(guān)鍵字后的選擇列表中的列。
  4. 限制索引的數(shù)目:索引的數(shù)目不是“越多越好”巩梢。每個(gè)索引都需要占用磁盤空間创泄,索引越多,需要的磁盤空間就越大括蝠。在修改表的內(nèi)容時(shí)鞠抑,索引必須進(jìn)行更新,有時(shí)還可能需要重構(gòu)忌警。因此搁拙,索引越多,更新表的時(shí)間就越長(zhǎng)。
    • 如果有一個(gè)索引很少利用或從不使用感混,那么會(huì)不必要地減緩表的修改速度端幼。此外,MySQL 在生成一個(gè)執(zhí)行計(jì)劃時(shí)弧满,要考慮各個(gè)索引婆跑,這也要花費(fèi)時(shí)間。創(chuàng)建多余的索引給查詢優(yōu)化帶來了更多的工作庭呜。索引太多滑进,也可能會(huì)使 MySQL 選擇不到所要使用的最佳索引。
  5. 盡量使用數(shù)據(jù)量少的索引:如果索引的值很長(zhǎng)募谎,那么查詢的速度會(huì)受到影響扶关。
    • 例如,對(duì)一個(gè) CHAR(100) 類型的字段進(jìn)行全文檢索需要的時(shí)間肯定要比對(duì) CHAR(10) 類型的字段需要的時(shí)間要多数冬。
  6. 數(shù)據(jù)量小的表最好不要使用索引:由于數(shù)據(jù)較小节槐,查詢花費(fèi)的時(shí)間可能比遍歷索引的時(shí)間還要短,索引可能不會(huì)產(chǎn)生優(yōu)化效果拐纱。
  7. 盡量使用前綴來索引:如果索引字段的值很長(zhǎng)铜异,最好使用值的前綴來索引。
    • 例如秸架,TEXT 和 BLOG 類型的字段揍庄,進(jìn)行全文檢索會(huì)很浪費(fèi)時(shí)間。如果只檢索字段的前面的若干個(gè)字符东抹,這樣可以提高檢索速度蚂子。
  8. 刪除不再使用或者很少使用的索引:表中的數(shù)據(jù)被大量更新,或者數(shù)據(jù)的使用方式被改變后缭黔,原有的一些索引可能不再需要食茎。應(yīng)該定期找出這些索引,將它們刪除馏谨,從而減少索引對(duì)更新操作的影響董瞻。

總結(jié):選擇索引的最終目的是為了使查詢的速度變快,上面給出的原則是最基本的準(zhǔn)則田巴,但不能只拘泥于上面的準(zhǔn)則钠糊。應(yīng)該在學(xué)習(xí)和工作中不斷的實(shí)踐,根據(jù)應(yīng)用的實(shí)際情況進(jìn)行分析和判斷壹哺,選擇最合適的索引方式抄伍。

存儲(chǔ)過程是什么

在數(shù)據(jù)庫(kù)的實(shí)際操作中,經(jīng)常會(huì)有需要多條 SQL 語(yǔ)句處理多個(gè)表才能完成的操作管宵。

  • 例如截珍,為了確認(rèn)學(xué)生能否畢業(yè)攀甚,需要同時(shí)查詢學(xué)生檔案表、成績(jī)表和綜合表岗喉,此時(shí)就需要使用多條 SQL 語(yǔ)句來針對(duì)這幾個(gè)數(shù)據(jù)表完成處理要求秋度。

存儲(chǔ)過程是一組為了完成特定功能的 SQL 語(yǔ)句集合。使用存儲(chǔ)過程的目的是將常用或復(fù)雜的工作預(yù)先用 SQL 語(yǔ)句寫好并用一個(gè)指定名稱存儲(chǔ)起來钱床,這個(gè)過程經(jīng)編譯和優(yōu)化后存儲(chǔ)在數(shù)據(jù)庫(kù)服務(wù)器中荚斯,因此稱為存儲(chǔ)過程。當(dāng)以后需要數(shù)據(jù)庫(kù)提供與已定義好的存儲(chǔ)過程的功能相同的服務(wù)時(shí)查牌,只需調(diào)用“CALL存儲(chǔ)過程名字”即可自動(dòng)完成事期。

常用操作數(shù)據(jù)庫(kù)的 SQL 語(yǔ)句在執(zhí)行的時(shí)候需要先編譯,然后執(zhí)行纸颜。存儲(chǔ)過程則采用另一種方式來執(zhí)行 SQL 語(yǔ)句兽泣。

一個(gè)存儲(chǔ)過程是一個(gè)可編程的函數(shù),它在數(shù)據(jù)庫(kù)中創(chuàng)建并保存胁孙,一般由 SQL 語(yǔ)句和一些特殊的控制結(jié)構(gòu)組成唠倦。當(dāng)希望在不同的應(yīng)用程序或平臺(tái)上執(zhí)行相同的特定功能時(shí),存儲(chǔ)過程尤為合適涮较。

MySQL 5.0 版本以前并不支持存儲(chǔ)過程牵敷,這使 MySQL 在應(yīng)用上大打折扣。MySQL 從 5.0 版本開始支持存儲(chǔ)過程法希,既提高了數(shù)據(jù)庫(kù)的處理速度,同時(shí)也提高了數(shù)據(jù)庫(kù)編程的靈活性

存儲(chǔ)過程是數(shù)據(jù)庫(kù)中的一個(gè)重要功能靶瘸,存儲(chǔ)過程可以用來轉(zhuǎn)換數(shù)據(jù)苫亦、數(shù)據(jù)遷移、制作報(bào)表怨咪,它類似于編程語(yǔ)言屋剑,一次執(zhí)行成功,就可以隨時(shí)被調(diào)用诗眨,完成指定的功能操作唉匾。

使用存儲(chǔ)過程不僅可以提高數(shù)據(jù)庫(kù)的訪問效率,同時(shí)也可以提高數(shù)據(jù)庫(kù)使用的安全性匠楚。

對(duì)于調(diào)用者來說巍膘,存儲(chǔ)過程封裝了 SQL 語(yǔ)句,調(diào)用者無(wú)需考慮邏輯功能的具體實(shí)現(xiàn)過程芋簿。只是簡(jiǎn)單調(diào)用即可峡懈,它可以被 Java 和 C# 等編程語(yǔ)言調(diào)用。

編寫存儲(chǔ)過程對(duì)開發(fā)者要求稍微高一些与斤,但這并不影響存儲(chǔ)過程的普遍使用肪康,因?yàn)榇鎯?chǔ)過程有如下優(yōu)點(diǎn):

  1. 封裝性:通常完成一個(gè)邏輯功能需要多條 SQL 語(yǔ)句荚恶,而且各個(gè)語(yǔ)句之間很可能傳遞參數(shù),所以磷支,編寫邏輯功能相對(duì)來說稍微復(fù)雜些谒撼,而存儲(chǔ)過程可以把這些 SQL 語(yǔ)句包含到一個(gè)獨(dú)立的單元中,使外界看不到復(fù)雜的 SQL 語(yǔ)句雾狈,只需要簡(jiǎn)單調(diào)用即可達(dá)到目的廓潜。并且數(shù)據(jù)庫(kù)專業(yè)人員可以隨時(shí)對(duì)存儲(chǔ)過程進(jìn)行修改,而不會(huì)影響到調(diào)用它的應(yīng)用程序源代碼箍邮。
  2. 可增強(qiáng) SQL 語(yǔ)句的功能和靈活性:存儲(chǔ)過程可以用流程控制語(yǔ)句編寫茉帅,有很強(qiáng)的靈活性,可以完成復(fù)雜的判斷和較復(fù)雜的運(yùn)算锭弊。
  3. 可減少網(wǎng)絡(luò)流量:由于存儲(chǔ)過程是在服務(wù)器端運(yùn)行的堪澎,且執(zhí)行速度快,因此當(dāng)客戶計(jì)算機(jī)上調(diào)用該存儲(chǔ)過程時(shí)味滞,網(wǎng)絡(luò)中傳送的只是該調(diào)用語(yǔ)句樱蛤,從而可降低網(wǎng)絡(luò)負(fù)載。
  4. 高性能:當(dāng)存儲(chǔ)過程被成功編譯后剑鞍,就存儲(chǔ)在數(shù)據(jù)庫(kù)服務(wù)器里了昨凡,以后客戶端可以直接調(diào)用,這樣所有的 SQL 語(yǔ)句將從服務(wù)器執(zhí)行蚁署,從而提高性能便脊。但需要說明的是,存儲(chǔ)過程不是越多越好光戈,過多的使用存儲(chǔ)過程反而影響系統(tǒng)性能哪痰。
  5. 提高數(shù)據(jù)庫(kù)的安全性和數(shù)據(jù)的完整性:存儲(chǔ)過程提高安全性的一個(gè)方案就是把它作為中間組件,存儲(chǔ)過程里可以對(duì)某些表做相關(guān)操作久妆,然后存儲(chǔ)過程作為接口提供給外部程序晌杰。這樣,外部程序無(wú)法直接操作數(shù)據(jù)庫(kù)表筷弦,只能通過存儲(chǔ)過程來操作對(duì)應(yīng)的表肋演,因此在一定程度上,安全性是可以得到提高的烂琴。
  6. 使數(shù)據(jù)獨(dú)立:數(shù)據(jù)的獨(dú)立可以達(dá)到解耦的效果爹殊,也就是說,程序可以調(diào)用存儲(chǔ)過程奸绷,來替代執(zhí)行多條的 SQL 語(yǔ)句边灭。這種情況下,存儲(chǔ)過程把數(shù)據(jù)同用戶隔離開來健盒,優(yōu)點(diǎn)就是當(dāng)數(shù)據(jù)表的結(jié)構(gòu)改變時(shí)绒瘦,調(diào)用表不用修改程序称簿,只需要數(shù)據(jù)庫(kù)管理者重新編寫存儲(chǔ)過程即可。

MySQL創(chuàng)建存儲(chǔ)過程

MySQL 存儲(chǔ)過程是一些 SQL 語(yǔ)句的集合惰帽,比如有時(shí)候我們可能需要一大串的 SQL 語(yǔ)句憨降,或者說在編寫 SQL 語(yǔ)句的過程中需要設(shè)置一些變量的值,這個(gè)時(shí)候我們就完全有必要編寫一個(gè)存儲(chǔ)過程该酗。

編寫存儲(chǔ)過程并不是件簡(jiǎn)單的事情授药,但是使用存儲(chǔ)過程可以簡(jiǎn)化操作,且減少冗余的操作步驟呜魄,同時(shí)悔叽,還可以減少操作過程中的失誤,提高效率爵嗅,因此應(yīng)該盡可能的學(xué)會(huì)使用存儲(chǔ)過程娇澎。

下面主要介紹如何創(chuàng)建存儲(chǔ)過程。

可以使用 CREATE PROCEDURE 語(yǔ)句創(chuàng)建存儲(chǔ)過程睹晒,語(yǔ)法格式如下:

CREATE PROCEDURE <過程名> ( [過程參數(shù)[,…] ] ) <過程體>
[過程參數(shù)[,…] ] 格式
[ IN | OUT | INOUT ] <參數(shù)名> <類型>

語(yǔ)法說明如下:

  1. 過程名:存儲(chǔ)過程的名稱趟庄,默認(rèn)在當(dāng)前數(shù)據(jù)庫(kù)中創(chuàng)建。若需要在特定數(shù)據(jù)庫(kù)中創(chuàng)建存儲(chǔ)過程伪很,則要在名稱前面加上數(shù)據(jù)庫(kù)的名稱戚啥,即 db_name.sp_name。
    • 需要注意的是锉试,名稱應(yīng)當(dāng)盡量避免選取與 MySQL 內(nèi)置函數(shù)相同的名稱猫十,否則會(huì)發(fā)生錯(cuò)誤。
  2. 過程參數(shù):存儲(chǔ)過程的參數(shù)列表呆盖。其中拖云,<參數(shù)名>為參數(shù)名,<類型>為參數(shù)的類型(可以是任何有效的 MySQL 數(shù)據(jù)類型)。當(dāng)有多個(gè)參數(shù)時(shí),參數(shù)列表中彼此間用逗號(hào)分隔辈挂。存儲(chǔ)過程可以沒有參數(shù)(此時(shí)存儲(chǔ)過程的名稱后仍需加上一對(duì)括號(hào))抓督,也可以有 1 個(gè)或多個(gè)參數(shù)。
    • MySQL 存儲(chǔ)過程支持三種類型的參數(shù)邑贴,即輸入?yún)?shù)席里、輸出參數(shù)和輸入/輸出參數(shù),分別用 IN拢驾、OUT 和 INOUT 三個(gè)關(guān)鍵字標(biāo)識(shí)奖磁。其中,輸入?yún)?shù)可以傳遞給一個(gè)存儲(chǔ)過程繁疤,輸出參數(shù)用于存儲(chǔ)過程需要返回一個(gè)操作結(jié)果的情形咖为,而輸入/輸出參數(shù)既可以充當(dāng)輸入?yún)?shù)也可以充當(dāng)輸出參數(shù)秕狰。
    • 需要注意的是,參數(shù)的取名不要與數(shù)據(jù)表的列名相同躁染,否則盡管不會(huì)返回出錯(cuò)信息鸣哀,但是存儲(chǔ)過程的 SQL 語(yǔ)句會(huì)將參數(shù)名看作列名,從而引發(fā)不可預(yù)知的結(jié)果吞彤。
  3. 過程體存儲(chǔ)過程的主體部分我衬,也稱為存儲(chǔ)過程體,包含在過程調(diào)用的時(shí)候必須執(zhí)行的 SQL 語(yǔ)句饰恕。這個(gè)部分以關(guān)鍵字 BEGIN 開始挠羔,以關(guān)鍵字 END 結(jié)束。若存儲(chǔ)過程體中只有一條 SQL 語(yǔ)句埋嵌,則可以省略 BEGIN-END 標(biāo)志破加。

DELIMITER 命令

在存儲(chǔ)過程的創(chuàng)建中,經(jīng)常會(huì)用到一個(gè)十分重要的 MySQL 命令莉恼,即 DELIMITER 命令

在 MySQL 中拌喉,服務(wù)器處理 SQL 語(yǔ)句默認(rèn)是以分號(hào)作為語(yǔ)句結(jié)束標(biāo)志的。然而俐银,在創(chuàng)建存儲(chǔ)過程時(shí)尿背,存儲(chǔ)過程體可能包含有多條 SQL 語(yǔ)句,這些 SQL 語(yǔ)句如果仍以分號(hào)作為語(yǔ)句結(jié)束符捶惜,那么 MySQL 服務(wù)器在處理時(shí)會(huì)以遇到的第一條 SQL 語(yǔ)句結(jié)尾處的分號(hào)作為整個(gè)程序的結(jié)束符田藐,而不再去處理存儲(chǔ)過程體中后面的 SQL 語(yǔ)句,這樣顯然不行吱七。

為解決以上問題汽久,通常使用 DELIMITER 命令將結(jié)束命令修改為其他字符。語(yǔ)法格式如下:

DELIMITER $$

語(yǔ)法說明如下:

  • $$ 是用戶定義的結(jié)束符踊餐,通常這個(gè)符號(hào)可以是一些特殊的符號(hào)景醇,如兩個(gè)“?”或兩個(gè)“¥”等。
  • 當(dāng)使用 DELIMITER 命令時(shí)吝岭,應(yīng)該避免使用反斜杠“\”字符三痰,因?yàn)樗?MySQL 的轉(zhuǎn)義字符。

在 MySQL 命令行客戶端輸入如下 SQL 語(yǔ)句窜管。

mysql > DELIMITER ??

成功執(zhí)行這條 SQL 語(yǔ)句后散劫,任何命令、語(yǔ)句或程序的結(jié)束標(biāo)志就換為兩個(gè)問號(hào)“??”了幕帆。

若希望換回默認(rèn)的分號(hào)“;”作為結(jié)束標(biāo)志获搏,則在 MySQL 命令行客戶端輸入下列語(yǔ)句即可:

mysql > DELIMITER ;

注意:DELIMITER 和分號(hào)“;”之間一定要有一個(gè)空格。在創(chuàng)建存儲(chǔ)過程時(shí)失乾,必須具有 CREATE ROUTINE 權(quán)限常熙。

MySQL查看存儲(chǔ)過程

創(chuàng)建好存儲(chǔ)過程后纬乍,用戶可以通過 SHOW ATATUS 語(yǔ)句來查看存儲(chǔ)過程的狀態(tài),也可以通過 SHOW CREATE 語(yǔ)句來查看存儲(chǔ)過程的定義症概。

查看存儲(chǔ)過程的狀態(tài)

MySQL 中可以通過 SHOW STATUS 語(yǔ)句查看存儲(chǔ)過程的狀態(tài)蕾额,其基本語(yǔ)法形式如下:

SHOW PROCEDURE STATUS LIKE 存儲(chǔ)過程名;

LIKE 存儲(chǔ)過程名用來匹配存儲(chǔ)過程的名稱,LIKE 不能省略彼城。

查看存儲(chǔ)過程的定義

MySQL 中可以通過 SHOW CREATE 語(yǔ)句查看存儲(chǔ)過程的狀態(tài)诅蝶,語(yǔ)法格式如下:

SHOW CREATE PROCEDURE 存儲(chǔ)過程名;

SHOW STATUS 語(yǔ)句只能查看存儲(chǔ)過程是操作的哪一個(gè)數(shù)據(jù)庫(kù)、存儲(chǔ)過程的名稱募壕、類型调炬、誰(shuí)定義的、創(chuàng)建和修改時(shí)間舱馅、字符編碼等信息缰泡。但是,這個(gè)語(yǔ)句不能查詢存儲(chǔ)過程的集體定義代嗤,如果需要查看詳細(xì)定義棘钞,需要使用 SHOW CREATE 語(yǔ)句。

存儲(chǔ)過程的信息都存儲(chǔ)在 information_schema 數(shù)據(jù)庫(kù)下的 Routines 表中干毅,可以通過查詢?cè)摫淼挠涗泚聿樵兇鎯?chǔ)過程的信息宜猜,SQL 語(yǔ)句如下:

SELECT * FROM information_schema.Routines WHERE ROUTINE_NAME=存儲(chǔ)過程名;

在 information_schema 數(shù)據(jù)庫(kù)下的 routines 表中,存儲(chǔ)著所有存儲(chǔ)過程的定義硝逢。所以姨拥,使用 SELECT 語(yǔ)句查詢 routines 表中的存儲(chǔ)過程和函數(shù)的定義時(shí),一定要使用 routine_name 字段指定存儲(chǔ)過程的名稱渠鸽,否則叫乌,將查詢出所有的存儲(chǔ)過程的定義。

MySQL修改存儲(chǔ)過程

在實(shí)際開發(fā)過程中徽缚,業(yè)務(wù)需求修改的情況時(shí)有發(fā)生憨奸,所以修改 MySQL 中的存儲(chǔ)過程是不可避免的。

MySQL 中通過 ALTER PROCEDURE 語(yǔ)句來修改存儲(chǔ)過程凿试。

MySQL 中修改存儲(chǔ)過程的語(yǔ)法格式如下:

ALTER PROCEDURE 存儲(chǔ)過程名 [ 特征 ... ]

特征指定了存儲(chǔ)過程的特性排宰,可能的取值有:

  • CONTAINS SQL 表示子程序包含 SQL 語(yǔ)句,但不包含讀或?qū)憯?shù)據(jù)的語(yǔ)句红省。
  • NO SQL 表示子程序中不包含 SQL 語(yǔ)句额各。
  • READS SQL DATA 表示子程序中包含讀數(shù)據(jù)的語(yǔ)句国觉。
  • MODIFIES SQL DATA 表示子程序中包含寫數(shù)據(jù)的語(yǔ)句吧恃。
  • SQL SECURITY { DEFINER |INVOKER } 指明誰(shuí)有權(quán)限來執(zhí)行。
  • DEFINER 表示只有定義者自己才能夠執(zhí)行麻诀。
  • INVOKER 表示調(diào)用者可以執(zhí)行痕寓。
  • COMMENT 'string' 表示注釋信息傲醉。

注意:ALTER PROCEDURE 語(yǔ)句用于修改存儲(chǔ)過程的某些特征。如果要修改存儲(chǔ)過程的內(nèi)容呻率,可以先刪除原存儲(chǔ)過程硬毕,再以相同的命名創(chuàng)建新的存儲(chǔ)過程;如果要修改存儲(chǔ)過程的名稱礼仗,可以先刪除原存儲(chǔ)過程吐咳,再以不同的命名創(chuàng)建新的存儲(chǔ)過程。

MySQL刪除存儲(chǔ)過程

存儲(chǔ)過程被創(chuàng)建后元践,就會(huì)一直保存在數(shù)據(jù)庫(kù)服務(wù)器上韭脊,直至被刪除。當(dāng) MySQL 數(shù)據(jù)庫(kù)中存在廢棄的存儲(chǔ)過程時(shí)单旁,我們需要將它從數(shù)據(jù)庫(kù)中刪除沪羔。

MySQL 中使用 DROP PROCEDURE 語(yǔ)句來刪除數(shù)據(jù)庫(kù)中已經(jīng)存在的存儲(chǔ)過程。語(yǔ)法格式如下:

DROP PROCEDURE [ IF EXISTS ] <過程名>

語(yǔ)法說明如下:

  • 過程名:指定要?jiǎng)h除的存儲(chǔ)過程的名稱象浑。
  • IF EXISTS:指定這個(gè)關(guān)鍵字蔫饰,用于防止因刪除不存在的存儲(chǔ)過程而引發(fā)的錯(cuò)誤。

注意:存儲(chǔ)過程名稱后面沒有參數(shù)列表愉豺,也沒有括號(hào)篓吁,在刪除之前,必須確認(rèn)該存儲(chǔ)過程沒有任何依賴關(guān)系粒氧,否則會(huì)導(dǎo)致其他與之關(guān)聯(lián)的存儲(chǔ)過程無(wú)法運(yùn)行越除。

觸發(fā)器是什么

MySQL 的觸發(fā)器和存儲(chǔ)過程一樣,都是嵌入到 MySQL 中的一段程序外盯,是 MySQL 中管理數(shù)據(jù)的有力工具摘盆。不同的是執(zhí)行存儲(chǔ)過程要使用 CALL 語(yǔ)句來調(diào)用,而觸發(fā)器的執(zhí)行不需要使用 CALL 語(yǔ)句來調(diào)用饱苟,也不需要手工啟動(dòng)孩擂,而是通過對(duì)數(shù)據(jù)表的相關(guān)操作來觸發(fā)、激活從而實(shí)現(xiàn)執(zhí)行箱熬。比如當(dāng)對(duì) student 表進(jìn)行操作(INSERT类垦,DELETE 或 UPDATE)時(shí)就會(huì)激活它執(zhí)行。

觸發(fā)器與數(shù)據(jù)表關(guān)系密切城须,主要用于保護(hù)表中的數(shù)據(jù)蚤认。特別是當(dāng)有多個(gè)表具有一定的相互聯(lián)系的時(shí)候,觸發(fā)器能夠讓不同的表保持?jǐn)?shù)據(jù)的一致性糕伐。

在 MySQL 中砰琢,只有執(zhí)行 INSERT、UPDATE 和 DELETE 操作時(shí)才能激活觸發(fā)器,其它 SQL 語(yǔ)句則不會(huì)激活觸發(fā)器陪汽。

那么為什么要使用觸發(fā)器呢训唱?比如,在實(shí)際開發(fā)項(xiàng)目時(shí)挚冤,我們經(jīng)常會(huì)遇到以下情況:

  • 在學(xué)生表中添加一條關(guān)于學(xué)生的記錄時(shí)况增,學(xué)生的總數(shù)就必須同時(shí)改變。
  • 增加一條學(xué)生記錄時(shí)训挡,需要檢查年齡是否符合范圍要求澳骤。
  • 刪除一條學(xué)生信息時(shí),需要?jiǎng)h除其成績(jī)表上的對(duì)應(yīng)記錄澜薄。
  • 刪除一條數(shù)據(jù)時(shí)宴凉,需要在數(shù)據(jù)庫(kù)存檔表中保留一個(gè)備份副本。

雖然上述情況實(shí)現(xiàn)的業(yè)務(wù)邏輯不同表悬,但是它們都需要在數(shù)據(jù)表發(fā)生更改時(shí)弥锄,自動(dòng)進(jìn)行一些處理。這時(shí)就可以使用觸發(fā)器處理蟆沫。

  • 例如籽暇,對(duì)于第一種情況,可以創(chuàng)建一個(gè)觸發(fā)器對(duì)象饭庞,每當(dāng)添加一條學(xué)生記錄時(shí)戒悠,就執(zhí)行一次計(jì)算學(xué)生總數(shù)的操作,這樣就可以保證每次添加一條學(xué)生記錄后舟山,學(xué)生總數(shù)和學(xué)生記錄數(shù)是一致的绸狐。

觸發(fā)器的優(yōu)缺點(diǎn)

觸發(fā)器的優(yōu)點(diǎn)如下:

  • 觸發(fā)器的執(zhí)行是自動(dòng)的,當(dāng)對(duì)觸發(fā)器相關(guān)表的數(shù)據(jù)做出相應(yīng)的修改后立即執(zhí)行累盗。
  • 觸發(fā)器可以實(shí)施比 FOREIGN KEY 約束寒矿、CHECK 約束更為復(fù)雜的檢查和操作。
  • 觸發(fā)器可以實(shí)現(xiàn)表數(shù)據(jù)的級(jí)聯(lián)更改若债,在一定程度上保證了數(shù)據(jù)的完整性符相。

觸發(fā)器的缺點(diǎn)如下:

  • 使用觸發(fā)器實(shí)現(xiàn)的業(yè)務(wù)邏輯在出現(xiàn)問題時(shí)很難進(jìn)行定位,特別是涉及到多個(gè)觸發(fā)器的情況下蠢琳,會(huì)使后期維護(hù)變得困難啊终。
  • 大量使用觸發(fā)器容易導(dǎo)致代碼結(jié)構(gòu)被打亂,增加了程序的復(fù)雜性傲须,
  • 如果需要變動(dòng)的數(shù)據(jù)量較大時(shí)蓝牲,觸發(fā)器的執(zhí)行效率會(huì)非常低。

MySQL 支持的觸發(fā)器

在實(shí)際使用中泰讽,MySQL 所支持的觸發(fā)器有三種:INSERT 觸發(fā)器例衍、UPDATE 觸發(fā)器和 DELETE 觸發(fā)器散怖。

INSERT 觸發(fā)器

在 INSERT 語(yǔ)句執(zhí)行之前或之后響應(yīng)的觸發(fā)器。

使用 INSERT 觸發(fā)器需要注意以下幾點(diǎn):

  • 在 INSERT 觸發(fā)器代碼內(nèi)肄渗,可引用一個(gè)名為 NEW(不區(qū)分大小寫)的虛擬表來訪問被插入的行。
  • 在 BEFORE INSERT 觸發(fā)器中咬最,NEW 中的值也可以被更新翎嫡,即允許更改被插入的值(只要具有對(duì)應(yīng)的操作權(quán)限)。
  • 對(duì)于 AUTO_INCREMENT 列永乌,NEW 在 INSERT 執(zhí)行之前包含的值是 0惑申,在 INSERT 執(zhí)行之后將包含新的自動(dòng)生成值。

UPDATE 觸發(fā)器

在 UPDATE 語(yǔ)句執(zhí)行之前或之后響應(yīng)的觸發(fā)器翅雏。

使用 UPDATE 觸發(fā)器需要注意以下幾點(diǎn):

  • 在 UPDATE 觸發(fā)器代碼內(nèi)圈驼,可引用一個(gè)名為 NEW(不區(qū)分大小寫)的虛擬表來訪問更新的值。
  • 在 UPDATE 觸發(fā)器代碼內(nèi)望几,可引用一個(gè)名為 OLD(不區(qū)分大小寫)的虛擬表來訪問 UPDATE 語(yǔ)句執(zhí)行前的值绩脆。
  • 在 BEFORE UPDATE 觸發(fā)器中,NEW 中的值可能也被更新橄抹,即允許更改將要用于 UPDATE 語(yǔ)句中的值(只要具有對(duì)應(yīng)的操作權(quán)限)靴迫。
  • OLD 中的值全部是只讀的,不能被更新楼誓。

注意:當(dāng)觸發(fā)器設(shè)計(jì)對(duì)觸發(fā)表自身的更新操作時(shí)玉锌,只能使用 BEFORE 類型的觸發(fā)器,AFTER 類型的觸發(fā)器將不被允許疟羹。

DELETE 觸發(fā)器

在 DELETE 語(yǔ)句執(zhí)行之前或之后響應(yīng)的觸發(fā)器主守。

使用 DELETE 觸發(fā)器需要注意以下幾點(diǎn):

  • 在 DELETE 觸發(fā)器代碼內(nèi),可以引用一個(gè)名為 OLD(不區(qū)分大小寫)的虛擬表來訪問被刪除的行榄融。
  • OLD 中的值全部是只讀的参淫,不能被更新。

總體來說愧杯,觸發(fā)器使用的過程中黄刚,MySQL 會(huì)按照以下方式來處理錯(cuò)誤。

對(duì)于事務(wù)性表民效,如果觸發(fā)程序失敗憔维,以及由此導(dǎo)致的整個(gè)語(yǔ)句失敗,那么該語(yǔ)句所執(zhí)行的所有更改將回滾畏邢;對(duì)于非事務(wù)性表业扒,則不能執(zhí)行此類回滾,即使語(yǔ)句失敗舒萎,失敗之前所做的任何更改依然有效程储。

若 BEFORE 觸發(fā)程序失敗,則 MySQL 將不執(zhí)行相應(yīng)行上的操作。

若在 BEFORE 或 AFTER 觸發(fā)程序的執(zhí)行過程中出現(xiàn)錯(cuò)誤章鲤,則將導(dǎo)致調(diào)用觸發(fā)程序的整個(gè)語(yǔ)句失敗摊灭。

僅當(dāng) BEFORE 觸發(fā)程序和行操作均已被成功執(zhí)行,MySQL 才會(huì)執(zhí)行 AFTER 觸發(fā)程序败徊。

MySQL創(chuàng)建觸發(fā)器

觸發(fā)器是與 MySQL 數(shù)據(jù)表有關(guān)的數(shù)據(jù)庫(kù)對(duì)象帚呼,在滿足定義條件時(shí)觸發(fā),并執(zhí)行觸發(fā)器中定義的語(yǔ)句集合皱蹦。觸發(fā)器的這種特性可以協(xié)助應(yīng)用在數(shù)據(jù)庫(kù)端確保數(shù)據(jù)的完整性煤杀。

基本語(yǔ)法

在 MySQL 5.7 中,可以使用 CREATE TRIGGER 語(yǔ)句創(chuàng)建觸發(fā)器沪哺。

語(yǔ)法格式如下:

CREATE <觸發(fā)器名> < BEFORE | AFTER >
<INSERT | UPDATE | DELETE >
ON <表名> FOR EACH Row<觸發(fā)器主體>

語(yǔ)法說明如下沈自。

  1. 觸發(fā)器名:觸發(fā)器的名稱,觸發(fā)器在當(dāng)前數(shù)據(jù)庫(kù)中必須具有唯一的名稱辜妓。如果要在某個(gè)特定數(shù)據(jù)庫(kù)中創(chuàng)建枯途,名稱前面應(yīng)該加上數(shù)據(jù)庫(kù)的名稱。
  2. INSERT | UPDATE | DELETE:觸發(fā)事件籍滴,用于指定激活觸發(fā)器的語(yǔ)句的種類柔袁。
    • 注意:三種觸發(fā)器的執(zhí)行時(shí)間如下。
      • INSERT:將新行插入表時(shí)激活觸發(fā)器异逐。例如捶索,INSERT 的 BEFORE 觸發(fā)器不僅能被 MySQL 的 INSERT 語(yǔ)句激活,也能被 LOAD DATA 語(yǔ)句激活灰瞻。
      • DELETE: 從表中刪除某一行數(shù)據(jù)時(shí)激活觸發(fā)器腥例,例如 DELETE 和 REPLACE 語(yǔ)句。
      • UPDATE:更改表中某一行數(shù)據(jù)時(shí)激活觸發(fā)器酝润,例如 UPDATE 語(yǔ)句燎竖。
  3. BEFORE | AFTER:BEFORE 和 AFTER,觸發(fā)器被觸發(fā)的時(shí)刻要销,表示觸發(fā)器是在激活它的語(yǔ)句之前或之后觸發(fā)构回。若希望驗(yàn)證新數(shù)據(jù)是否滿足條件,則使用 BEFORE 選項(xiàng)疏咐;若希望在激活觸發(fā)器的語(yǔ)句執(zhí)行之后完成幾個(gè)或更多的改變纤掸,則通常使用 AFTER 選項(xiàng)。
  4. 表名:與觸發(fā)器相關(guān)聯(lián)的表名浑塞,此表必須是永久性表借跪,不能將觸發(fā)器與臨時(shí)表或視圖關(guān)聯(lián)起來。在該表上觸發(fā)事件發(fā)生時(shí)才會(huì)激活觸發(fā)器酌壕。同一個(gè)表不能擁有兩個(gè)具有相同觸發(fā)時(shí)刻和事件的觸發(fā)器掏愁。例如歇由,對(duì)于一張數(shù)據(jù)表,不能同時(shí)有兩個(gè) BEFORE UPDATE 觸發(fā)器果港,但可以有一個(gè) BEFORE UPDATE 觸發(fā)器和一個(gè) BEFORE INSERT 觸發(fā)器沦泌,或一個(gè) BEFORE UPDATE 觸發(fā)器和一個(gè) AFTER UPDATE 觸發(fā)器。
  5. 觸發(fā)器主體:觸發(fā)器動(dòng)作主體辛掠,包含觸發(fā)器激活時(shí)將要執(zhí)行的 MySQL 語(yǔ)句谢谦。如果要執(zhí)行多個(gè)語(yǔ)句,可使用 BEGIN…END 復(fù)合語(yǔ)句結(jié)構(gòu)公浪。
  6. FOR EACH ROW:一般是指行級(jí)觸發(fā),對(duì)于受觸發(fā)事件影響的每一行都要激活觸發(fā)器的動(dòng)作船侧。例如欠气,使用 INSERT 語(yǔ)句向某個(gè)表中插入多行數(shù)據(jù)時(shí),觸發(fā)器會(huì)對(duì)每一行數(shù)據(jù)的插入都執(zhí)行相應(yīng)的觸發(fā)器動(dòng)作镜撩。

注意:每個(gè)表都支持 INSERT预柒、UPDATE 和 DELETE 的 BEFORE 與 AFTER,因此每個(gè)表最多支持 6 個(gè)觸發(fā)器袁梗。每個(gè)表的每個(gè)事件每次只允許有一個(gè)觸發(fā)器宜鸯。單一觸發(fā)器不能與多個(gè)事件或多個(gè)表關(guān)聯(lián)。

另外遮怜,在 MySQL 中淋袖,若需要查看數(shù)據(jù)庫(kù)中已有的觸發(fā)器,則可以使用 SHOW TRIGGERS 語(yǔ)句锯梁。

創(chuàng)建 BEFORE 類型觸發(fā)器

在 test_db 數(shù)據(jù)庫(kù)中即碗,數(shù)據(jù)表 tb_emp8 為員工信息表,包含 id陌凳、name剥懒、deptId 和 salary 字段,數(shù)據(jù)表 tb_emp8 的表結(jié)構(gòu)如下所示合敦。

mysql> SELECT * FROM tb_emp8;
Empty set (0.07 sec)
mysql> DESC tb_emp8;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id     | int(11)     | NO   | PRI | NULL    |       |
| name   | varchar(22) | YES  | UNI | NULL    |       |
| deptId | int(11)     | NO   | MUL | NULL    |       |
| salary | float       | YES  |     | 0       |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.05 sec)

【實(shí)例 1】創(chuàng)建一個(gè)名為 SumOfSalary 的觸發(fā)器初橘,觸發(fā)的條件是向數(shù)據(jù)表 tb_emp8 中插入數(shù)據(jù)之前,對(duì)新插入的 salary 字段值進(jìn)行求和計(jì)算充岛。輸入的 SQL 語(yǔ)句和執(zhí)行過程如下所示保檐。

mysql> CREATE TRIGGER SumOfSalary
    -> BEFORE INSERT ON tb_emp8
    -> FOR EACH ROW
    -> SET @sum=@sum+NEW.salary;
Query OK, 0 rows affected (0.35 sec)

觸發(fā)器 SumOfSalary 創(chuàng)建完成之后,向表 tb_emp8 中插入記錄時(shí)崔梗,定義的 sum 值由 0 變成了 1500澜汤,即插入值 1000 和 500 的和,如下所示得滤。

SET @sum=0;
Query OK, 0 rows affected (0.05 sec)
mysql> INSERT INTO tb_emp8
    -> VALUES(1,'A',1,1000),(2,'B',1,500);
Query OK, 2 rows affected (0.09 sec)
Records: 2  Duplicates: 0  Warnings: 0
mysql> SELECT @sum;
+------+
| @sum |
+------+
| 1500 |
+------+
1 row in set (0.03 sec)

創(chuàng)建 AFTER 類型觸發(fā)器

在 test_db 數(shù)據(jù)庫(kù)中,數(shù)據(jù)表 tb_emp6 和 tb_emp7 都為員工信息表爪膊,包含 id、name砸王、deptId 和 salary 字段推盛,數(shù)據(jù)表 tb_emp6 和 tb_emp7 的表結(jié)構(gòu)如下所示。

mysql> SELECT * FROM tb_emp6;
Empty set (0.07 sec)
mysql> SELECT * FROM tb_emp7;
Empty set (0.03 sec)
mysql> DESC tb_emp6;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id     | int(11)     | NO   | PRI | NULL    |       |
| name   | varchar(25) | YES  |     | NULL    |       |
| deptId | int(11)     | YES  | MUL | NULL    |       |
| salary | float       | YES  |     | NULL    |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
mysql> DESC tb_emp7;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id     | int(11)     | NO   | PRI | NULL    |       |
| name   | varchar(25) | YES  |     | NULL    |       |
| deptId | int(11)     | YES  |     | NULL    |       |
| salary | float       | YES  |     | 0       |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.04 sec)

【實(shí)例 2】創(chuàng)建一個(gè)名為 double_salary 的觸發(fā)器谦铃,觸發(fā)的條件是向數(shù)據(jù)表 tb_emp6 中插入數(shù)據(jù)之后耘成,再向數(shù)據(jù)表 tb_emp7 中插入相同的數(shù)據(jù),并且 salary 為 tb_emp6 中新插入的 salary 字段值的 2 倍驹闰。輸入的 SQL 語(yǔ)句和執(zhí)行過程如下所示瘪菌。

mysql> CREATE TRIGGER double_salary
    -> AFTER INSERT ON tb_emp6
    -> FOR EACH ROW
    -> INSERT INTO tb_emp7
    -> VALUES (NEW.id,NEW.name,deptId,2*NEW.salary);
Query OK, 0 rows affected (0.25 sec)

觸發(fā)器 double_salary 創(chuàng)建完成之后,向表 tb_emp6 中插入記錄時(shí)嘹朗,同時(shí)向表 tb_emp7 中插入相同的記錄师妙,并且 salary 字段為 tb_emp6 中 salary 字段值的 2 倍,如下所示屹培。

mysql> INSERT INTO tb_emp6
    -> VALUES (1,'A',1,1000),(2,'B',1,500);
Query OK, 2 rows affected (0.09 sec)
Records: 2  Duplicates: 0  Warnings: 0
mysql> SELECT * FROM tb_emp6;
+----+------+--------+--------+
| id | name | deptId | salary |
+----+------+--------+--------+
|  1 | A    |      1 |   1000 |
|  2 | B    |      1 |    500 |
+----+------+--------+--------+
3 rows in set (0.04 sec)
mysql> SELECT * FROM tb_emp7;
+----+------+--------+--------+
| id | name | deptId | salary |
+----+------+--------+--------+
|  1 | A    |      1 |   2000 |
|  2 | B    |      1 |   1000 |
+----+------+--------+--------+
2 rows in set (0.06 sec)

MySQL查看觸發(fā)器

查看觸發(fā)器是指查看數(shù)據(jù)庫(kù)中已經(jīng)存在的觸發(fā)器的定義默穴、狀態(tài)和語(yǔ)法信息等。MySQL 中查看觸發(fā)器的方法包括 SHOW TRIGGERS 語(yǔ)句和查詢 information_schema 數(shù)據(jù)庫(kù)下的 triggers 數(shù)據(jù)表等褪秀。本節(jié)將詳細(xì)介紹這兩種查看觸發(fā)器的方法蓄诽。

SHOW TRIGGERS語(yǔ)句查看觸發(fā)器信息

在 MySQL 中,可以通過 SHOW TRIGGERS 語(yǔ)句來查看觸發(fā)器的基本信息媒吗,語(yǔ)法格式如下:

SHOW TRIGGERS;

對(duì)以上顯示信息的說明如下:

  • Trigger 表示觸發(fā)器的名稱仑氛,在這里觸發(fā)器的名稱為 trigupdate;
  • Event 表示激活觸發(fā)器的事件闸英,這里的觸發(fā)事件為更新操作 UPDATE调衰;
  • Table 表示激活觸發(fā)器的操作對(duì)象表,這里為 account 表自阱;
  • Statement 表示觸發(fā)器執(zhí)行的操作嚎莉,這里是向 myevent 數(shù)據(jù)表中插入一條數(shù)據(jù);
  • Timing 表示觸發(fā)器觸發(fā)的時(shí)間沛豌,這里為更新操作之后(AFTER)趋箩;
  • 還有一些其他信息,比如觸發(fā)器的創(chuàng)建時(shí)間加派、SQL 的模式叫确、觸發(fā)器的定義賬戶和字符集等,這里不再一一介紹芍锦。

SHOW TRIGGERS 語(yǔ)句用來查看當(dāng)前創(chuàng)建的所有觸發(fā)器的信息竹勉。因?yàn)樵撜Z(yǔ)句無(wú)法查詢指定的觸發(fā)器,所以在觸發(fā)器較少的情況下娄琉,使用該語(yǔ)句會(huì)很方便次乓。如果要查看特定觸發(fā)器的信息或者數(shù)據(jù)庫(kù)中觸發(fā)器較多時(shí)吓歇,可以直接從 information_schema 數(shù)據(jù)庫(kù)中的 triggers 數(shù)據(jù)表中查找。

在triggers表中查看觸發(fā)器信息

在 MySQL 中票腰,所有觸發(fā)器的信息都存在 information_schema 數(shù)據(jù)庫(kù)的 triggers 表中城看,可以通過查詢命令 SELECT 來查看,具體的語(yǔ)法如下:

SELECT * FROM information_schema.triggers WHERE trigger_name= '觸發(fā)器名';

其中杏慰,'觸發(fā)器名'用來指定要查看的觸發(fā)器的名稱测柠,需要用單引號(hào)引起來。這種方式可以查詢指定的觸發(fā)器缘滥,使用起來更加方便轰胁、靈活。

示例 2

下面使用 SELECT 命令查看 trigupdate 觸發(fā)器朝扼,SQL 語(yǔ)句如下:

SELECT * FROM information_schema.triggers WHERE TRIGGER_NAME= 'trigupdate'\G

顯示信息的說明如下:

  • TRIGGER_SCHEMA 表示觸發(fā)器所在的數(shù)據(jù)庫(kù)赃阀;
  • TRIGGER_NAME 表示觸發(fā)器的名稱;
  • EVENT_OBJECT_TABLE 表示在哪個(gè)數(shù)據(jù)表上觸發(fā)吟税;
  • ACTION_STATEMENT 表示觸發(fā)器觸發(fā)的時(shí)候執(zhí)行的具體操作凹耙;
  • ACTION_ORIENTATION 的值為 ROW姿现,表示在每條記錄上都觸發(fā)肠仪;
  • ACTION_TIMING 表示觸發(fā)的時(shí)刻是 AFTER;
  • 還有一些其他信息备典,比如觸發(fā)器的創(chuàng)建時(shí)間异旧、SQL 的模式、觸發(fā)器的定義賬戶和字符集等提佣,這里不再一一介紹吮蛹。

上述 SQL 語(yǔ)句也可以不指定觸發(fā)器名稱,這樣將查看所有的觸發(fā)器拌屏,SQL 語(yǔ)句如下:

SELECT * FROM information_schema.triggers \G

這個(gè)語(yǔ)句會(huì)顯示 triggers 數(shù)據(jù)表中所有的觸發(fā)器信息潮针。

MySQL修改和刪除觸發(fā)器

修改觸發(fā)器可以通過刪除原觸發(fā)器,再以相同的名稱創(chuàng)建新的觸發(fā)器倚喂。

基本語(yǔ)法

與其他 MySQL 數(shù)據(jù)庫(kù)對(duì)象一樣每篷,可以使用 DROP 語(yǔ)句將觸發(fā)器從數(shù)據(jù)庫(kù)中刪除。

語(yǔ)法格式如下:

DROP TRIGGER [ IF EXISTS ] [數(shù)據(jù)庫(kù)名] <觸發(fā)器名>

語(yǔ)法說明如下:

  1. 觸發(fā)器名:要?jiǎng)h除的觸發(fā)器名稱端圈。
  2. 數(shù)據(jù)庫(kù)名:可選項(xiàng)焦读。指定觸發(fā)器所在的數(shù)據(jù)庫(kù)的名稱。若沒有指定舱权,則為當(dāng)前默認(rèn)的數(shù)據(jù)庫(kù)矗晃。
  3. 權(quán)限:執(zhí)行 DROP TRIGGER 語(yǔ)句需要 SUPER 權(quán)限。
  4. IF EXISTS:可選項(xiàng)宴倍。避免在沒有觸發(fā)器的情況下刪除觸發(fā)器张症。

注意:刪除一個(gè)表的同時(shí)仓技,也會(huì)自動(dòng)刪除該表上的觸發(fā)器。另外吠冤,觸發(fā)器不能更新或覆蓋浑彰,為了修改一個(gè)觸發(fā)器,必須先刪除它拯辙,再重新創(chuàng)建郭变。

刪除觸發(fā)器

使用 DROP TRIGGER 語(yǔ)句可以刪除 MySQL 中已經(jīng)定義的觸發(fā)器。

【實(shí)例】刪除 double_salary 觸發(fā)器涯保,輸入的 SQL 語(yǔ)句和執(zhí)行過程如下所示诉濒。

mysql> DROP TRIGGER double_salary;
Query OK, 0 rows affected (0.03 sec)

Event事件(定時(shí)任務(wù))是什么

在數(shù)據(jù)庫(kù)管理中,經(jīng)常要周期性的執(zhí)行某一命令或 SQL 語(yǔ)句夕春,于是 MySQL 5.1 版本以后就提供了事件未荒,它可以很方便的實(shí)現(xiàn) MySQL 數(shù)據(jù)庫(kù)的計(jì)劃任務(wù),定期運(yùn)行指定命令及志,使用起來非常簡(jiǎn)單方便片排。

事件(Event)也可稱為事件調(diào)度器(Event Scheduler),是用來執(zhí)行定時(shí)任務(wù)的一組 SQL 集合速侈,可以通俗理解成 MySQL 中的定時(shí)器率寡。一個(gè)事件可調(diào)用一次,也可周期性的啟動(dòng)倚搬。

事件可以作為定時(shí)任務(wù)調(diào)度器冶共,取代部分原來只能用操作系統(tǒng)的計(jì)劃任務(wù)才能執(zhí)行的工作。另外每界,更值得一提的是捅僵,MySQL 的事件可以實(shí)現(xiàn)每秒鐘執(zhí)行一個(gè)任務(wù),非常適合對(duì)實(shí)時(shí)性要求較高的環(huán)境眨层,而操作系統(tǒng)的計(jì)劃任務(wù)只能精確到每分鐘一次庙楚。

事件和觸發(fā)器類似,都是在某些事情發(fā)生時(shí)啟動(dòng)趴樱。當(dāng)數(shù)據(jù)庫(kù)啟動(dòng)一條語(yǔ)句的時(shí)候馒闷,觸發(fā)器就啟動(dòng)了,而事件是根據(jù)調(diào)度事件來啟動(dòng)的伊佃。由于他們彼此相似窜司,所以事件也稱為臨時(shí)性觸發(fā)器。

查看事件是否開啟

在 MySQL 中航揉,調(diào)度器 event_scheduler 負(fù)責(zé)調(diào)用事件塞祈。我們可以通過以下幾種命令查看事件是否開啟,一般情況下默認(rèn)值為 OFF帅涂。SQL 命令和運(yùn)行結(jié)果如下:

mysql> SHOW VARIABLES LIKE 'event_scheduler';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| event_scheduler | OFF   |
+-----------------+-------+
1 row in set, 1 warning (0.02 sec)

mysql> SELECT @@event_scheduler;
+-------------------+
| @@event_scheduler |
+-------------------+
| OFF               |
+-------------------+
1 row in set (0.00 sec)

mysql> SHOW PROCESSLIST;
+----+------+-----------------+------+---------+------+----------+------------------+
| Id | User | Host            | db   | Command | Time | State    | Info             |
+----+------+-----------------+------+---------+------+----------+------------------+
|  2 | root | localhost:56279 | NULL | Query   |    0 | starting | SHOW PROCESSLIST |
+----+------+-----------------+------+---------+------+----------+------------------+
1 row in set (0.01 sec)

從結(jié)果可以看出议薪,事件沒有開啟尤蛮。因?yàn)閰?shù) event_scheduler 的值為 OFF,并且在 PROCESSLIST 中查看不到 event_scheduler 的信息斯议。如果參數(shù) event_scheduler 的值為 ON产捞,或者在 PROCESSLIST 中顯示了 event_scheduler 的信息,則說明事件已經(jīng)開啟哼御。

開啟事件

開啟事件主要通過以下兩種方式實(shí)現(xiàn)坯临。

通過設(shè)置全局參數(shù)修改

可以使用 SET GLOBAL 命令設(shè)定全局變量 event_scheduler 的值,開啟或關(guān)閉事件恋昼。將 event_scheduler 參數(shù)的值設(shè)置為 ON看靠,表示開啟事件;設(shè)置為 OFF液肌,則關(guān)閉事件挟炬。

例如,要開啟事件可以在命令行窗口中輸入以下命令嗦哆。

mysql> SET GLOBAL event_scheduler = ON ;
Query OK, 0 rows affected (0.06 sec)

mysql> SHOW VARIABLES LIKE 'event_scheduler';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| event_scheduler | ON    |
+-----------------+-------+
1 row in set, 1 warning (0.01 sec)

結(jié)果顯示谤祖,event_scheduler 的值為 ON,表示事件已經(jīng)開啟老速。

通過 SET GLOBAL 命令開啟或關(guān)閉事件粥喜,MySQL 重啟服務(wù)后事件又會(huì)回到原來的狀態(tài),如果想要始終開啟或關(guān)閉事件烁峭,可以修改 MySQL 配置文件容客。

更改配置文件

在 MySQL 配置文件中找到 [mysqld] 選項(xiàng)秕铛,然后在下面添加以下代碼開啟事件约郁。

event_scheduler = ON

在配置文件中添加代碼并保存文件后,重啟 MySQL 服務(wù)才能生效但两。

通過該方法開啟或關(guān)閉事件鬓梅,重啟 MySQL 服務(wù)后,不會(huì)回到原來的狀態(tài)谨湘。例如绽快,此時(shí)重啟 MySQL 服務(wù)器,然后查看事件是否開啟紧阔。

mysql> SHOW VARIABLES LIKE 'event_scheduler';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| event_scheduler | ON    |
+-----------------+-------+
1 row in set, 1 warning (0.01 sec)

結(jié)果顯示坊罢,參數(shù) event_scheduler 的值為 ON,表示已經(jīng)開啟擅耽。

MySQL創(chuàng)建事件

在 MySQL 中活孩,可以通過 CREATE EVENT 語(yǔ)句來創(chuàng)建事件,其語(yǔ)法格式如下:

CREATE EVENT [IF NOT EXISTS] event_name
  ON SCHEDULE schedule
  [ON COMPLETION [NOT] PRESERVE]
  [ENABLE | DISABLE | DISABLE ON SLAVE]
  [COMMENT 'comment']
  DO event_body;

從上面的語(yǔ)法可以看出乖仇,CRATE EVENT 語(yǔ)句由多個(gè)子句組成憾儒,各子句的詳細(xì)說明如下表所示询兴。

子句 說明
DEFINER 可選 用于定義事件執(zhí)行時(shí)檢查權(quán)限的用戶
IF NOT EXISTS 可選 用于判斷要?jiǎng)?chuàng)建的事件是否存在
EVENT event_name 必選 用于指定事件名稱,event_name 的最大長(zhǎng)度為 64 個(gè)字符 如果未指定 event_name起趾,則默認(rèn)為當(dāng)前的 MySQL 用戶名(不區(qū)分大小寫)
ON SCHEDULE schedule 必選 用于定義執(zhí)行的時(shí)間和時(shí)間間隔 schedule 表示觸發(fā)點(diǎn)
ON COMPLETION [NOT] PRESERVE 可選 用于定義事件是否循環(huán)執(zhí)行诗舰,即是一次執(zhí)行還是永久執(zhí)行,默認(rèn)為一次執(zhí)行训裆,即 NOT PRESERVE
ENABLE | DISABLE | DISABLE ON SLAVE 可選眶根,用于指定事件的一種屬性。 其中边琉,關(guān)鍵字 ENABLE 表示該事件是活動(dòng)的汛闸,即調(diào)度器檢查事件是否必須調(diào)用; 關(guān)鍵字 DISABLE 表示該事件是關(guān)閉的艺骂,即事件的聲明存儲(chǔ)到目錄中诸老,但是調(diào)度器不會(huì)檢查它是否應(yīng)該調(diào)用; 關(guān)鍵字 DISABLE ON SLAVE 表示事件在從機(jī)中是關(guān)閉的钳恕。 如果不指定以上 3 個(gè)選項(xiàng)中的任何一個(gè)别伏,默認(rèn)為 ENABLE
COMMENT 'comment' 可選,用于定義事件的注釋
DO event_body 必選 用于指定事件啟動(dòng)時(shí)所要執(zhí)行的代碼忧额,可以是任何有效的 SQL 語(yǔ)句厘肮、存儲(chǔ)過程或者一個(gè)計(jì)劃執(zhí)行的事件。 如果包含多條語(yǔ)句睦番,則可以使用 BEGIN..END 復(fù)合結(jié)構(gòu)

在 ON SCHEDULE 子句中类茂,參數(shù) schedule 的值為一個(gè) AT 子句,用于指定事件在某個(gè)時(shí)刻發(fā)生托嚣,其語(yǔ)法格式如下:

AT timestamp [+ INTERVAL interval]...
  | EVERY interval
  [STARTS timestamp [+ INTERVAL interval] ...]
  [ENDS timestamp[+ INTERVAL interval]...]

參數(shù)說明如下:

  • timestamp:一般用于只執(zhí)行一次巩检,表示一個(gè)具體的時(shí)間點(diǎn),后面加上一個(gè)時(shí)間間隔示启,表示在這個(gè)時(shí)間間隔后事件發(fā)生兢哭。
  • EVERY 子句:用于事件在指定時(shí)間區(qū)間內(nèi)每隔多長(zhǎng)時(shí)間發(fā)生一次,其中 STARTS 子句用于指定開始時(shí)間夫嗓;ENDS 子句用于指定結(jié)束時(shí)間迟螺。
  • interval:一般用于周期性執(zhí)行,表示一個(gè)從現(xiàn)在開始的時(shí)間舍咖,其值由一個(gè)數(shù)值和單位構(gòu)成矩父。例如,使用“4 WEEK”表示 4 周排霉,使用“'1:10'HOUR_MINUTE”表示 1 小時(shí) 10 分鐘窍株。間隔的長(zhǎng)短用 DATE_ADD() 函數(shù)支配。

interval 參數(shù)可以是以下值:

**YEAR** | QUARTER | **MONTH** | **DAY** | **HOUR** | **MINUTE** |
  WEEK | **SECOND** | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |
  DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND

一般情況下,不建議使用不標(biāo)準(zhǔn)(以上未加粗關(guān)鍵字)的時(shí)間單位夹姥。

例子:在 test 數(shù)據(jù)庫(kù)中創(chuàng)建一個(gè)名稱為 e_test 的事件杉武,用于每隔 5 秒向表 tb_eventtest 中插入一條數(shù)據(jù)。

創(chuàng)建 tb_eventtest 表辙售,SQL 語(yǔ)句和運(yùn)行結(jié)果如下:

mysql> CREATE TABLE tb_eventtest(
    -> id INT(11) PRIMARY KEY AUTO_INCREMENT,
    -> user VARCHAR(20),
    -> createtime DATETIME);
Query OK, 0 rows affected (0.07 sec)

創(chuàng)建 e_test 事件轻抱,SQL 語(yǔ)句和運(yùn)行結(jié)果如下:

mysql> CREATE EVENT IF NOT EXISTS e_test ON SCHEDULE EVERY 5 SECOND
    -> ON COMPLETION PRESERVE
    -> DO INSERT INTO tb_eventtest(user,createtime)VALUES('MySQL',NOW());
Query OK, 0 rows affected (0.04 sec)

創(chuàng)建事件后,查詢 tb_eventtest 中的數(shù)據(jù)旦部,SQL 語(yǔ)句和運(yùn)行結(jié)果如下:

mysql> SELECT * FROM tb_eventtest;
+----+-------+---------------------+
| id | user  | createtime          |
+----+-------+---------------------+
|  1 | MySQL | 2020-05-21 10:41:39 |
|  2 | MySQL | 2020-05-21 10:41:44 |
|  3 | MySQL | 2020-05-21 10:41:49 |
|  4 | MySQL | 2020-05-21 10:41:54 |
+----+-------+---------------------+
4 rows in set (0.01 sec)

從結(jié)果可以看出祈搜,系統(tǒng)每隔 5 秒插入一條數(shù)據(jù),這說明事件創(chuàng)建執(zhí)行成功了士八。

MySQL查看事件

創(chuàng)建好事件后容燕,用戶可以通過以下 3 種方式來查看事件的狀態(tài)信息:

  1. 查看 mysql.event
  2. 查看 information_schema.events
  3. 切換到相應(yīng)的數(shù)據(jù)庫(kù)后執(zhí)行 SHOW EVENTS;

查看 information_schema.events 表中的事件狀態(tài)信息。SQL 語(yǔ)句和運(yùn)行結(jié)果如下:

mysql> SELECT * FROM information_schema.events limit 1\G
*************************** 1. row ***************************
       EVENT_CATALOG: def
        EVENT_SCHEMA: test
          EVENT_NAME: e_test
             DEFINER: root@localhost
           TIME_ZONE: SYSTEM
          EVENT_BODY: SQL
    EVENT_DEFINITION: INSERT INTO tb_eventtest(user,createtime)VALUES('MySQL',NOW())
          EVENT_TYPE: RECURRING
          EXECUTE_AT: NULL
      INTERVAL_VALUE: 5
      INTERVAL_FIELD: SECOND
            SQL_MODE: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
              STARTS: 2020-05-21 10:41:39
                ENDS: NULL
              STATUS: ENABLED
       ON_COMPLETION: PRESERVE
             CREATED: 2020-05-21 10:41:39
        LAST_ALTERED: 2020-05-21 10:41:39
       LAST_EXECUTED: 2020-05-21 12:38:54
       EVENT_COMMENT:
          ORIGINATOR: 1
CHARACTER_SET_CLIENT: gbk
COLLATION_CONNECTION: gbk_chinese_ci
  DATABASE_COLLATION: utf8_unicode_ci
1 row in set (0.08 sec)

以上參數(shù)說明如下表所示:

參數(shù)名 說明
EVENT_CATALOG 事件存放目錄婚度,一般情況下蘸秘,值為 def,不建議修改
EVENT_SCHEMA 事件所在的數(shù)據(jù)庫(kù)
EVENT_NAME 事件名稱
DEFINER 事件的定義者
TIME_ZONE 事件使用的時(shí)區(qū)蝗茁,默認(rèn)是 SYSTEM醋虏,不建議修改
EVENT_BODY 一般情況下,值為 SQL哮翘,不建議修改
EVENT_DEFINITION 該事件的內(nèi)容颈嚼,可以是具體的 INSERT 等 SQL,也可以是一個(gè)調(diào)用的存儲(chǔ)過程
EVENT_TYPE 事件類型饭寺,這個(gè)參數(shù)比較重要阻课,在定義時(shí)指定 有兩個(gè)值:RECURRING 和 ONE TIME RECURRING 表示只要符合條件就會(huì)重復(fù)執(zhí)行,RECURRING 類型的事件一般為 NULL艰匙,表示該事件的預(yù)計(jì)執(zhí)行時(shí)間 ONE TIME 只會(huì)調(diào)用 EXECUTE_AT限煞,針對(duì) one-time 類型的事件有效
INTERVAL_VALUE 針對(duì) RECURRING 類型的事件有效,表示執(zhí)行間隔長(zhǎng)度
INTERVAL_FIELD 針對(duì) RECURRING 類型的事件有效旬薯,表示執(zhí)行間隔的單位晰骑,一般是 SECOND适秩,DAY 等值绊序,可參考創(chuàng)建語(yǔ)法
SQL_MODE 當(dāng)前事件采用的 SQL_MODE
STARTS 針對(duì) RECURRING 類型的事件有效,表示一個(gè)事件從哪個(gè)時(shí)間點(diǎn)開始執(zhí)行秽荞,和 one-time 的 EXECUTE_AT 功能類似骤公。 為 NULL 時(shí)表示一符合條件就開始執(zhí)行
ENDS 針對(duì) RECURRING 類型的事件有效,表示一個(gè)事件到了哪個(gè)時(shí)間點(diǎn)后不再執(zhí)行扬跋,如果為 NULL 就是永不停止
STATUS 一般有三個(gè)值阶捆,ENABLED、DISABLED 和 SLAVESIDE_DISABLED
ON_COMPLETION 只有兩個(gè)值,PRESERVE 和 NOT PRESERVE
CREATED 事件的創(chuàng)建時(shí)間
LAST_ALTERED 事件最近一次被修改的時(shí)間
LAST_EXECUTED 事件最近一次執(zhí)行的時(shí)間洒试,如果為 NULL 表示從未執(zhí)行過
EVENT_COMMENT 事件的注釋信息
ORIGINATOR 當(dāng)前事件創(chuàng)建時(shí)的 server-id倍奢,用于主從上的處理,比如 SLAVESIDE_DISABLED
CHARACTER_SET_CLIENT 事件創(chuàng)建時(shí)的客戶端字符集
COLLATION_CONNECTION 事件創(chuàng)建時(shí)的連接字符校驗(yàn)規(guī)則
DATABASE_COLLATION 事件創(chuàng)建時(shí)的數(shù)據(jù)庫(kù)字符集校驗(yàn)規(guī)則

MySQL修改和刪除事件

修改事件

在 MySQL 中垒棋,事件創(chuàng)建之后卒煞,可以使用 ALTER EVENT 語(yǔ)句修改其定義和相關(guān)屬性。

修改事件的語(yǔ)法格式如下:

ALTER EVENT event_name
  ON SCHEDULE schedule
  [ON COMPLETION [NOT] PRESERVE]
  [ENABLE | DISABLE | DISABLE ON SLAVE]
  [COMMENT 'comment']
  DO event_body;

ALTER EVENT 語(yǔ)句還有一個(gè)用法就是讓一個(gè)事件關(guān)閉或再次讓其活動(dòng)叼架。

例子:修改 e_test 事件畔裕,讓其每隔 30 秒向表 tb_eventtest 中插入一條數(shù)據(jù),SQL 語(yǔ)句和運(yùn)行結(jié)果如下所示:

mysql> ALTER EVENT e_test ON SCHEDULE EVERY 30 SECOND
    -> ON COMPLETION PRESERVE
    -> DO INSERT INTO tb_eventtest(user,createtime) VALUES('MySQL',NOW());
Query OK, 0 rows affected (0.04 sec)

mysql> TRUNCATE TABLE tb_eventtest;
Query OK, 0 rows affected (0.04 sec)

mysql> SELECT * FROM tb_eventtest;
+----+-------+---------------------+
| id | user  | createtime          |
+----+-------+---------------------+
|  1 | MySQL | 2020-05-21 13:23:49 |
|  2 | MySQL | 2020-05-21 13:24:19 |
+----+-------+---------------------+
2 rows in set (0.00 sec)

由結(jié)果可以看出乖订,修改事件后扮饶,表 tb_eventtest 中的數(shù)據(jù)由原來的每 5 秒插入一條,變?yōu)槊?30 秒插入一條乍构。

使用 ALTER EVENT 語(yǔ)句還可以臨時(shí)關(guān)閉一個(gè)已經(jīng)創(chuàng)建的事件甜无。

例子:臨時(shí)關(guān)閉事件 e_test 的具體代碼如下所示:

mysql> ALTER EVENT e_test DISABLE;
Query OK, 0 rows affected (0.00 sec)

查詢 tb_eventtest 表中的數(shù)據(jù),SQL 語(yǔ)句如下:

SELECT * FROM tb_eventtest;

為了確定事件已關(guān)閉哥遮,可以查詢兩次(每次間隔 1 分鐘)tb_eventtest 表的數(shù)據(jù)毫蚓,SQL 語(yǔ)句和運(yùn)行結(jié)果如下所示:

mysql> TRUNCATE TABLE tb_eventtest;
Query OK, 0 rows affected (0.05 sec)

mysql> SELECT * FROM tb_eventtest;
Empty set (0.00 sec)

mysql> SELECT * FROM tb_eventtest;
Empty set (0.00 sec)

由結(jié)果可以看出,臨時(shí)關(guān)閉事件后昔善,系統(tǒng)就不再繼續(xù)向表 tb_eventtest 中插入數(shù)據(jù)了元潘。

刪除事件

在 MySQL 中,可以使用 DROP EVENT 語(yǔ)句刪除已經(jīng)創(chuàng)建的事件君仆。語(yǔ)法格式如下:

DROP EVENT [IF EXISTS] event_name;

例子:刪除事件 e_test翩概,SQL 語(yǔ)句和運(yùn)行結(jié)果如下:

mysql> DROP EVENT IF EXISTS e_test;
Query OK, 0 rows affected (0.01 sec)

mysql> SELECT * FROM information_schema.events \G
Empty set (0.00 sec)

存儲(chǔ)函數(shù)詳解

存儲(chǔ)函數(shù)和存儲(chǔ)過程一樣,都是在數(shù)據(jù)庫(kù)中定義一些 SQL 語(yǔ)句的集合返咱。存儲(chǔ)函數(shù)可以通過 return 語(yǔ)句返回函數(shù)值钥庇,主要用于計(jì)算并返回一個(gè)值。而存儲(chǔ)過程沒有直接返回值咖摹,主要用于執(zhí)行操作评姨。

在 MySQL 中,使用 CREATE FUNCTION 語(yǔ)句來創(chuàng)建存儲(chǔ)函數(shù)萤晴,其語(yǔ)法形式如下:

CREATE FUNCTION sp_name ([func_parameter[...]])
RETURNS type
[characteristic ...] routine_body

其中:

  • sp_name 參數(shù):表示存儲(chǔ)函數(shù)的名稱吐句;
  • func_parameter:表示存儲(chǔ)函數(shù)的參數(shù)列表;
  • RETURNS type:指定返回值的類型店读;
  • characteristic 參數(shù):指定存儲(chǔ)函數(shù)的特性嗦枢,該參數(shù)的取值與存儲(chǔ)過程是一樣的;
  • routine_body 參數(shù):表示 SQL 代碼的內(nèi)容屯断,可以用 BEGIN...END 來標(biāo)示 SQL 代碼的開始和結(jié)束文虏。

注意:在具體創(chuàng)建函數(shù)時(shí)侣诺,函數(shù)名不能與已經(jīng)存在的函數(shù)名重名。除了上述要求外氧秘,推薦函數(shù)名命名(標(biāo)識(shí)符)為 function_xxx 或者 func_xxx年鸳。

func_parameter 可以由多個(gè)參數(shù)組成,其中每個(gè)參數(shù)由參數(shù)名稱和參數(shù)類型組成丸相,其形式如下:

[IN | OUT | INOUT] param_name type;

其中:

  • IN 表示輸入?yún)?shù)阻星,OUT 表示輸出參數(shù),INOUT 表示既可以輸入也可以輸出已添;
  • param_name 參數(shù)是存儲(chǔ)函數(shù)的參數(shù)名稱妥箕;
  • type 參數(shù)指定存儲(chǔ)函數(shù)的參數(shù)類型,該類型可以是 MySQL 數(shù)據(jù)庫(kù)的任意數(shù)據(jù)類型更舞。

創(chuàng)建函數(shù)與創(chuàng)建存儲(chǔ)過程一樣畦幢,需要通過命令 DELIMITER // 將 SQL 語(yǔ)句的結(jié)束符由“;”修改為“//”,最后通過命令 DELIMITER ; 將結(jié)束符號(hào)修改成 SQL 語(yǔ)句中默認(rèn)的結(jié)束符號(hào)缆蝉。

如果在存儲(chǔ)函數(shù)中的 RETURN 語(yǔ)句返回一個(gè)類型不同于函數(shù)的 RETURNS 子句中指定類型的值宇葱,返回值將被強(qiáng)制為恰當(dāng)?shù)念愋汀1热缈罚绻粋€(gè)函數(shù)返回一個(gè) ENUM 或 SET 值黍瞧,但是 RETURN 語(yǔ)句返回一個(gè)整數(shù),對(duì)于 SET 成員集的相應(yīng)的 ENUM 成員原杂,從函數(shù)返回的值是字符串印颤。

由于存儲(chǔ)函數(shù)和存儲(chǔ)過程的查看、修改穿肄、刪除等操作幾乎相同年局,所以我們不再詳細(xì)講解如何操作存儲(chǔ)函數(shù)了。

查看存儲(chǔ)函數(shù)的語(yǔ)法如下:

SHOW FUNCTION STATUS LIKE 存儲(chǔ)函數(shù)名;
SHOW CREATE FUNCTION 存儲(chǔ)函數(shù)名;
SELECT * FROM information_schema.Routines WHERE ROUTINE_NAME=存儲(chǔ)函數(shù)名;

可以發(fā)現(xiàn)咸产,操作存儲(chǔ)函數(shù)和操作存儲(chǔ)過程不同的是將 PROCEDURE 替換成了 FUNCTION矢否。同樣,修改存儲(chǔ)函數(shù)的語(yǔ)法如下:

ALTER FUNCTION 存儲(chǔ)函數(shù)名 [ 特征 ... ]

存儲(chǔ)函數(shù)的特征與存儲(chǔ)過程的基本一樣。

刪除存儲(chǔ)過程的語(yǔ)法如下:

DROP FUNCTION [ IF EXISTS ] <函數(shù)名>

MySQL調(diào)用存儲(chǔ)過程和函數(shù)

存儲(chǔ)過程和存儲(chǔ)函數(shù)都是存儲(chǔ)在服務(wù)器端的 SQL 語(yǔ)句集合。要想使用這些已經(jīng)定義好的存儲(chǔ)過程和存儲(chǔ)函數(shù)就必須要通過調(diào)用的方式來實(shí)現(xiàn)趟佃。

存儲(chǔ)過程通過 CALL 語(yǔ)句來調(diào)用,存儲(chǔ)函數(shù)的使用方法與 MySQL 內(nèi)部函數(shù)的使用方法相同亿絮。執(zhí)行存儲(chǔ)過程和存儲(chǔ)函數(shù)需要擁有 EXECUTE 權(quán)限(EXECUTE 權(quán)限的信息存儲(chǔ)在 information_schema 數(shù)據(jù)庫(kù)下的 USER_PRIVILEGES 表中)。

調(diào)用存儲(chǔ)過程

MySQL 中使用 CALL 語(yǔ)句來調(diào)用存儲(chǔ)過程。調(diào)用存儲(chǔ)過程后,數(shù)據(jù)庫(kù)系統(tǒng)將執(zhí)行存儲(chǔ)過程中的 SQL 語(yǔ)句壶谒,然后將結(jié)果返回給輸出值。

CALL 語(yǔ)句接收存儲(chǔ)過程的名字以及需要傳遞給它的任意參數(shù)膳沽,基本語(yǔ)法形式如下:

CALL sp_name([parameter[...]]);

其中,sp_name 表示存儲(chǔ)過程的名稱,parameter 表示存儲(chǔ)過程的參數(shù)挑社。

因?yàn)榇鎯?chǔ)過程實(shí)際上也是一種函數(shù)陨界,所以存儲(chǔ)過程名后需要有( )符號(hào),即使不傳遞參數(shù)也需要痛阻。

調(diào)用存儲(chǔ)函數(shù)

在 MySQL 中菌瘪,存儲(chǔ)函數(shù)的使用方法與 MySQL 內(nèi)部函數(shù)的使用方法是一樣的。換言之阱当,用戶自己定義的存儲(chǔ)函數(shù)與 MySQL 內(nèi)部函數(shù)是一個(gè)性質(zhì)的俏扩。區(qū)別在于,存儲(chǔ)函數(shù)是用戶自己定義的弊添,而內(nèi)部函數(shù)是 MySQL 開發(fā)者定義的录淡。

MySQL變量的定義和賦值

在 MySQL 中,除了支持標(biāo)準(zhǔn)的存儲(chǔ)過程和函數(shù)外油坝,還引入了表達(dá)式嫉戚。表達(dá)式與其它高級(jí)語(yǔ)言的表達(dá)式一樣,由變量澈圈、運(yùn)算符和流程控制來構(gòu)成彬檀。

變量是表達(dá)式語(yǔ)句中最基本的元素,可以用來臨時(shí)存儲(chǔ)數(shù)據(jù)瞬女。在存儲(chǔ)過程和函數(shù)中都可以定義和使用變量窍帝。用戶可以使用 DECLARE 關(guān)鍵字來定義變量,定義后可以為變量賦值诽偷。這些變量的作用范圍是 BEGIN...END 程序段中盯桦。

定義變量

MySQL 中可以使用 DECLARE 關(guān)鍵字來定義變量,其基本語(yǔ)法如下:

DECLARE var_name[,...] type [DEFAULT value]

其中:

  • DECLARE 關(guān)鍵字是用來聲明變量的渤刃;
  • var_name 參數(shù)是變量的名稱拥峦,這里可以同時(shí)定義多個(gè)變量;
  • type 參數(shù)用來指定變量的類型卖子;
  • DEFAULT value 子句將變量默認(rèn)值設(shè)置為 value略号,沒有使用 DEFAULT 子句時(shí),默認(rèn)值為 NULL洋闽。

為變量賦值

MySQL 中可以使用 SET 關(guān)鍵字來為變量賦值玄柠,SET 語(yǔ)句的基本語(yǔ)法如下:

SET var_name = expr[,var_name = expr]...

其中:

  • SET 關(guān)鍵字用來為變量賦值;
  • var_name 參數(shù)是變量的名稱诫舅;
  • expr 參數(shù)是賦值表達(dá)式羽利。

注意:一個(gè) SET 語(yǔ)句可以同時(shí)為多個(gè)變量賦值,各個(gè)變量的賦值語(yǔ)句之間用逗號(hào)隔開刊懈。

MySQL 中還可以使用 SELECT..INTO 語(yǔ)句為變量賦值这弧。其基本語(yǔ)法如下:

SELECT col_name [...] INTO var_name[,...]
FROM table_name WEHRE condition

其中:

  • col_name 參數(shù)表示查詢的字段名稱娃闲;
  • var_name 參數(shù)是變量的名稱;
  • table_name 參數(shù)指表的名稱匾浪;
  • condition 參數(shù)指查詢條件皇帮。

注意:當(dāng)將查詢結(jié)果賦值給變量時(shí),該查詢語(yǔ)句的返回結(jié)果只能是單行蛋辈。

MySQL定義條件和處理程序

在程序的運(yùn)行過程中可能會(huì)遇到問題属拾,此時(shí)我們可以通過定義條件和處理程序來事先定義這些問題。

定義條件是指事先定義程序執(zhí)行過程中遇到的問題冷溶,處理程序定義了在遇到這些問題時(shí)應(yīng)當(dāng)采取的處理方式和解決辦法渐白,保證存儲(chǔ)過程和函數(shù)在遇到警告或錯(cuò)誤時(shí)能繼續(xù)執(zhí)行,從而增強(qiáng)程序處理問題的能力逞频,避免程序出現(xiàn)異常被停止執(zhí)行纯衍。

定義條件

MySQL 中可以使用 DECLARE 關(guān)鍵字來定義條件。其基本語(yǔ)法如下:

DECLARE condition_name CONDITION FOR condition_value
condition value:
SQLSTATE [VALUE] sqlstate_value | mysql_error_code

其中:

  • condition_name 參數(shù)表示條件的名稱虏劲;
  • condition_value 參數(shù)表示條件的類型托酸;
  • sqlstate_value 參數(shù)和 mysql_error_code 參數(shù)都可以表示 MySQL 的錯(cuò)誤。sqlstate_value 表示長(zhǎng)度為 5 的字符串類型錯(cuò)誤代碼柒巫,mysql_error_code 表示數(shù)值類型錯(cuò)誤代碼励堡。例如 ERROR 1146(42S02) 中,sqlstate_value 值是 42S02堡掏,mysql_error_code 值是 1146应结。

定義處理程序

MySQL 中可以使用 DECLARE 關(guān)鍵字來定義處理程序。其基本語(yǔ)法如下:

DECLARE handler_type HANDLER FOR condition_value[...] sp_statement
handler_type:
CONTINUE | EXIT | UNDO
condition_value:
SQLSTATE [VALUE] sqlstate_value | condition_name | SQLWARNING | NOT FOUND | SQLEXCEPTION | mysql_error_code

其中泉唁,handler_type 參數(shù)指明錯(cuò)誤的處理方式鹅龄,該參數(shù)有 3 個(gè)取值。這 3 個(gè)取值分別是 CONTINUE亭畜、EXIT 和 UNDO扮休。

  • CONTINUE 表示遇到錯(cuò)誤不進(jìn)行處理,繼續(xù)向下執(zhí)行拴鸵;
  • EXIT 表示遇到錯(cuò)誤后馬上退出玷坠;
  • UNDO 表示遇到錯(cuò)誤后撤回之前的操作,MySQL 中暫時(shí)還不支持這種處理方式劲藐。

注意:通常情況下八堡,執(zhí)行過程中遇到錯(cuò)誤應(yīng)該立刻停止執(zhí)行下面的語(yǔ)句,并且撤回前面的操作聘芜。但是兄渺,MySQL 中現(xiàn)在還不能支持 UNDO 操作因此汰现,遇到錯(cuò)誤時(shí)最好執(zhí)行 EXIT 操作挂谍。如果事先能夠預(yù)測(cè)錯(cuò)誤類型叔壤,并且進(jìn)行相應(yīng)的處理,那么可以執(zhí)行 CONTINUE 操作凳兵。

參數(shù)指明錯(cuò)誤類型百新,該參數(shù)有 6 個(gè)取值:

  • sqlstate_value:包含 5 個(gè)字符的字符串錯(cuò)誤值企软;
  • condition_name:表示 DECLARE 定義的錯(cuò)誤條件名稱庐扫;
  • SQLWARNING:匹配所有以 01 開頭的 sqlstate_value 值;
  • NOT FOUND:匹配所有以 02 開頭的 sqlstate_value 值仗哨;
  • SQLEXCEPTION:匹配所有沒有被 SQLWARNING 或 NOT FOUND 捕獲的 sqlstate_value 值形庭;
  • mysql_error_code:匹配數(shù)值類型錯(cuò)誤代碼。

sp_statement 參數(shù)為程序語(yǔ)句段厌漂,表示在遇到定義的錯(cuò)誤時(shí)萨醒,需要執(zhí)行的一些存儲(chǔ)過程或函數(shù)。

例子:下面是定義處理程序的幾種方式苇倡,代碼如下:

//方法一:捕獲 sqlstate_value
DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02' SET @info='CAN NOT FIND';

//方法二:捕獲 mysql_error_code
DECLARE CONTINUE HANDLER FOR 1146 SET @info='CAN NOT FIND';

//方法三:先定義條件富纸,然后調(diào)用
DECLARE can_not_find CONDITION FOR 1146;
DECLARE CONTINUE HANDLER FOR can_not_find SET @info='CAN NOT FIND';

//方法四:使用 SQLWARNING
DECLARE EXIT HANDLER FOR SQLWARNING SET @info='ERROR';

//方法五:使用 NOT FOUND
DECLARE EXIT HANDLER FOR NOT FOUND SET @info='CAN NOT FIND';

//方法六:使用 SQLEXCEPTION
DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @info='ERROR';

上述代碼是 6 種定義處理程序的方法。

  1. 捕獲 sqlstate_value 值旨椒。如果遇到 sqlstate_value 值為 42S02晓褪,執(zhí)行 CONTINUE 操作,并且輸出“CAN NOT FIND”信息综慎。
  2. 捕獲 mysql_error_code 值涣仿。如果遇到 mysql_error_code 值為 1146, 執(zhí)行 CONTINUE 操作示惊,并且輸出“CAN NOT FIND”信息好港。
  3. 先定義條件,然后再調(diào)用條件米罚。這里先定義 can_not_find 條件钧汹,遇到 1146 錯(cuò)誤就執(zhí)行 CONTINUE 操作。
  4. 使用 SQLWARNING录择。SQLWARNING 捕獲所有以 01 開頭的 sqlstate_value 值拔莱,然后執(zhí)行 EXIT 操作,并且輸出“ERROR"信息糊肠。
  5. 使用 NOT FOUND辨宠。NOT FOUND 捕獲所有以 02 開頭的 sqlstate_value 值,然后執(zhí)行 EXIT 操作货裹,并且輸出“CAN NOT FIND”信息嗤形。
  6. 使用 SQLEXCEPTION。 SQLEXCEPTION 捕獲所有沒有被 SQLWARNING 或 NOT FOUND 捕獲的 sqlstate_value 值弧圆,然后執(zhí)行 EXIT 操作赋兵,并且輸出“ERROR”信息笔咽。

定義條件和處理順序,具體的執(zhí)行過程如下:

mysql> CREATE TABLE t8(s1 INT,PRIMARY KEY(s1));
Query OK, 0 rows affected (0.07 sec)

mysql> DELIMITER //
mysql> CREATE PROCEDURE handlerdemo()
    -> BEGIN
    -> DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @X2=1;
    -> SET @X=1;
    -> INSERT INTO t8 VALUES(1);
    -> SET @X=2;
    -> INSERT INTO t8 VALUES(1);
    -> SET @X=3;
    -> END //
Query OK, 0 rows affected (0.02 sec)

mysql> DELIMITER ;
mysql> CALL handlerdemo();
Query OK, 0 rows affected (0.01 sec)

mysql> SELECT @X;
+------+
| @X   |
+------+
|    3 |
+------+
1 row in set (0.00 sec)

上述代碼中霹期,@X 是一個(gè)用戶變量叶组,執(zhí)行結(jié)果 @X 等于 3,這表明 MySQL 執(zhí)行到程序的末尾历造。

如果DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @X2=1;這一行不存在甩十,第二個(gè) INSERT 因 PRIMARY KEY 約束而失敗之后,MySQL 可能已經(jīng)采取 EXIT 策略吭产,且 SELECT @X 可能已經(jīng)返回 2侣监。

注意:@X 表示用戶變量,使用 SET 語(yǔ)句為其賦值臣淤,用戶變量與連接有關(guān)橄霉,一個(gè)客戶端定義的變量不能被其他客戶端所使用,當(dāng)客戶端退出時(shí)邑蒋,該客戶端連接的所有變量將自動(dòng)釋放姓蜂。

MySQL游標(biāo)的定義及使用

在 MySQL 中,存儲(chǔ)過程或函數(shù)中的查詢有時(shí)會(huì)返回多條記錄医吊,而使用簡(jiǎn)單的 SELECT 語(yǔ)句钱慢,沒有辦法得到第一行、下一行或前十行的數(shù)據(jù)遮咖,這時(shí)可以使用游標(biāo)來逐條讀取查詢結(jié)果集中的記錄滩字。游標(biāo)在部分資料中也被稱為光標(biāo)。

關(guān)系數(shù)據(jù)庫(kù)管理系統(tǒng)實(shí)質(zhì)是面向集合的御吞,在 MySQL 中并沒有一種描述表中單一記錄的表達(dá)形式麦箍,除非使用 WHERE 子句來限制只有一條記錄被選中。所以有時(shí)我們必須借助于游標(biāo)來進(jìn)行單條記錄的數(shù)據(jù)處理陶珠。

一般通過游標(biāo)定位到結(jié)果集的某一行進(jìn)行數(shù)據(jù)修改挟裂。結(jié)果集是符合 SQL 語(yǔ)句的所有記錄的集合。

個(gè)人理解游標(biāo)就是一個(gè)標(biāo)識(shí)揍诽,用來標(biāo)識(shí)數(shù)據(jù)取到了什么地方诀蓉,可以把他理解成數(shù)組中的下標(biāo)。

不像多數(shù) DBMS暑脆,MySQL 游標(biāo)只能用于存儲(chǔ)過程和函數(shù)渠啤。

聲明游標(biāo)

MySQL 中使用 DECLARE 關(guān)鍵字來聲明游標(biāo),并定義相應(yīng)的 SELECT 語(yǔ)句添吗,根據(jù)需要添加 WHERE 和其它子句沥曹。其語(yǔ)法的基本形式如下:

DECLARE cursor_name CURSOR FOR select_statement;

其中,cursor_name 表示游標(biāo)的名稱;select_statement 表示 SELECT 語(yǔ)句妓美,可以返回一行或多行數(shù)據(jù)僵腺。

打開游標(biāo)

聲明游標(biāo)之后,要想從游標(biāo)中提取數(shù)據(jù)壶栋,必須首先打開游標(biāo)辰如。在 MySQL 中,打開游標(biāo)通過 OPEN 關(guān)鍵字來實(shí)現(xiàn)贵试,其語(yǔ)法格式如下:

OPEN cursor_name;

其中琉兜,cursor_name 表示所要打開游標(biāo)的名稱。需要注意的是锡移,打開一個(gè)游標(biāo)時(shí)呕童,游標(biāo)并不指向第一條記錄漆际,而是指向第一條記錄的前邊淆珊。

在程序中,一個(gè)游標(biāo)可以打開多次奸汇。用戶打開游標(biāo)后施符,其他用戶或程序可能正在更新數(shù)據(jù)表,所以有時(shí)會(huì)導(dǎo)致用戶每次打開游標(biāo)后擂找,顯示的結(jié)果都不同戳吝。

使用游標(biāo)

游標(biāo)順利打開后,可以使用 FETCH...INTO 語(yǔ)句來讀取數(shù)據(jù)贯涎,其語(yǔ)法形式如下:

FETCH cursor_name INTO var_name [,var_name]...

上述語(yǔ)句中听哭,將游標(biāo) cursor_name 中 SELECT 語(yǔ)句的執(zhí)行結(jié)果保存到變量參數(shù) var_name 中。變量參數(shù) var_name 必須在游標(biāo)使用之前定義塘雳。使用游標(biāo)類似高級(jí)語(yǔ)言中的數(shù)組遍歷陆盘,當(dāng)?shù)谝淮问褂糜螛?biāo)時(shí),此時(shí)游標(biāo)指向結(jié)果集的第一條記錄败明。

MySQL 的游標(biāo)是只讀的隘马,也就是說,你只能順序地從開始往后讀取結(jié)果集妻顶,不能從后往前酸员,也不能直接跳到中間的記錄。

關(guān)閉游標(biāo)

游標(biāo)使用完畢后讳嘱,要及時(shí)關(guān)閉幔嗦,在 MySQL 中,使用 CLOSE 關(guān)鍵字關(guān)閉游標(biāo)沥潭,其語(yǔ)法格式如下:

CLOSE cursor_name;

CLOSE 釋放游標(biāo)使用的所有內(nèi)部?jī)?nèi)存和資源邀泉,因此每個(gè)游標(biāo)不再需要時(shí)都應(yīng)該關(guān)閉。

在一個(gè)游標(biāo)關(guān)閉后叛氨,如果沒有重新打開呼渣,則不能使用它棘伴。但是,使用聲明過的游標(biāo)不需要再次聲明屁置,用 OPEN 語(yǔ)句打開它就可以了焊夸。

如果你不明確關(guān)閉游標(biāo),MySQL 將會(huì)在到達(dá) END 語(yǔ)句時(shí)自動(dòng)關(guān)閉它蓝角。游標(biāo)關(guān)閉之后阱穗,不能使用 FETCH 來使用該游標(biāo)。

MySQL流程控制語(yǔ)句詳解

在存儲(chǔ)過程和自定義函數(shù)中可以使用流程控制語(yǔ)句來控制程序的流程使鹅。MySQL 中流程控制語(yǔ)句有:IF 語(yǔ)句揪阶、CASE 語(yǔ)句、LOOP 語(yǔ)句患朱、LEAVE 語(yǔ)句鲁僚、ITERATE 語(yǔ)句、REPEAT 語(yǔ)句和 WHILE 語(yǔ)句等裁厅。

IF語(yǔ)句

IF 語(yǔ)句用來進(jìn)行條件判斷冰沙,根據(jù)是否滿足條件(可包含多個(gè)條件),來執(zhí)行不同的語(yǔ)句执虹,是流程控制中最常用的判斷語(yǔ)句拓挥。其語(yǔ)法的基本形式如下:

IF search_condition THEN statement_list
    [ELSEIF search_condition THEN statement_list]...
    [ELSE statement_list]
END IF

其中,search_condition 參數(shù)表示條件判斷語(yǔ)句袋励,如果返回值為 TRUE 侥啤,相應(yīng)的 SQL 語(yǔ)句列表(statement_list)被執(zhí)行;如果返回值為 FALSE茬故,則 ELSE 子句的語(yǔ)句列表被執(zhí)行盖灸。statement_list 可以包括一個(gè)或多個(gè)語(yǔ)句。

注意:MySQL 中的 IF( ) 函數(shù)不同于這里的 IF 語(yǔ)句均牢。

CASE語(yǔ)句

CASE 語(yǔ)句也是用來進(jìn)行條件判斷的糠雨,它提供了多個(gè)條件進(jìn)行選擇,可以實(shí)現(xiàn)比 IF 語(yǔ)句更復(fù)雜的條件判斷徘跪。CASE 語(yǔ)句的基本形式如下:

CASE case_value
    WHEN when_value THEN statement_list
    [WHEN when_value THEN statement_list]...
    [ELSE statement_list]
END CASE

其中:

  • case_value 參數(shù)表示條件判斷的變量甘邀,決定了哪一個(gè) WHEN 子句會(huì)被執(zhí)行;
  • when_value 參數(shù)表示變量的取值垮庐,如果某個(gè) when_value 表達(dá)式與 case_value 變量的值相同松邪,則執(zhí)行對(duì)應(yīng)的 THEN 關(guān)鍵字后的 statement_list 中的語(yǔ)句;
  • statement_list 參數(shù)表示 when_value 值沒有與 case_value 相同值時(shí)的執(zhí)行語(yǔ)句哨查。
  • CASE 語(yǔ)句都要使用 END CASE 結(jié)束逗抑。

CASE 語(yǔ)句還有另一種形式。該形式的語(yǔ)法如下:

CASE
    WHEN search_condition THEN statement_list
    [WHEN search_condition THEN statement_list] ...
    [ELSE statement_list]
END CASE

其中,search_condition 參數(shù)表示條件判斷語(yǔ)句邮府;statement_list 參數(shù)表示不同條件的執(zhí)行語(yǔ)句荧关。

與上述語(yǔ)句不同的是,該語(yǔ)句中的 WHEN 語(yǔ)句將被逐個(gè)執(zhí)行褂傀,直到某個(gè) search_condition 表達(dá)式為真忍啤,則執(zhí)行對(duì)應(yīng) THEN 關(guān)鍵字后面的 statement_list 語(yǔ)句。如果沒有條件匹配仙辟,ELSE 子句里的語(yǔ)句被執(zhí)行同波。

這里介紹的 CASE 語(yǔ)句與“控制流程函數(shù)”里描述的 SQL CASE 表達(dá)式的 CASE 語(yǔ)句有輕微的不同。這里的 CASE 語(yǔ)句不能有 ELSE NULL 語(yǔ)句叠国,并且用 END CASE 替代 END 來終止未檩。

LOOP 語(yǔ)句

LOOP 語(yǔ)句可以使某些特定的語(yǔ)句重復(fù)執(zhí)行。與 IF 和 CASE 語(yǔ)句相比粟焊,LOOP 只實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的循環(huán)冤狡,并不進(jìn)行條件判斷。

LOOP 語(yǔ)句本身沒有停止循環(huán)的語(yǔ)句吆玖,必須使用 LEAVE 語(yǔ)句等才能停止循環(huán)筒溃,跳出循環(huán)過程。LOOP 語(yǔ)句的基本形式如下:

[begin_label:]LOOP
    statement_list
END LOOP [end_label]

其中沾乘,begin_label 參數(shù)和 end_label 參數(shù)分別表示循環(huán)開始和結(jié)束的標(biāo)志,這兩個(gè)標(biāo)志必須相同浑测,而且都可以省略翅阵;statement_list 參數(shù)表示需要循環(huán)執(zhí)行的語(yǔ)句。

LEAVE 語(yǔ)句

LEAVE 語(yǔ)句主要用于跳出循環(huán)控制迁央。其語(yǔ)法形式如下:

LEAVE label

其中掷匠,label 參數(shù)表示循環(huán)的標(biāo)志,LEAVE 語(yǔ)句必須跟在循環(huán)標(biāo)志前面岖圈。

ITERATE 語(yǔ)句

ITERATE 是“再次循環(huán)”的意思讹语,用來跳出本次循環(huán),直接進(jìn)入下一次循環(huán)蜂科。ITERATE 語(yǔ)句的基本語(yǔ)法形式如下:

ITERATE label

其中顽决,label 參數(shù)表示循環(huán)的標(biāo)志,ITERATE 語(yǔ)句必須跟在循環(huán)標(biāo)志前面导匣。

說明:LEAVE 語(yǔ)句和 ITERATE 語(yǔ)句都用來跳出循環(huán)語(yǔ)句才菠,但兩者的功能是不一樣的。LEAVE 語(yǔ)句是跳出整個(gè)循環(huán)贡定,然后執(zhí)行循環(huán)后面的程序赋访。而 ITERATE 語(yǔ)句是跳出本次循環(huán),然后進(jìn)入下一次循環(huán)。使用這兩個(gè)語(yǔ)句時(shí)一定要區(qū)分清楚蚓耽。

REPEAT 語(yǔ)句

REPEAT 語(yǔ)句是有條件控制的循環(huán)語(yǔ)句渠牲,每次語(yǔ)句執(zhí)行完畢后,會(huì)對(duì)條件表達(dá)式進(jìn)行判斷步悠,如果表達(dá)式返回值為 TRUE嘱兼,則循環(huán)結(jié)束,否則重復(fù)執(zhí)行循環(huán)中的語(yǔ)句贤徒。

REPEAT 語(yǔ)句的基本語(yǔ)法形式如下:

[begin_label:] REPEAT
  statement_list
  UNTIL search_condition
END REPEAT [end_label]

其中:

  • begin_label 為 REPEAT 語(yǔ)句的標(biāo)注名稱芹壕,該參數(shù)可以省略;
  • REPEAT 語(yǔ)句內(nèi)的語(yǔ)句被重復(fù)接奈,直至 search_condition 返回值為 TRUE踢涌。
  • statement_list 參數(shù)表示循環(huán)的執(zhí)行語(yǔ)句;
  • search_condition 參數(shù)表示結(jié)束循環(huán)的條件序宦,滿足該條件時(shí)循環(huán)結(jié)束睁壁。
  • REPEAT 循環(huán)都用 END REPEAT 結(jié)束。

WHILE 語(yǔ)句

WHILE 語(yǔ)句也是有條件控制的循環(huán)語(yǔ)句互捌。WHILE 語(yǔ)句和 REPEAT 語(yǔ)句不同的是潘明,WHILE 語(yǔ)句是當(dāng)滿足條件時(shí),執(zhí)行循環(huán)內(nèi)的語(yǔ)句秕噪,否則退出循環(huán)钳降。WHILE 語(yǔ)句的基本語(yǔ)法形式如下:

[begin_label:] WHILE search_condition DO
  statement list
END WHILE [end label]

其中,search_condition 參數(shù)表示循環(huán)執(zhí)行的條件腌巾,滿足該條件時(shí)循環(huán)執(zhí)行遂填;statement_list 參數(shù)表示循環(huán)的執(zhí)行語(yǔ)句。WHILE 循環(huán)需要使用 END WHILE 來結(jié)束澈蝙。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末吓坚,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子灯荧,更是在濱河造成了極大的恐慌礁击,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逗载,死亡現(xiàn)場(chǎng)離奇詭異哆窿,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)撕贞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門更耻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人捏膨,你說我怎么就攤上這事秧均∈澄辏” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵目胡,是天一觀的道長(zhǎng)锯七。 經(jīng)常有香客問我,道長(zhǎng)誉己,這世上最難降的妖魔是什么眉尸? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮巨双,結(jié)果婚禮上噪猾,老公的妹妹穿的比我還像新娘。我一直安慰自己筑累,他們只是感情好袱蜡,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著慢宗,像睡著了一般坪蚁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上镜沽,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天敏晤,我揣著相機(jī)與錄音,去河邊找鬼缅茉。 笑死嘴脾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的宾舅。 我是一名探鬼主播统阿,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼筹我!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起茂附,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤的榛,失蹤者是張志新(化名)和其女友劉穎拌滋,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體岸夯,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年们妥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了猜扮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡监婶,死狀恐怖旅赢,靈堂內(nèi)的尸體忽然破棺而出齿桃,到底是詐尸還是另有隱情,我是刑警寧澤煮盼,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布短纵,位于F島的核電站,受9級(jí)特大地震影響僵控,放射性物質(zhì)發(fā)生泄漏香到。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一报破、第九天 我趴在偏房一處隱蔽的房頂上張望悠就。 院中可真熱鬧,春花似錦充易、人聲如沸梗脾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)藐唠。三九已至,卻和暖如春鹉究,著一層夾襖步出監(jiān)牢的瞬間宇立,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國(guó)打工自赔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留妈嘹,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓绍妨,卻偏偏與公主長(zhǎng)得像润脸,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子他去,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345