咱們在 MySQL 入門篇主要介紹了基本的 SQL 命令、數據類型和函數,在局部以上知識後,你就能夠進行 MySQL 的開發工做了,可是若是要成爲一個合格的開發人員,你還要具有一些更高級的技能,下面咱們就來探討一下 MySQL 都須要哪些高級的技能mysql
數據庫最核心的一點就是用來存儲數據,數據存儲就避免不了和磁盤打交道。那麼數據以哪一種方式進行存儲,如何存儲是存儲的關鍵所在。因此存儲引擎就至關因而數據存儲的發動機,來驅動數據在磁盤層面進行存儲。算法
MySQL 的架構能夠按照三層模式來理解sql
存儲引擎也是 MySQL 的組建,它是一種軟件,它所能作的和支持的功能主要有數據庫
MySQL 默認支持多種存儲引擎,來適用不一樣數據庫應用,用戶能夠根據須要選擇合適的存儲引擎,下面是 MySQL 支持的存儲引擎緩存
默認狀況下,若是建立表不指定存儲引擎,會使用默認的存儲引擎,若是要修改默認的存儲引擎,那麼就能夠在參數文件中設置 default-table-type
,可以查看當前的存儲引擎安全
show variables like 'table_type';
複製代碼
奇怪,爲何沒有了呢?網上求證一下,在 5.5.3 取消了這個參數服務器
能夠經過下面兩種方法查詢當前數據庫支持的存儲引擎session
show engines \g
複製代碼
在建立新表的時候,能夠經過增長 ENGINE
關鍵字設置新建表的存儲引擎。數據結構
create table cxuan002(id int(10),name varchar(20)) engine = MyISAM;
複製代碼
上圖咱們指定了 MyISAM
的存儲引擎。架構
若是你不知道表的存儲引擎怎麼辦?你能夠經過 show create table
來查看
若是不指定存儲引擎的話,從MySQL 5.1 版本以後,MySQL 的默認內置存儲引擎已是 InnoDB了。建一張表看一下
如上圖所示,咱們沒有指定默認的存儲引擎,下面查看一下表
能夠看到,默認的存儲引擎是 InnoDB
。
若是你的存儲引擎想要更換,可使用
alter table cxuan003 engine = myisam;
複製代碼
來更換,更換完成後回顯示 0 rows affected ,但其實已經操做成功
咱們使用 show create table
查看一下表的 sql 就知道
下面會介紹幾個經常使用的存儲引擎以及它的基本特性,這些存儲引擎是 **MyISAM、InnoDB、MEMORY 和 MERGE **
在 5.1 版本以前,MyISAM 是 MySQL 的默認存儲引擎,MyISAM 併發性比較差,使用的場景比較少,主要特色是
不支持事務
操做,ACID 的特性也就不存在了,這一設計是爲了性能和效率考慮的。
不支持外鍵
操做,若是強行增長外鍵,MySQL 不會報錯,只不過外鍵不起做用。
MyISAM 默認的鎖粒度是表級鎖
,因此併發性能比較差,加鎖比較快,鎖衝突比較少,不太容易發生死鎖的狀況。
MyISAM 會在磁盤上存儲三個文件,文件名和表名相同,擴展名分別是 .frm(存儲表定義)
、.MYD(MYData,存儲數據)
、MYI(MyIndex,存儲索引)
。這裏須要特別注意的是 MyISAM 只緩存索引文件
,並不緩存數據文件。
MyISAM 支持的索引類型有 全局索引(Full-Text)
、B-Tree 索引
、R-Tree 索引
Full-Text 索引:它的出現是爲了解決針對文本的模糊查詢效率較低的問題。
B-Tree 索引:全部的索引節點都按照平衡樹的數據結構來存儲,全部的索引數據節點都在葉節點
R-Tree索引:它的存儲方式和 B-Tree 索引有一些區別,主要設計用於存儲空間和多維數據的字段作索引,目前的 MySQL 版本僅支持 geometry 類型的字段做索引,相對於 BTREE,RTREE 的優點在於範圍查找。
數據庫所在主機若是宕機,MyISAM 的數據文件容易損壞,並且難以恢復。
增刪改查性能方面:SELECT 性能較高,適用於查詢較多的狀況
自從 MySQL 5.1 以後,默認的存儲引擎變成了 InnoDB 存儲引擎,相對於 MyISAM,InnoDB 存儲引擎有了較大的改變,它的主要特色是
可重複讀(repetable-read)
、經過MVCC(併發版本控制)
來實現的。可以解決髒讀
和不可重複讀
的問題。行級鎖
,併發性能比較好,會發生死鎖的狀況。.frm文件存儲表結構
定義,可是不一樣的是,InnoDB 的表數據與索引數據是存儲在一塊兒的,都位於 B+ 數的葉子節點上,而 MyISAM 的表數據和索引數據是分開的。MEMORY 存儲引擎使用存在內存中的內容來建立表。每一個 MEMORY 表實際只對應一個磁盤文件,格式是 .frm
。 MEMORY 類型的表訪問速度很快,由於其數據是存放在內存中。默認使用 HASH 索引
。
MERGE 存儲引擎是一組 MyISAM 表的組合,MERGE 表自己沒有數據,對 MERGE 類型的表進行查詢、更新、刪除的操做,其實是對內部的 MyISAM 表進行的。MERGE 表在磁盤上保留兩個文件,一個是 .frm
文件存儲表定義、一個是 .MRG
文件存儲 MERGE 表的組成等。
在實際開發過程當中,咱們每每會根據應用特色選擇合適的存儲引擎。
咱們會常常碰見的一個問題就是,在建表時如何選擇合適的數據類型,一般選擇合適的數據類型可以提升性能、減小沒必要要的麻煩,下面咱們就來一塊兒探討一下,如何選擇合適的數據類型。
char 和 varchar 是咱們常常要用到的兩個存儲字符串的數據類型,char 通常存儲定長的字符串,它屬於固定長度的字符類型,好比下面
值 | char(5) | 存儲字節 |
---|---|---|
'' | ' ' | 5個字節 |
'cx' | 'cx ' | 5個字節 |
'cxuan' | 'cxuan' | 5個字節 |
'cxuan007' | 'cxuan' | 5個字節 |
能夠看到,無論你的值寫的是什麼,一旦指定了 char 字符的長度,若是你的字符串長度不夠指定字符的長度的話,那麼就用空格來填補,若是超過字符串長度的話,只存儲指定字符長度的字符。
這裏注意一點:若是 MySQL 使用了非
嚴格模式
的話,上面表格最後一行是能夠存儲的。若是 MySQL 使用了嚴格模式
的話,那麼表格上面最後一行存儲會報錯。
若是使用了 varchar 字符類型,咱們來看一下例子
值 | varchar(5) | 存儲字節 |
---|---|---|
'' | '' | 1個字節 |
'cx' | 'cx ' | 3個字節 |
'cxuan' | 'cxuan' | 6個字節 |
'cxuan007' | 'cxuan' | 6個字節 |
能夠看到,若是使用 varchar 的話,那麼存儲的字節將根據實際的值進行存儲。你可能會疑惑爲何 varchar 的長度是 5 ,可是卻須要存儲 3 個字節或者 6 個字節,這是由於使用 varchar 數據類型進行存儲時,默認會在最後增長一個字符串長度,佔用1個字節(若是列聲明的長度超過255,則使用兩個字節)。varchar 不會填充空餘的字符串。
通常使用 char 來存儲定長的字符串,好比身份證號、手機號、郵箱等;使用 varchar 來存儲不定長的字符串。因爲 char 長度是固定的,因此它的處理速度要比 VARCHAR 快不少,可是缺點是浪費存儲空間,可是隨着 MySQL 版本的不斷演進,varchar 數據類型的性能也在不斷改進和提升,因此在許多應用中,VARCHAR 類型更多的被使用。
在 MySQL 中,不一樣的存儲引擎對 CHAR 和 VARCHAR 的使用原則也有不一樣
通常在保存較少的文本的時候,咱們會選擇 CHAR 和 VARCHAR,在保存大數據量的文本時,咱們每每選擇 TEXT 和 BLOB;TEXT 和 BLOB 的主要差異是 BLOB 可以保存二進制數據
;而 TEXT 只能保存字符數據
,TEXT 往下細分有
BLOB 往下細分有
三種,它們最主要的區別就是存儲文本長度不一樣和存儲字節不一樣,用戶應該根據實際狀況選擇知足需求的最小存儲類型,下面主要對 BLOB 和 TEXT 存在一些問題進行介紹
TEXT 和 BLOB 在刪除數據後會存在一些性能上的問題,爲了提升性能,建議使用 OPTIMIZE TABLE
功能對錶進行碎片整理。
也可使用合成索引來提升文本字段(BLOB 和 TEXT)的查詢性能。合成索引就是根據大文本(BLOB 和 TEXT)字段的內容創建一個散列值,把這個值存在對應列中,這樣就可以根據散列值查找到對應的數據行。通常使用散列算法好比 md5() 和 SHA1() ,若是散列算法生成的字符串帶有尾部空格,就不要把它們存在 CHAR 和 VARCHAR 中,下面咱們就來看一下這種使用方式
首先建立一張表,表中記錄 blob 字段和 hash 值
向 cxuan005 中插入數據,其中 hash 值做爲 info 的散列值。
而後再插入兩條數據
插入一條 info 爲 cxuan005 的數據
若是想要查詢 info 爲 cxuan005 的數據,能夠經過查詢 hash 列來進行查詢
這是合成索引的例子,若是要對 BLOB 進行模糊查詢的話,就要使用前綴索引。
其餘優化 BLOB 和 TEXT 的方式:
浮點數指的就是含有小數的值,浮點數插入到指定列中超過指定精度後,浮點數會四捨五入,MySQL 中的浮點數指的就是 float
和 double
,定點數指的是 decimal
,定點數可以更加精確的保存和顯示數據。下面經過一個示例講解一下浮點數精確性問題
首先建立一個表 cxuan006 ,只爲了測試浮點數問題,因此這裏咱們選擇的數據類型是 float
而後分別插入兩條數據
而後執行查詢,能夠看到查詢出來的兩條數據執行的舍入不一樣
爲了清晰的看清楚浮點數與定點數的精度問題,再來看一個例子
先修改 cxuan006 的兩個字段爲相同的長度和小數位數
而後插入兩條數據
執行查詢操做,能夠發現,浮點數相較於定點數來講,會產生偏差
在 MySQL 中,用來表示日期類型的有 DATE、TIME、DATETIME、TIMESTAMP,在
這篇文中介紹過了日期類型的區別,咱們這裏就再也不闡述了。下面主要介紹一下選擇
下面來認識一下 MySQL 字符集,簡單來講字符集就是一套文字符號和編碼、比較規則的集合。1960 年美國標準化組織 ANSI 發佈了第一個計算機字符集,就是著名的 ASCII(American Standard Code for Information Interchange)
。自從 ASCII 編碼後,每一個國家、國際組織都研究了一套本身的字符集,好比 ISO-8859-1
、GBK
等。
可是每一個國家都使用本身的字符集爲移植性帶來了很大的困難。因此,爲了統一字符編碼,國際標準化組織(ISO)
指定了統一的字符標準 - Unicode 編碼,它容納了幾乎全部的字符編碼。下面是一些常見的字符編碼
字符集 | 是否認長 | 編碼方式 |
---|---|---|
ASCII | 是 | 單字節 7 位編碼 |
ISO-8859-1 | 是 | 單字節 8 位編碼 |
GBK | 是 | 雙字節編碼 |
UTF-8 | 否 | 1 - 4 字節編碼 |
UTF-16 | 否 | 2 字節或 4 字節編碼 |
UTF-32 | 是 | 4 字節編碼 |
對數據庫來講,字符集是很重要的,由於數據庫存儲的數據大多數都是各類文字,字符集對數據庫的存儲、性能、系統的移植來講都很是重要。
MySQL 支持多種字符集,可使用 show character set;
來查看全部可用的字符集
或者使用
select character_set_name, default_collate_name, description, maxlen from information_schema.character_sets;
複製代碼
來查看。
使用 information_schema.character_set
來查看字符集和校對規則。
咱們上面介紹到了索引的幾種類型並對不一樣的索引類型作了闡述,闡明瞭優缺點等等,下面咱們從設計角度來聊一下索引,關於索引,你必需要知道的一點就是:索引是數據庫用來提升性能的最經常使用工具。
全部的 MySQL 類型均可以進行索引,對相關列使用索引是提升 SELECT
查詢性能的最佳途徑。MyISAM 和 InnoDB 都是使用 BTREE
做爲索引,MySQL 5 不支持函數索引
,可是支持 前綴索引
。
前綴索引顧名思義就是對列字段的前綴作索引,前綴索引的長度和存儲引擎有關係。MyISAM 前綴索引的長度支持到 1000 字節,InnoDB 前綴索引的長度支持到 767 字節,索引值重複性越低,查詢效率也就越高。
在 MySQL 中,主要有下面這幾種索引
全局索引(FULLTEXT)
:全局索引,目前只有 MyISAM 引擎支持全局索引,它的出現是爲了解決針對文本的模糊查詢效率較低的問題,而且只限於 CHAR、VARCHAR 和 TEXT 列。哈希索引(HASH)
:哈希索引是 MySQL 中用到的惟一 key-value 鍵值對的數據結構,很適合做爲索引。HASH 索引具備一次定位的好處,不須要像樹那樣逐個節點查找,可是這種查找適合應用於查找單個鍵的狀況,對於範圍查找,HASH 索引的性能就會很低。默認狀況下,MEMORY 存儲引擎使用 HASH 索引,但也支持 BTREE 索引。B-Tree 索引
:B 就是 Balance 的意思,BTree 是一種平衡樹,它有不少變種,最多見的就是 B+ Tree,它被 MySQL 普遍使用。R-Tree 索引
:R-Tree 在 MySQL 不多使用,僅支持 geometry 數據類型,支持該類型的存儲引擎只有MyISAM、BDb、InnoDb、NDb、Archive幾種,相對於 B-Tree 來講,R-Tree 的優點在於範圍查找。索引能夠在建立表的時候進行建立,也能夠單首創建,下面咱們採用單首創建的方式,咱們在 cxuan004 上建立前綴索引
咱們使用 explain
進行分析,能夠看到 cxuan004 使用索引的狀況
若是不想使用索引,能夠刪除索引,索引的刪除語法是
建立索引的時候,要儘可能考慮如下原則,便於提高索引的使用效率。
索引位置
,選擇索引最合適的位置是出如今 where
語句中的列,而不是 select
關鍵字後的選擇列表中的列。惟一索引
,顧名思義,惟一索引的值是惟一的,能夠更快速的肯定某條記錄,例如學生的學號就適合使用惟一性索引,而學生的性別則不適合使用,由於無論搜索哪一個值,都差很少有一半的行。前綴索引
,若是索引的值很長,那麼查詢速度會受到影響,這個時候應該使用前綴索引,對列的某幾個字符進行索引,能夠提升檢索效率。MySQL 從 5.0 開始就提供了視圖功能,下面咱們對視圖功能進行介紹。
視圖的英文名稱是 view
,它是一種虛擬存在的表。視圖對於用戶來講是透明的,它並不在數據庫中實際存在,視圖是使用數據庫行和列動態組成的表,那麼視圖相對於數據庫表來講,優點體如今哪裏?
視圖相對於普通的表來講,優點包含下面這幾項
視圖的操做包括建立或者修改視圖、刪除視圖以及查看視圖定義。
使用 create view
來建立視圖
爲了演示功能,咱們先建立一張表 product
表,有三個字段,id,name,price,下面是建表語句
create table product(id int(11),name varchar(20),price float(10,2));
複製代碼
而後咱們向其中插入幾條數據
insert into product values(1, "apple","3.5"),(2,"banana","4.2"),(3,"melon","1.2");
複製代碼
插入完成後的表結構以下
而後咱們建立視圖
create view v1 as select * from product;
複製代碼
而後咱們查看一下 v1 視圖的結構
能夠看到咱們把 product 中的數據放在了視圖中,也至關因而建立了一個 product 的副本,只不過這個副本跟表無關。
視圖使用
show tables;
複製代碼
也能看到全部的視圖。
刪除視圖的語法是
drop view v1;
複製代碼
可以直接進行刪除。
視圖還有其餘操做,好比查詢操做
你還可使用
describe v1;
複製代碼
查看錶結構
更新視圖
update v1 set name = "grape" where id = 1;
複製代碼
MySQL 從 5.0 開始起就支持存儲過程和函數了。
那麼什麼是存儲過程呢?
存儲過程是在數據庫系統中完成一組特定功能的 SQL 語句集,它存儲在數據庫系統中,一次編譯後永久有效。那麼使用存儲過程有什麼優勢呢?
使用存儲過程有什麼缺點?
在認識到存儲過程是什麼以後,咱們就來使用一下存儲過程,這裏須要先了解一個小技巧,也就是 delimiter
的用法,delimiter 用於自定義結束符,什麼意思呢,若是你使用
delimiter $$
複製代碼
的話,那麼你在 sql 語句末使用 ;
是不能使 SQL 語句執行的,不信?咱們能夠看下
能夠看到,咱們在 SQL 語句的行末使用了 ;
可是咱們卻沒有看到執行結果。下面咱們使用
delimiter ;
複製代碼
恢復默認的執行條件再來看下
咱們建立存儲過程首先要把 ;
替換爲 $$
,下面是一個存儲過程的建立語句
mysql> delimiter $$
mysql> create procedure sp_product()
-> begin
-> select * from product;
-> end $$
複製代碼
存儲過程其實是一種函數,因此建立完畢後,咱們可使用 call
方法來調用這個存儲過程
由於咱們上面定義了使用 delimiter $$ 來結尾,因此這裏也應該使用。
存儲過程也能夠接受參數,好比咱們定義一種接收參數的狀況
而後咱們使用 call
調用這個存儲過程
能夠看到,當咱們調用 id = 2 的時候,存儲過程的 SQL 語句至關因而
select * from product where id = 2;
複製代碼
因此只查詢出 id = 2 的結果。
一次只能刪除一個存儲過程,刪除存儲過程的語法以下
drop procedure sp_product ;
複製代碼
直接使用 sp_product 就能夠了,不用加 ()
。
存儲過程建立後,用戶可能須要須要查看存儲過程的狀態等信息,便於瞭解存儲過程的基本狀況
咱們可使用
show create procedure proc_name;
複製代碼
在 MySQL 中,變量可分爲兩大類,即系統變量
和用戶變量
,這是一種粗略的分法。可是根據實際應用又被細化爲四種類型,即局部變量、用戶變量、會話變量和全局變量。
用戶變量是基於會話變量
實現的,能夠暫存,用戶變量與鏈接有關,也就是說一個客戶端定義的變量不能被其餘客戶端使用看到。當客戶端退出時,連接會自動釋放。咱們可使用 set
語句設置一個變量
set @myId = "cxuan";
複製代碼
而後使用 select
查詢條件能夠查詢出咱們剛剛設置的用戶變量
用戶變量是和客戶端有關係,當咱們退出後,這個變量會自動消失,如今咱們退出客戶端
exit
複製代碼
如今咱們從新登錄客戶端,再次使用 select
條件查詢
發現已經沒有這個 @myId
了。
MySQL 中的局部變量與 Java 很相似 ,Java 中的局部變量是 Java 所在的方法或者代碼塊,而 MySQL 中的局部變量做用域是所在的存儲過程。MySQL 局部變量使用 declare
來聲明。
服務器會爲每一個鏈接的客戶端維護一個會話變量。可使用
show session variables;
複製代碼
顯示全部的會話變量。
咱們能夠手動設置會話變量
set session auto_increment_increment=1;
或者使用
set @@session.auto_increment_increment=2;
複製代碼
而後進行查詢,查詢會話變量使用
或者使用
當服務啓動時,它將全部全局變量初始化爲默認值。其做用域爲 server 的整個生命週期。
可使用
show global variables;
複製代碼
查看全局變量
可使用下面這兩種方式設置全局變量
set global sql_warnings=ON; -- global不能省略
/** 或者 **/
set @@global.sql_warnings=OFF;
複製代碼
查詢全局變量時,可使用
或者是
MySQL 支持下面這些控制語句
IF 用於實現邏輯判斷,知足不一樣條件執行不一樣的 SQL 語句
IF ... THEN ...
複製代碼
CASE 實現比 IF 稍微複雜,語法以下
CASE ...
WHEN ... THEN...
...
END CASE
複製代碼
CASE 語句也可使用 IF 來完成
LOOP 用於實現簡單的循環
label:LOOP
...
END LOOP label;
複製代碼
若是 ...
中不寫 SQL 語句的話,那麼就是一個簡單的死循環語句
用來表示從標註的流程構造中退出,一般和 BEGIN...END 或者循環一塊兒使用
ITERATE 語句必須用在循環中,做用是跳過當前循環的剩下的語句,直接進入下一輪循環。
帶有條件的循環控制語句,當知足條件的時候退出循環。
REPEAT
...
UNTIL
END REPEAT;
複製代碼
WHILE 語句表示的含義和 REPEAT 相差無幾,WHILE 循環和 REPEAT 循環的區別在於:WHILE 是知足條件才執行循環,REPEAT 是知足條件退出循環;
MySQL 從 5.0 開始支持觸發器
,觸發器通常做用在表上,在知足定義條件時觸發,並執行觸發器中定義的語句集合,下面咱們就來一塊兒認識一下觸發器。
舉個例子來認識一下觸發器:好比你有一個日誌表和金額表,你每錄入一筆金額就要進行日誌表的記錄,你會怎麼樣?同時在金額表和日誌表插入數據嗎?若是有了觸發器,你能夠直接在金額表錄入數據,日誌表會自動插入一條日誌記錄,固然,觸發器不只只有新增操做,還有更新和刪除操做。
咱們能夠用以下的方式建立觸發器
create trigger triggername triggertime triggerevent on tbname for each row triggerstmt
複製代碼
上面涉及到幾個參數,我知道你有點懵逼,解釋一下。
triggername
:這個指的就是觸發器的名字triggertime
:這個指的就是觸發器觸發時機,是 BEFORE
仍是 AFTER
triggerevent
: 這個指的就是觸發器觸發事件,一共有三種事件:INSERT、UPDATE 或者 DELETE。tbname
:這個參數指的是觸發器建立的表名,在哪一個表上建立triggerstmt
: 觸發器的程序體,也就是 SQL 語句因此,能夠建立六種觸發器
BEFORE INSERT、AFTER INSERT、BEFORE UPDATE、AFTER UPDATE、BEFORE DELETE、AFTER DELETE
上面的 for each now
表示任何一條記錄上的操做都會觸發觸發器。
下面咱們經過一個例子來演示一下觸發器的操做
咱們仍是用上面的 procuct 表作例子,咱們建立一個 product_info 產品信息表。
create table product_info(p_info varchar(20));
複製代碼
而後咱們建立一個 trigger
咱們在 product 表中插入一條數據
insert into product values(4,"pineapple",15.3);
複製代碼
咱們進行 select 查詢,能夠看到如今 product 表中有四條數據
咱們沒有向 product_info 表中插入數據,如今咱們來看一下 product_info 表中,咱們預想到是有數據的,具體來看下
這條數據是何時插入的呢?咱們在建立觸發器 tg_pinfo
的時候插入了的這條數據。
觸發器可使用 drop
進行刪除,具體刪除語法以下
drop trigger tg_pinfo;
複製代碼
和刪除表的語法是同樣的
咱們常常會查看觸發器,能夠經過執行 show triggers
命令查看觸發器的狀態、語法等信息。
另外一種查詢方式是查詢表中的 information_schema.triggers
表,這個能夠查詢指定觸發器的指定信息,操做起來方便不少
注意:觸發器的使用有兩個限制
- 觸發程序不能調用將數據返回客戶端的存儲程序。也不能使用 CALL 語句的動態 SQL 語句。
- 不能在觸發器中開始和結束語句,例如 START TRANSACTION