《MySql必知必會》學習筆記
MySql的使用
--選擇資料庫 use database; --返回可用資料庫列表 show database; --返回一個數據庫內表的列表 show tables; --對一個表的每個欄位返回一行,行中包括欄位名、資料型別、是否允許NULL、鍵資訊、預設值以及其他資訊等 show columns from table; --功能同上 describe table; --用於顯示廣泛的伺服器狀態資訊; show status; --顯示建立建立資料庫和表的MySql資訊 show create database; show create table; --用於顯示伺服器錯誤或警告資訊 show errors; show warnings;
檢索資料
--查詢多個欄位
select nickname,email from user;
--查詢不同的姓名
select distinct nickname from user;
--返回前幾行
select nickname,email from user limit 1;
--返回從第0行開始的2行
select nickname,email from user limit 0,2;
--功能同上
select nickname,email from user limit 0 offset 2;
排序和過濾檢索資料
select nickname,email from user order by age desc , nickname; //按照年齡從大到小排序,如果年齡相同則按照暱稱從小到大排序 select nickename from user where age <> 20; //返回年齡不等於20的使用者姓名 `<>`用法等同於`!=` select nickename from user where email is NULL; //返回郵箱資訊為空的使用者名稱 select nickename from user where email is NULL; //返回郵箱資訊為空的使用者名稱 --預設執行順序為 `( age=10 ) or ( age=20 and eamil is NULL )`,`and`優先順序更高 select * from user where age=10 or age=20 and eamil is NULL; // --對`IN`後圓括中的每一個元素進行匹配,等同於`OR` select * from user where age in(10,20); --對其中條件進行否定 select * from user where age not in(10,20); --表示暱稱包含字元e的所有使用者,%表示萬用字元 表示任何字元出現的次數,0次、1次或多次。 select * from user where nickname like '%e%'; --表示暱稱第二個字元為e的所有使用者,`_`表示匹配單個字元。 select * from user where nickname like '_e%';
正則表示式
select * from user where age REGEXP '.0'; //正則表示式,匹配年齡為10、20、30... 的使用者,`.`表示匹配任意一個字元 select * from user where age BINARY REGEXP 'JetPack.000'; //`BINARY`用於正則表示式中區分大小寫 select * from user where age BINARY REGEXP '1000|1000'; //正則表示式進行OR匹配 select nickname from user where nickname BINARY REGEXP '[123] Ton'; //返回的是`1 Ton` `2 Ton` ,`[123]`為`[1|2|3]`的縮寫,表示匹配1或2或3 select nickname from user where nickname BINARY REGEXP '[^123] Ton'; //返回的是匹配指定字串以外的值 select nickname from user where nickname BINARY REGEXP '[a-c] Ton' and age REGEXP '[1-3]'; //nikename中包含`a Ton` `b Ton` `c Ton`,age中包含1,2,3
匹配字元類
類 | 說明 |
---|---|
[:alnum:] | 任意字元和數字(同[a-zA-Z0-9]) |
[:alpha:] | 任意字元(同[a-zA-Z]) |
[:blank:] | 空格和製表(同[\t]) |
[:cntrl:] | ASCII控制字元(ASCII 0到31和127) |
[:digit:] | 任意數字(同[0-9]) |
[:graph:] | 與[:print:]相同,但不包括空格 |
[:lower:] | 任意小寫字母(同[a-z]) |
[:print:] | 任意可列印字元 |
[:punct:] | 既不在[:alnum:]又不在[:cntrl:]中的任意字元 |
[:space:] | 包括空格在內的任意空白字元(同[\f\n\r\t\v]) |
[:upper:] | 任意大寫字母(同[A-Z]) |
[:xdigit:] | 任意十六進位制數字(同[a-fA-F0-9]) |
匹配多個例項
元字元 | 說明 |
---|---|
* | 0個或多個匹配 |
+ | 1個或多個匹配(等於{1,}) |
? | 0個或1個匹配(等於{0,1}) |
{n} | 指定數目的匹配 |
{n,} | 不少於指定數目的匹配 |
{n,m} | 匹配數目的範圍(m不超過255) |
'\\([0-9]stick?\\)'
A (1 stick)
B (1 sticks)
\\
為轉移符 ,第一個\是MySql自己解釋一個,第二\是正則表示式解釋一個
定位符
元字元 | 說明 |
---|---|
^ | 文字的開始 |
$ | 文字的結尾 |
[[:<:]] | 詞的開始 |
[[:>:]] | 詞的結尾 |
'[1]'
^
匹配串的開始,即以數字開頭或者.
開頭的字串
計算欄位
拼接
-- 按照 `雲捲雲舒(20)`這樣的暱稱+年齡格式表示,`RTrim`去掉值右邊的所有空格,
select Concat(RTrim(nick_name),'(',RTrim(age),')') from user_info;
使用別名
-- as info
select Concat(RTrim(nick_name),'(',RTrim(age),')') as info from user_info;
算術運算
select order_id,quantity,item_price,quantity*item_price as cost from order_items;
操作符 | 說明 |
---|---|
+ | 加法 |
- | 減法 |
* | 乘法 |
/ | 除法 |
資料處理函式
文字處理函式
函式 | 說明 |
---|---|
Left() | 返回串左邊的字元 |
Length() | 返回串的長度 |
Locate() | 找出串的一個子串 |
Lower() | 將串轉換為小寫 |
LTrim() | 去掉串左邊的空格 |
Right() | 返回串右邊的字元 |
RTrim() | 去掉串右邊的空格 |
Soundex() | 返回串的SOUNDEX值 |
SubString() | 返回子串的字元 |
Upper() | 將串轉換為大寫 |
SOUNDEX:將任何文字串轉換為其語音表示的字母數字模式的演算法。使得能對串進行發音比較而不是字母比較
-- nikename發音類似cc的所有nickname
select nickname from user_info where Soundex(nickname)=Soundex('cc');
時間處理函式
函式 | 說明 |
---|---|
AddDate() | 增加一個日期(天、周等) |
AddTime() | 增加一個時間(時、分等) |
CurDate() | 返回當前日期 |
CurTime() | 返回當前時間 |
Date() | 返回日期時間的日期部分 |
DateDiff() | 計算兩個日期之差 |
Date_Add() | 高度靈活的日期運算函式 |
Date_Format() | 返回一個格式化的日期或時間串 |
Day() | 返回一個日期的天數部分 |
DayOfWeek() | 對於一個日期,返回對應的星期幾 |
Hour() | 返回一個時間的小時部分 |
Minute() | 返回一個時間的分鐘部分 |
Month() | 返回一個日期的月份部分 |
Now() | 返回當前日期和時間 |
Second() | 返回一個時間的秒部分 |
Time() | 返回一個日期時間的時間部分 |
Year() | 返回一個日期的年份部分 |
日期格式最好為yyyy-mm-dd,可以排除多義性,這樣MySql就不必做出任何假設,更加可靠
select * from user where birthday='2000-01-01'
會和 birthday為'2000-01-01 01:01:01'的匹配失敗
更好的解決方案是利用Date()
函式直接匹配日期部分select * from user where Date(birthday)='2000-01-01'
數值處理函式
函式 | 說明 |
---|---|
Abs() | 返回一個數的絕對值 |
Cos() | 返回一個角度的餘弦 |
Exp() | 返回一個數的指數值 |
Mod() | 返回除操作的餘數 |
Pi() | 返回圓周率 |
Rand() | 返回一個隨機數 |
Sin() | 返回一個角度的正弦 |
Sqrt() | 返回一個數的平方根 |
Tan() | 返回一個角度的正切 |
彙總資料
聚集函式
函式 | 說明 |
---|---|
AVG() | 返回某列的平均值 |
COUNT() | 返回某列的行數 |
MAX() | 返回某列的最大值 |
MIN() | 返回某列的最小值 |
SUM() | 返回某列值之和 |
以上函式均忽略列值為NULL的行
select AVG(age) from user_info;
select COUNT(age) from user_info;
select MAX(age) from user_info;
select MIN(age) from user_info;
select SUM(age) from user_info;
分組函式
建立分組
- 先按照特定順序分組
- 再對每一組進行計算
-- 先按照暱稱分組,然後對每一組進行求和運算
select nick_name,SUM(age) from user_info group by nick_name;
select後的每一列都必須在GROUP BY字句中給出
如果在select中使用表示式,則必須在group by子句中指定相同的表示式
過濾分組
HAVING:
- 基礎功能和WHERE一樣,在簡單句式中可以替代WHERE
- 區別:
- WHERE過濾行,HAVING過濾分組
- WHERE在資料分組前過濾資料,HAVING在資料分組後對組進行分組。
-- 先對過濾掉age<=10的資料,再篩選出分組總年齡大於100的小組
select nick_name,SUM(age) from user_info where age>10 group by nick_name having SUM(age)>100;
子查詢
利用子查詢過濾
現在有訂單表orderitems,客戶資訊表customers,訂單物品表orderitems
查詢出訂購物品cc2的所有客戶姓名
- 檢索包含物品cc2的所有訂單的編號。
select order_num from orderitems where prod_id='cc2';
- 檢索具有前一步驟列出的訂單編號的所有客戶的ID。
select cust_id from orders where order_num IN (2005,2006);
- 檢索前一步驟返回的所有客戶ID的客戶資訊。 從內向外執行
select cust_id from orders where order_num IN (select order_num from orderitems where prod_id='cc2');
- 從客戶ID中查詢出資訊
select
cust_name
from
customers
where
cust_id IN (select
cust_id
from
orders
where
order_num IN (select
order_num
from
orderitems
where
prod_id='cc2'));
作為計算手段使用子查詢
現有訂單表orderitems,客戶資訊表customers
查詢每個使用者的訂單總數
- 查詢某個使用者的所有訂單數
select count(*) as orders from orders where cust_id=1001;
- 查詢在訂單表中每個使用者的訂單總數及其資訊
select cust_name,
(select count(*)
from orders
where oders.cust_id=customers.cust_id) as orders
from customer
order by cust_name;
聯結表
使用where
select vend_name,prod_name,prod_price from vendors,products where vendors.vend_id=prodcts.vend_id order by vend_name,prod_name;
內部聯結
使用 INNER JOIN 指定表,再使用 ON 執行特定條件的連線
- 檢索所有客戶及其訂單
SELECT customer.cust_id,orders.order_num FROM customer INNER JOIN orders ON customers.cust_id = orders.cust_id;
多表聯結
select cust_name
from customer,orders,orderitems
where customer.cust_id=oders.cust_id
and orderitems.order_num=orders.order_num
and prod_id='cc2';
高階聯結
使用表別名
select cust_name
from customer as c,orders as o,orderitems as oi
where c.cust_id=o.cust_id
and oi.order_num=o.order_num
and prod_id='cc2';
自聯結
在商品表中發一下一個不合格商品(id為cc3),現在需要查找出生產這個商品的廠家的其他產品
- 使用子查詢
SELECT prod_id,prod_name FROM products where vend_id = (SELECT vend_id FROM products WHERE prod_id = 'cc2');
- 使用自聯結
SELECT p1.prod_id,p1.prod_name FROM products AS p1, products AS p2 WHERE p1.vend_id=p2.vend_id AND p2.prod_id = 'cc3';
p1,p2實際上是相同的一張表
自然聯結
無論何時對錶進行聯結,應該至少有一個列出現在不止一個表中,標準的聯結(內部聯結)返回所有的資料,甚至所有的列多次出現。
自然聯結排除多次出現,使每個列只返回一次。
外部聯結
許多聯結將一個表中的行與另外一個表中的行相關聯。但有時候需要包含沒有關聯行的那些行。
-
列出所有產品以及訂購資料,包括哪些沒有人訂購的產品
-
對每個客戶下了多少訂單進行計數,包括哪些至今尚未下訂單的客戶
-
檢索所有客戶及其訂單(內部聯結)
SELECT customer.cust_id,orders.order_num FROM customer INNER JOIN orders ON customers.cust_id = orders.cust_id;
- 檢索所有客戶,包括那些沒有下訂單的客戶(外部聯結)
SELECT customer.cust_id,orders.order_num FROM customer LEFT OUTER JOIN orders ON customers.cust_id = orders.cust_id;
RIGHT表示OUTER JION右邊的表的所有行(匹配或不匹配)都將被檢索出來
LEFT 表示OUTER JION左邊的表
帶聚集函式的聯結
檢索出所有客戶及每個客戶所下的訂單數
SELECT customers.cust_id,count(orders.ooder_num) FROM customer LEFT OUTER JOIN orders ON customer.cust_id = orders.cust_id ORDER BY customers.id;
組合查詢
- 對於單個查詢中從不同表彙總返回類似結構的資料
- 對單個表執行多個查詢,按單個查詢返回資料
使用UNION
檢索出所有價格小於5且來自2001,2002的供應商的所有商品
SELECT prod_id,pro_name
FROM products
WHERE prod_price < 5
UNION
SELECT prod_id,pro_name
FROM productes
WHERE vend_id in (2001,2003)
ORDER BY prod_name;
預設去除多個SELECT結果的重複行,但是可以使用UNION ALL來返回所有的改變行
排序語句放在最後一個SELECT的後面
全文字搜尋
啟用全文搜尋
MySql指定列中各詞的一個索引,搜尋可以針對這些詞進行。這樣,MySql可以快速有效地判斷哪些行包含它們,哪些詞不匹配,它們匹配的頻率,等等
FULLTEXT(列名稱)
CREATE TABLE product(
note_id int NOT NULL,
pro_id char(10) NOT NULL,
note_text text NOT NULL,
PRIMARY KEY(pro_id),
FULLTEXT(note_text)
)ENGINE=MyISAM;
InnoDB不支援全文字搜尋引擎
進行全文字搜尋
Match():指定被搜尋的列
Against():指定要使用的搜尋表示式
SELECT note_text FROM productnotes WHERE Match (note_text) Against('rabbit');
使用擴充套件查詢
考慮下面 的情況。你想找出所有提到anvils的註釋。只有一個註釋包含詞anvils, 但你還想找出可能與你的搜尋有關的所有其他行,即使它們不包含詞anvils。 這也是查詢擴充套件的一項任務。在使用查詢擴充套件時,MySQL對資料和 索引進行兩遍掃描來完成搜尋:
- 首先,進行一個基本的全文字搜尋,找出與搜尋條件匹配的所有行;
- 其次,MySQL檢查這些匹配行並選擇所有有用的詞(我們將會簡 要地解釋MySQL如何斷定什麼有用,什麼無用)。
- 再其次,MySQL再次進行全文字搜尋,這次不僅使用原來的條件, 而且還使用所有有用的詞。
SELECT note_text FROM productnotes WHERE Match(note_text) Against ('anvil' WITH QUERY EXPANsION);
可能返回多行,但只有第一行含有關鍵字'anvil',其他行因為含有第一行的相關字而有可能被檢索出來
布林文字搜尋
可以提供關於如下內容的細節:
- 要匹配的詞
- 要排斥的詞(如果某行包含這個詞,則不返回該行,即使它包含 其他指定的詞也是如此)
- 排列提示(指定某些詞比其他詞更重要,更重要的詞等級更高)
- 表示式分組
- 另外一些內容
布林操作符 | 說明 |
---|---|
+ | 包含,詞必須存在 |
- | 排除,詞必須不出現 |
> | 包含,而且增加等級值 |
< | 包含,且減少等級值 |
() | 把片語成子表示式(允許這些子表示式作為一個組被包含、 排除、排列等) |
~ | 取消一個詞的排序值 |
* | 詞尾的萬用字元 |
"" | 定義一個短語(與單個詞的列表不一樣,它匹配整個短語以 便包含或排除這個短語) |
SELECT note_text FROM productnotes WHERE Match(note_text) Against('heavy -rope*' IN BOOLEAN MODE);
檢索含有關鍵字
heavy
但不含有以rope
開頭的行
一些說明
- 在索引全文字資料時,短詞被忽略且從索引中排除。短詞定義為 那些具有3個或3個以下字元的詞(如果需要,這個數目可以更改)。
- MySQL帶有一個內建的非用詞(stopword)列表,這些詞在索引全文字資料時總是被忽略。如果需要,可以覆蓋這個列表(請參 閱MySQL文件以瞭解如何完成此工作)。
- 許多詞出現的頻率很高,搜尋它們沒有用處(返回太多的結果)。 因此,MySQL規定了一條50%規則,如果一個詞出現在50%以上的行中,則將它作為一個非用詞忽略。50%規則不用於IN BOOLEAN MODE。
- 如果表中的行數少於3行,則全文字搜尋不返回結果(因為每個詞 或者不出現,或者至少出現在50%的行中)。
- 忽略詞中的單引號。例如,don't索引為dont。
- 不具有詞分隔符(包括日語和漢語)的語言不能恰當地返回全文本搜尋結果。
- 如前所述,僅在MyISAM資料庫引擎中支援全文字搜尋。
插入資料
插入完整的行
INSERT into customers VALUES (1,cc,cc@foxmail);
對每個列必須提供一個值。如果某個列沒有值,應該使用NULL值(假定表允許對該列指定空值)。
對於自增的欄位,也需要設為NULL
種語法很簡單,但並不安全,應該儘量避免使用。不能保證下一次表結構變動後各個列 保持完全相同的次序
INSERT into customers(cust_id,cust_name,cust_email) VALUES (1,cc,cc@foxmail);
用VALUES 列表中的相應值填入列表中的對應項
對於自增欄位,可以不出現
如果資料檢索是最重要的(通常是這樣),則你可以通過在 INSERT和INTO之間新增關鍵字LOW_PRIORITY,指示MySQL 降低INSERT語句的優先順序,如下所示:
INSERT LOW_PRIORITY INTO
這也適用於UPDATE和DELETE語句
插入多行
INSERT into customers(cust_id,cust_name,cust_email) VALUES (1,cc1,cc1@foxmail),(2,cc2,cc2@foxmail);
插入檢索出來的資料
合併新舊錶
INSERT into cust_new(cust_id,
cust_name,
cust_email)
SELECT cust_id,
cust_name,
cust_email
FROM cust_old;
更新和刪除資料
更新
UPDATE customers SET cust_email = '[email protected]', cust_name = 'newname' WHERE cust_id = '1';
如果沒有
WHERE
語句,則將更新這張表中所有資料
IGNORE關鍵字,如果用UPDATE語句更新多行,並且在更新這些行中的一行或多行時出一個現錯誤,則整個UPDATE操作被取消 (錯誤發生前更新的所有行被恢復到它們原來的值)。為即使是發生錯誤,也繼續進行更新,可使用IGNORE關鍵字,如下所示: UPDATE IGNORE customers…
為了刪除某一行的某個列值,可以將它更新為NULL
刪除
- 刪除一行
DELETE FROM customers WHERE cust_id = '1231';
如果沒有
WHERE
語句,則將刪除這張表中所有資料
如果更快的刪除而且刪除清零自增欄位,可以使用truncate tablename
除非確實打算更新和刪除每一行,否則絕對不要使用不帶WHERE 子句的UPDATE或DELETE語句。
保證每個表都有主鍵(如果忘記這個內容,請參閱第15章),儘可能 像WHERE子句那樣使用它(可以指定各主鍵、多個值或值的範圍)。
在對UPDATE或DELETE語句使用WHERE子句前,應該先用SELECT進 行測試,保證它過濾的是正確的記錄,以防編寫的WHERE子句不正確。
建立和刪除表
建立表
CREATE TABLE product(
pro_id char(10) NOT NULL AUTO_INCREMENT, --自增
note_id int NOT NULL,
note_text text NOT NULL,
pro_price ine NOT NULL DEFAULT 1, --預設值為1
PRIMARY KEY(pro_id)
)ENGINE=InnoDB;
自增欄位 AUTO_INCREMENT,(每個表只允許有一個自增欄位,且必須被索引<例如使它變為主鍵>)
使用SELECT last_insert_id()
語句返回最後一個AUTO_INCREMENT值
DEFAULT 設定預設值
引擎型別
與其他DBMS一樣,MySQL有一個具體管理和處理資料的內部引擎。 在你使用CREATE TABLE語句時,該引擎具體建立表,而在你使用SELECT 語句或進行其他資料庫處理時,該引擎在內部處理你的請求。多數時候, 此引擎都隱藏在DBMS內,不需要過多關注它。
但MySQL與其他DBMS不一樣,它具有多種引擎。它打包多個引擎, 這些引擎都隱藏在MySQL伺服器內,全都能執行CREATE TABLE和SELECT 等命令。
為什麼要發行多種引擎呢?因為它們具有各自不同的功能和特性, 為不同的任務選擇正確的引擎能獲得良好的功能和靈活性。
當然,你完全可以忽略這些資料庫引擎。如果省略ENGINE=語句,則 使用預設引擎(很可能是MyISAM),多數SQL語句都會預設使用它。但並不是所有語句都預設使用它,這就是為什麼ENGINE=語句很重要的原因 (也就是為什麼本書的樣列表中使用兩種引擎的原因)。
- InnoDB是一個可靠的事務處理引擎(參見第26章),它不支援全文字搜尋
- MEMORY在功能等同於MyISAM,但由於資料儲存在記憶體(不是磁碟) 中,速度很快(特別適合於臨時表)
- MyISAM是一個效能極高的引擎,它支援全文字搜尋(參見第18章), 但不支援事務處理。
更新表
為更新表定義,可使用ALTER TABLE語句。但是,理想狀態下,當表中儲存資料以後,該表就不應該再被更新。在表的設計過程中需要花費大量時間來考慮,以便後期不對該表進行大的改動。
--增加欄位
ALTER TABLE products ADD prod_price;
--刪除欄位
ALTER TABLE products DROP prod_price;
--定義外來鍵
ALTER TABLE products ADD CONSTRAINT orderitems FOREIGN KEY (order_num) REFERENCES (order_num);
複雜的表結構更改一般需要手動刪除過程,它涉及以下步驟:
- 用新的列布局建立一個新表
- 使用INSERT SELECT語句從舊錶複製資料到新表
- 檢驗包含所需資料的新表
- 重新命名舊錶(如果確定,可以刪除它)
- 用舊錶原來的名字重新命名新表
- 根據需要,重新建立觸發器、儲存過程、索引和外來鍵
刪除表
DROP TABLE customers;
重命名錶
RENAME TABLE customer1 TO customer2;
檢視
檢視是虛擬的表。與包含資料的表不一樣,檢視只包含使用時動態檢索資料的查詢。
它本身不包含表中應該有的任何列或資料,它包含的是一個SQL查詢
檢視的應用
- 重用SQL語句
- 簡化複雜的SQL操作。在編寫查詢後,可以方便地重用它而不必知道它的基本查詢細節
- 使用表的組成部分而不是整個表。
- 保護資料。可以給使用者授予表的特定部分的訪問許可權而不是整個 表的訪問許可權
- 更改資料格式和表示。檢視可返回與底層表的表示和格式不同的資料
在檢視建立之後,可以用與表基本相同的方式利用它們。可以對檢視執行SELECT操作,過濾和排序資料,將視圖聯結到其他檢視或表,甚至能新增和更新資料(新增和更新資料存在某些限制。關於這個內容稍 後還要做進一步的介紹)。
如果你用多個聯結和過濾建立了複雜的檢視或者嵌套了檢視,可能會發現效能下降得很厲害。
檢視的規則和限制
- 檢視必須唯一命名
- 建立的檢視數目沒有限制
- 必須具有足夠的訪問許可權
- 檢視可以巢狀,即可以利用從其他檢視中檢索資料的查詢來構造 一個檢視
- ORDER BY可以用在檢視中,但如果從該檢視檢索資料SELECT中也含有ORDER BY,那麼該檢視中的ORDER BY將被覆蓋
- 檢視不能索引,也不能有關聯的觸發器或預設值
- 檢視可以和表一起使用。例如,編寫一條聯結表和檢視的SELECT 語句。
使用檢視
- CREATE VIEW語句來建立
- SHOW CREATE VIEW viewname;來檢視建立檢視的語
- 用DROP刪除檢視,其語法為DROP VIEW viewname
- 更新檢視時,可以先用DROP再用CREATE,也可以直接用
CREATE OR REPLACE VIEW
。如果要更新的檢視不存在,則第2條更新語句會創 建一個檢視;如果要更新的檢視存在,則第2條更新語句會替換原 有檢視
更新檢視
通常,檢視是可更新的,但是,並非所有檢視都是可更新的。基本上可以說,如果MySQL不能正確地確定被更新的基資料,則不允許更新(包括插入和刪除)。這實際上意味著,如果檢視定義中有以下操作,則不能進行檢視的更新:
- 分組
- 聯結
- 子查詢
- 並
- 聚集函式(Min()、Count()、Sum()等)
- DISTINCT
- 匯出(計算)列
儲存過程
迄今為止,使用的大多數SQL語句都是針對一個或多個表的單條語 句。並非所有操作都這麼簡單,經常會有一個完整的操作需要多條語句 才能完成。例如,考慮以下的情形
- 為了處理訂單,需要核對以保證庫存中有相應的物品
- 如果庫存有物品,這些物品需要預定以便不將它們再賣給別的人,並且要減少可用的物品數量以反映正確的庫存量
- 庫存中沒有的物品需要訂購,這需要與供應商進行某種互動
- 關於哪些物品入庫(並且可以立即發貨)和哪些物品退訂,需要通知相應的客戶
執行這個處理需要針對許多表的多條MySQL語句。此外,需要執行的具體語句及其次序也不是固定的,它們可能會(和將)根據哪些物品在庫存中哪些不在而變化。
儲存過程簡單來說,就是為以後的使用而儲存的一條或多條MySQL語句的集合。
可將其視為批檔案,雖然它們的作用不僅限於批處理。
使用儲存過程的優缺點
優點
簡單、安全、高效能
-
通過把處理封裝在容易使用的單元中,簡化複雜的操作(正如前 面例子所述)
-
由於不要求反覆建立一系列處理步驟,這保證了資料的完整性。如果所有開發人員和應用程式都使用同一(試驗和測試)儲存過程,則所使用的程式碼都是相同的。 這一點的延伸就是防止錯誤。需要執行的步驟越多,出錯的可能性就越大。防止錯誤保證了資料的一致性。
-
簡化對變動的管理。如果表名、列名或業務邏輯(或別的內容) 有變化,只需要更改儲存過程的程式碼。使用它的人員甚至不需要知道這些變化。
-
提高效能。因為使用儲存過程比使用單獨的SQL語句要快
-
存在一些只能用在單個請求中的MySQL元素和特性,儲存過程可以使用它們來編寫功能更強更靈活的程式碼
缺點
- 儲存過程的編寫比基本SQL語句複雜,編寫儲存過程需要更高的技能,更豐富的經驗。
- 你可能沒有建立儲存過程的安全訪問許可權。許多資料庫管理員限 制儲存過程的建立許可權,允許使用者使用儲存過程,但不允許他們 建立儲存過程。
使用儲存過程
- 執行(call)
CALL productpricing(@pricelow,@pricehigh,@priceaverage);
建立儲存過程
返回產品平均過程的儲存過程
CREATE PROCEDURE productpricing()
BEGIN
SELECT AVG(prod_price) AS priceaverage FROM products;
END
注意productpricing()的()
mysql命令列客戶機的分隔符(命令列工具)
DELIMITER//
CREATE PROCEDURE productpricing()
BEGIN
SELECT AVG(prod_price) AS priceaverage FROM products;
END//
DELIMITER;
因為在儲存過程存在
;
,所以在命令列程式中需使用特定的分隔符
DELIMITER+符號(分隔符):表示告訴程式使用此分隔符作為新的語句結束分隔符,所以由END
變為了END//
除\符號外,任何字元都可以用作語句分隔符。
刪除儲存過程
DROP PROCEDURE productpricing;
注意沒有
()
如果該儲存過程不存在,則會報錯,所以建議使用DROP PROCEDURE IF EXISTS
使用引數
- 建立帶引數的儲存過程
CREATE PROCEDURE productpricing(
OUT pl DECIMAL(8,2), --pl:儲存產品最低價格
OUT ph DECIMAL(8,2), --ph:儲存產品最高價格
)
BEGIN
SELECT MIN(prod_price) INTO pl FROM products;
SELECT MAX(prod_price) INTO ph FROM products;
END
儲存過程儲存在BEGIN和END之間
OUT指出相應的引數用來從儲存過程傳出 一個值(返回給呼叫者)
IN,傳遞給儲存過程
INOUT,對儲存過程傳入傳出
- 使用儲存過程
--指定變數名
CALL productpricing(@pricelow, @prichigh);
--檢索
SELECT @prcielow;
SELECT @prcielow, @prichigh;
檢查儲存過程
-- 顯示建立的語句
SHOW CREATE PROCEDURE ordertotal;
-- 顯示更加詳細,何時、由何人建立的資訊
SHOW CREATE PROCEDURE STATUS ordertotal;
-- 過濾檢視更多儲存過程的資訊
SHOW CREATE PROCEDURE STATUS LIKE 'ordertotal';
遊標
(有待填坑)
有時,需要在檢索出來的行中前進或後退一行或多行。這就是使用遊標的原因。遊標(cursor)是一個儲存在MySQL伺服器上的資料庫查詢, 它不是一條SELECT語句,而是被該語句檢索出來的結果集。在儲存了遊標之後,應用程式可以根據需要滾動或瀏覽其中的資料。
遊標主要用於互動式應用,其中使用者需要滾動螢幕上的資料,並對資料進行瀏覽或做出更改。
使用注意
- 在能夠使用遊標前,必須宣告(定義)它
- 一旦聲明後,必須開啟遊標以供使用。
- 對於填有資料的遊標,根據需要取出(檢索)各行。
- 在結束遊標使用時,必須關閉遊標。
建立遊標
CREATE PROCEDURE processorders()
BEGIN
DECLARE ordernumbers CURSOR
FOR
SELECT order_num FROM orders;
END;
開啟和關閉遊標
--開啟
OPEN ordernumbers;
--關閉
CLOSE ordernumbers;
如果不明確關閉遊標,MySql將會在到達END語句時自動關閉
使用遊標
在一個遊標被開啟後,可以使用FETCH語句分別訪問它的每一行。 FETCH指定檢索什麼資料(所需的列),檢索出來的資料儲存在什麼地方。 它還向前移動遊標中的內部行指標,使下一條FETCH語句檢索下一行(不重複讀取同一行)。
CREATE PROCEDURE processorders()
BEGIN
--宣告一個變數
DECLARE o INT;
--宣告一個遊標
DECLARE ordernumbers CURSOR
FOR
SELECT order_num FROM orders;
--開啟一個遊標
OPEN ordernumbers;
--獲取資料
FETCH ordernumbers INTO o;
--關閉遊標
CLOSE ordernumbers;
END;
觸發器
MySQL語句在需要時被執行,儲存過程也是如此。但是,如果你想要某條語句(或某些語句)在事件發生時自動執行,怎麼辦呢?例如:
- 每當增加一個顧客到某個資料庫表時,都檢查其電話號碼格式是 否正確,州的縮寫是否為大寫;
- 每當訂購一個產品時,都從庫存數量中減去訂購的數量;
- 無論何時刪除一行,都在某個存檔表中保留一個副本。
所有這些例子的共同之處是它們都需要在某個表發生更改時自動處理。這確切地說就是觸發器。觸發器是MySQL響應以下任意語句而自動執行的一條MySQL語句(或位於BEGIN和END語句之間的一組語 句) :
- DELETE;
- INSERT;
- UPDATE。
其他MySQL語句不支援觸發器。
建立觸發器
在建立觸發器時,需要給出4條資訊:
- 唯一的觸發器名;
- 觸發器關聯的表; (只有表支援觸發器,檢視不支援)
- 觸發器應該響應的活動(DELETE、INSERT或UPDATE);
- 觸發器何時執行(處理之前或之後)。
每個表將最多支援6個觸發器,DELETE、INSERT或UPDATE的處理之前或之後
在MySQL 5中,觸發器名必 須在每個表中唯一,但不是在每個資料庫中唯一。這表示同一 資料庫中的兩個表可具有相同名字的觸發器。這在其他每個數 據庫觸發器名必須唯一的DBMS中是不允許的,而且以後的 MySQL版本很可能會使命名規則更為嚴格。因此,現在最好 是在資料庫範圍內使用唯一的觸發器名。
CREATE TRIGGER newproduct AFTER INSERT ON products FOR EACH ROW SELECT 'product added';
使用INSERT語句新增一行或多行到products表中時,將對每一行顯示文字product added
刪除觸發器
DROP TRIGGER newproduct;
觸發器不能更新或覆蓋。為了修改一個觸發器,必須先刪除它, 然後再重新建立。
使用觸發器
INSERT觸發器
INSERT觸發器在INSERT語句執行之前或之後執行。需要知道以下幾點:
- 在INSERT觸發器程式碼內,可引用一個名為NEW的虛擬表,訪問被插入的行;
- 在BEFORE INSERT觸發器中,NEW中的值也可以被更新(允許更改被插入的值) ;
- 對於AUTO_INCREMENT列,NEW在INSERT執行之前包含0,在INSERT執行之後包含新的自動生成值。
CREATE TRIGGER newproduct AFTER INSERT ON products FOR EACH ROW SELECT NEW.order_num;
在插入一個新訂單到orders表時,MySQL生成一個新訂單號並儲存到order_num中。觸發器從NEW. order_num取得這個值並返回它。
DELETE觸發器
DELETE觸發器在DELETE語句執行之前或之後執行。需要知道以下兩 點:
- 在DELETE觸發器程式碼內,你可以引用一個名為OLD的虛擬表,訪問被刪除的行;
- OLD中的值全都是隻讀的,不能更新。
CREATE TRIGGER deleteorder BEFORE DELETE ON products FOR EACH ROW
BEGIN
INSERT INTO archive_orders(order_num,order_date)
VALUES(OLD.order_num,OLD.order_num);
END;
在任意訂單被刪除前將執行此觸發器。它使用一條INSERT語句 將OLD中的值(要被刪除的訂單)儲存到一個名為archive_ orders的存檔表中
UPDATE觸發器
UPDATE觸發器在UPDATE語句執行之前或之後執行。需要知道以下幾點:
- 在UPDATE觸發器程式碼中,你可以引用一個名為OLD的虛擬表訪問以前(UPDATE語句前)的值,引用一個名為NEW的虛擬表訪問新更新的值;
- 在BEFORE UPDATE觸發器中,NEW中的值可能也被更新(允許更改 將要用於UPDATE語句中的值);
- OLD中的值全都是只讀的,不能更新。
CREATE TRIGGER updateevendor BEFORE DELETE ON vendors FOR EACH ROW SET NEW.vend_state = Upper(NEW.vend-state);
下面的例子保證州名縮寫總是大寫(不管UPDATE語句中給出的是大 寫還是小寫):
進一步介紹
在結束本章之前,我們再介紹一些使用觸發器時需要記住的重點。
- 與其他DBMS相比,MySQL 5中支援的觸發器相當初級。未來的 MySQL版本中有一些改進和增強觸發器支援的計劃。
- 建立觸發器可能需要特殊的安全訪問許可權,但是,觸發器的執行是自動的。如果INSERT、UPDATE或DELETE語句能夠執行,則相關的觸發器也能執行。
- 應該用觸發器來保證資料的一致性(大小寫、格式等)。在觸發器中執行這種型別的處理的優點是它總是進行這種處理,而且是透明地進行,與客戶機應用無關。
- 觸發器的一種非常有意義的使用是建立審計跟蹤。使用觸發器,把更改(如果需要,甚至還有之前和之後的狀態)記錄到另一個 表非常容易。
- 遺憾的是,MySQL觸發器中不支援CALL語句。這表示不能從觸發器內呼叫儲存過程。所需的儲存過程程式碼需要複製到觸發器內。
事物處理
事務處理(transaction processing)可以用來維護資料庫的完整性,它 保證成批的MySQL操作要麼完全執行,要麼完全不執行。
利用事務處理,可以保證一組操作不會中途停止,它們或者作為整體執行,或者完全不執行(除非明確指示)。如果沒有錯誤發生,整組語句提交給(寫到)資料庫表。如果發生錯誤,則進行回退(撤銷)以恢復資料庫到某個已知且安全的狀態。
- 事務(transaction)指一組SQL語句;
- 回退(rollback)指撤銷指定SQL語句的過程;
- 提交(commit)指將未儲存的SQL語句結果寫入資料庫表;
- 保留點(savepoint)指事務處理中設定的臨時佔位符(place- holder),你可以對它釋出回退(與回退整個事務處理不同
使用ROLLBACK
MySQL的ROLLBACK命令用來回退(撤銷)MySQL語句。
SELECT * FROM ordertotals ;
--開始事物
START TRANSACTION;
DELETE FROM ordertotals;
SELECT * FROM ordertotals;
--撤銷
ROLLBACK;
SELECT * FROM ordertotals;
首先執行一條SELECT以顯示該表不為空。然後開始一個事務處理,用一條DELETE語句刪除ordertotals中的所有行。另一條 SELECT語句驗證ordertotals確實為空。這時用一條ROLLBACK語句回退 START TRANSACTION之後的所有語句,最後一條SELECT語句顯示該表不為空。
使用COMMIT
一般的MySQL語句都是直接針對資料庫表執行和編寫的。這就是所謂的隱含提交(implicit commit),即提交(寫或儲存)操作是自動進行的。
但是,在事務處理塊中,提交不會隱含地進行。為進行明確的提交,使用COMMIT語句,如下所示:
--開始事物
START TRANSACTION;
DELETE FROM ordertotals WHERE order_num = 20010;
DELETE FROM orders WHERE order_num = 20010;
--提交
COMMIT;
從系統中完全刪除訂單20010。因為涉及更新兩個資料庫表orders和orderItems,所以使用事務處理塊來保證訂單不被部分刪除。最後的COMMIT語句僅在不出錯時寫出更改。如 果第一條DELETE起作用,但第二條失敗,則DELETE不會提交(實際上,它是被自動撤銷的)
隱含事務關閉 當COMMIT或ROLLBACK語句執行後,事務會自 動關閉(將來的更改會隱含提交)。
使用保用點
簡單的ROLLBACK和COMMIT語句就可以寫入或撤銷整個事務處理。但 是,只是對簡單的事務處理才能這樣做,更復雜的事務處理可能需要部分提交或回退。
--建立保用點
SAVEPOINT delete1;
--回退
ROLLBACK TO delete1
保留點越多越好 .可以在MySQL程式碼中設定任意多的保留 點,越多越好。為什麼呢?因為保留點越多,你就越能按自己的意願靈活地進行回退。
保留點在事務處理完成(執行一條ROLLBACK或 COMMIT)後自動釋放**。自MySQL 5以來,也可以用RELEASE SAVEPOINT明確地釋放保留點。
更改預設提交方式
正如所述,預設的MySQL行為是自動提交所有更改。換句話說,任何時候你執行一條MySQL語句,該語句實際上都是針對表執行的,而且所做的更改立即生效。為指示MySQL不自動提交更改,需要使用以下語句:
SET autocommit=0;
全球化和本地化
不同的語言和字符集需要以不同的方式儲存和檢索。
因此,MySQL需要適應不同的字符集(不同的字母和字元),適應不同的排序和檢索資料的方法。
- 字符集:字母和符號的集合;
- 編碼:某個字符集成員的內部表示;
- 校對:規定字元如何比較的指令。
校對為什麼重要 排序英文正文很容易,對嗎?或許不。考 慮詞APE、apex和Apple。它們處於正確的排序順序嗎?這有 賴於你是否想區分大小寫。使用區分大小寫的校對順序,這 些詞有一種排序方式,使用不區分大小寫的校對順序有另外 一種排序方式。這不僅影響排序(如用ORDER BY排序資料) , 還影響搜尋(例如,尋找apple的WHERE子句是否能找到 APPLE)。在使用諸如法文à或德文ö這樣的字元時,情況更復 雜,在使用不基於拉丁文的字符集(日文、希伯來文、俄文 等)時,情況更為複雜
使用字符集和校對順序
為檢視所支援的字符集完整列表
SHOW CHARACTER SET;
為了檢視所支援校對的完整列
SHOW COLLATION;
通常系統管理在安裝時定義一個預設的字符集和校對。此外,也可 以在建立資料庫時,指定預設的字符集和校對。為了確定所用的字符集和校對可以使用以下語句:
SHOW VARIABLES LIKE 'character%';
SHOW VARIABLES LIKE 'collation%';
為了給表指定字符集和校對,可使用帶子句的CREATE TABLE
CREATE TABLE mytable
(
column1 INT,
column2 VARCHAR(10),
) DEFAULT CHARACTER SET brew --字符集
COLLATE hebrew_general_ci; --校對順序
對某個列設定單獨的字符集和校對
CREATE TABLE mytable
(
column1 INT,
column2 VARCHAR(10),
column3 VARCHAR(20) CHARACTER SET latin1 COLLATE latin1_general_ci
) DEFAULT CHARACTER SET brew --字符集
COLLATE hebrew_general_ci; --校對順序
如前所述,校對在對用ORDER BY子句檢索出來的資料排序時起重要 的作用。如果你需要用與建立表時不同的校對順序排序特定的SELECT語句,可以在SELECT語句自身中進行:
SELECT * FROM customer ORDER BY lastname COLLATE latin1_general_ci;
安全管理
MySQL伺服器的安全基礎是:使用者應該對他們需要的資料具有適當的訪問權,既不能多也不能少。換句話說,使用者不能對過多的資料具有過多的訪問權。
應該嚴肅對待root登入的使用。僅在絕對需 要時使用它(或許在你不能登入其他管理賬號時使用)。不應 該在日常的MySQL操作中使用root。
管理使用者
MySQL使用者賬號和資訊儲存在名為mysql的MySQL資料庫中。一般不需要直接訪問mysql資料庫和表(你稍後會明白這一點),但有時需要直接訪問。需要直接訪問它的時機之一是在需要獲得所有使用者賬號列表時。
mysql資料庫有一個名為user的表,它包含所有使用者賬號。user 表有一個名為user的列,它儲存使用者登入名。
建立使用者
--建立賬戶名為cc1,密碼為123的賬戶
CREATE USER cc1 IDENTIFIED BY '123';
--重新命名
RENAME USER cc1 TO cc2;
使用GRANT或INSERT GRANT語句也可以建立用 戶賬號,但一般來說CREATE USER是最清楚和最簡單的句子。 此外,也可以通過直接插入行到user表來增加使用者,不過為安全起見,一般不建議這樣做。MySQL用來儲存使用者賬號資訊 的表(以及表模式等)極為重要,對它們的任何毀壞都 可能嚴重地傷害到MySQL伺服器。因此,相對於直接處理來 說,最好是用標記和函式來處理這些表。
更改口令
SET PASSWORD FOR cc2 = Password('456');
--設定當前賬戶口令
SET PASSWORD = Password('456');
刪除使用者
DROP USER cc2;
設定訪問許可權
在建立使用者賬號後,必須接著分配訪問許可權。新建立的使用者賬號沒有訪問許可權。它們能登入MySQL,但不能看到資料,不能執行任何資料庫操作。
--看到賦予使用者賬號的許可權
SHOW GRANTS FOR cc2;
為設定許可權,使用GRANT語句。GRANT要求你至少給出以下資訊:
- 要授予的許可權
- 被授予訪問許可權的資料庫或表;
- 使用者名稱
--此GRANT允許使用者在crashcourse.*(crashcourse資料庫的所有表)上使用SELECT。
GRANT SELECT ON crashcourse.* TO cc3;
通過只授予SELECT訪問許可權,使用者bforta對crashcourse資料庫中的所有資料具有隻讀訪問許可權。
GRANT的反操作為REVOKE,用它來撤銷特定的許可權。
--取消剛賦予使用者cc3的SELECT訪問許可權
REVOKE SELECT ON crashcourse.* FROM cc3;
GRANT和REVOKE可在幾個層次上控制訪問許可權:
- 整個伺服器,使用GRANT ALL和REVOKE ALL;
- 整個資料庫,使用ON database.*;
- 特定的表,使用ON database.table;
- 特定的列;
- 特定的儲存過程。
下標列出可以授予或撤銷的每個許可權。
許可權 | 說明 |
---|---|
ALL | 除GRANT OPTION外的所有許可權 |
ALTER | 使用ALTER TABLE |
ALTER ROUTINE | 使用ALTER PROCEDURE和DROP PROCEDURE |
CREATE | 使用CREATE TABLE |
CREATE ROUTINE | 使用CREATE PROCEDURE |
CREATE TEMPORARY TABLES | 使用CREATE TEMPORARY TABLE |
CREATE USER | 使用CREATE USER、DROP USER、RENAME USER和REVOKE ALL PRIVILEGES |
CREATE VIEW | 使用CREATE VIEW |
DELETE | 使用DELETE |
DROP | 使用DROP TABLE |
EXECUTE | 使用CALL和儲存過程 |
FILE | 使用SELECT INTO OUTFILE和LOAD DATA INFILE |
GRANT OPTION | 使用GRANT和REVOKE |
INDEX | 使用CREATE INDEX和DROP INDEX |
INSERT | 使用INSERT |
LOCK TABLES | 使用LOCK TABLES |
PROCESS | 使用SHOW FULL PROCESSLIST |
RELOAD | 使用FLUSH |
REPLICATION CLIENT | 伺服器位置的訪問 |
REPLICATION SLAVE | 由複製從屬使用 |
SELECT | 使用SELECT |
SHOW DATABASES | 使用SHOW DATABASES |
SHOW VIEW | 使用SHOW CREATE VIEW |
SHUTDOWN | 使用mysqladmin shutdown(用來關閉MySQL) |
SUPER | 使用CHANGE MASTER、KILL、LOGS、PURGE、MASTER 和SET GLOBAL。還允許mysqladmin除錯登入 |
UPDATE | 使用UPDATE |
USAGE | 無訪問許可權 |
,當某個資料庫或表被刪除時(用DROP語 句),相關的訪問許可權仍然存在。而且,如果將來重新建立該 資料庫或表,這些許可權仍然起作用。
未來的授權 在使用GRANT和REVOKE時,使用者賬號必須存在, 但對所涉及的物件沒有這個要求。這允許管理員在建立資料庫 和表之前設計和實現安全措施。 這樣做的副作用是,當某個資料庫或表被刪除時(用DROP語 句),相關的訪問許可權仍然存在。而且,如果將來重新建立該 資料庫或表,這些許可權仍然起作用。
簡化多次授權 可通過列出各許可權並用逗號分隔,將多條 GRANT語句串在一起,如下所示:
GRANT SELECT,INSERT ON crashcourse.* TO cc2;
資料庫維護
資料庫備份
像所有資料一樣,MySQL的資料也必須經常備份。由於MySQL資料 庫是基於磁碟的檔案,普通的備份系統和例程就能備份MySQL的資料。 但是,由於這些檔案總是處於開啟和使用狀態,普通的檔案副本備份不一定總是有效。
下面列出這個問題的可能解決方案。
- 使用命令列實用程式mysqldump轉儲所有資料庫內容到某個外部檔案。在進行常規備份前這個實用程式應該正常執行,以便能正 確地備份轉儲檔案。
- 可用命令列實用程式mysqlhotcopy從一個數據庫複製所有資料 (並非所有資料庫引擎都支援這個實用程式)。
- 可以使用MySQL的BACKUP TABLE或SELECT INTO OUTFILE轉儲所有資料到某個外部檔案。這兩條語句都接受將要建立的系統檔名,此係統檔案必須不存在,否則會出錯。資料可以用RESTORE TABLE來複原。
首先重新整理未寫資料 為了保證所有資料被寫到磁碟(包括索引資料),可能需要在進行備份前使用FLUSH TABLES語句。
資料庫維護
ANALYZE TABLE,用來檢查表鍵是否正確
如果從一個表中刪除大量資料,應該使用OPTIMIZE TABLE來收回所用的空間,從而優化表的效能。
診斷啟動問題
命令列mysqld手動啟動
檢視錯誤日誌
MySQL維護管理員依賴的一系列日誌檔案。主要的日誌檔案有以下幾種。
- 錯誤日誌。它包含啟動和關閉問題以及任意關鍵錯誤的細節。此 日誌通常名為hostname.err,位於data目錄中。此日誌名可用 --log-error命令列選項更改。
- 查詢日誌。它記錄所有MySQL活動,在診斷問題時非常有用。此 日誌檔案可能會很快地變得非常大,因此不應該長期使用它。此 日誌通常名為hostname.log,位於data目錄中。此名字可以用 --log命令列選項更改。
- 二進位制日誌。它記錄更新過資料(或者可能更新過資料)的所有 語句。此日誌通常名為hostname-bin,位於data目錄內。此名字 可以用--log-bin命令列選項更改。注意,這個日誌檔案是MySQL 5中新增的,以前的MySQL版本中使用的是更新日誌。
- 緩慢查詢日誌。顧名思義,此日誌記錄執行緩慢的任何查詢。這 個日誌在確定資料庫何處需要優化很有用。此日誌通常名為 hostname-slow.log ,位於data 目錄中。此名字可以用 --log-slow-queries命令列選項更改。 在使用日誌時,可用FLUSH LOGS語句來重新整理和重新開始所有日誌文 件。
在使用日誌時,可用FLUSH LOGS語句來重新整理和重新開始所有日誌檔案。
改善效能
- 首先,MySQL(與所有DBMS一樣)具有特定的硬體建議。在學 習和研究MySQL時,使用任何舊的計算機作為伺服器都可以。但 對用於生產的伺服器來說,應該堅持遵循這些硬體建議。
- 一般來說,關鍵的生產DBMS應該執行在自己的專用伺服器上。
- MySQL是用一系列的預設設定預先配置的,從這些設定開始通常是很好的。但過一段時間後你可能需要調整記憶體分配、緩衝區大小等。(為檢視當前設定,可使用SHOW VARIABLES;和SHOW STATUS;。)
- MySQL一個多使用者多執行緒的DBMS,換言之,它經常同時執行多個任務。如果這些任務中的某一個執行緩慢,則所有請求都會執行緩慢。如果你遇到顯著的效能不良,可使用SHOW PROCESSLIST 顯示所有活動程序(以及它們的執行緒ID和執行時間)。你還可以用KILL命令終結某個特定的程序(使用這個命令需要作為管理員登入) 。
- 總是有不止一種方法編寫同一條SELECT語句。應該試驗聯結、並、 子查詢等,找出最佳的方法。
- 使用EXPLAIN語句讓MySQL解釋它將如何執行一條SELECT語句。
- 一般來說,儲存過程執行得比一條一條地執行其中的各條MySQL語句快。
- 應該總是使用正確的資料型別。
- 決不要檢索比需求還要多的資料。換言之,不要用SELECT *(除 非你真正需要每個列)。
- 有的操作(包括INSERT)支援一個可選的DELAYED關鍵字,如果使用它,將把控制立即返回給呼叫程式,並且一旦有可能就實際執行該操作。
- 在匯入資料時,應該關閉自動提交。你可能還想刪除索引(包括 FULLTEXT索引),然後在匯入完成後再重建它們。
- 必須索引資料庫表以改善資料檢索的效能。確定索引什麼不是一件微不足道的任務,需要分析使用的SELECT語句以找出重複的 WHERE和ORDER BY子句。如果一個簡單的WHERE子句返回結果所花的時間太長,則可以斷定其中使用的列(或幾個列)就是需要索引的物件。
- 你的SELECT語句中有一系列複雜的OR條件嗎?通過使用多條SELECT語句和連線它們的UNION語句,你能看到極大的效能改 進。
- 索引改善資料檢索的效能,但損害資料插入、刪除和更新的效能。 如果你有一些表,它們收集資料且不經常被搜尋,則在有必要之 前不要索引它們。(索引可根據需要新增和刪除。)
- LIKE很慢。一般來說,最好是使用FULLTEXT而不是LIKE。
- 資料庫是不斷變化的實體。一組優化良好的表一會兒後可能就面 目全非了。由於表的使用和內容的更改,理想的優化和配置也會 改變。
- 最重要的規則就是,每條規則在某些條件下都會被打破。
0-9\. ↩︎