MyISAM與InnoDB
1.區別
MySQL默認是MyISAM;
(1)事務處理:
MyISAM不支持事物處理,InnoDB支持事務處理;
(2)鎖機制不同:
MyISAM是表級鎖,而InnoDB是行級鎖;
(3)select ,update ,insert ,delete 操作:
MyISAM:如果執行大量的SELECT,MyISAM是更好的選擇
InnoDB:如果你的數據執行大量的INSERT或UPDATE,出於性能方面的考慮,應該使用InnoDB表
(4)查詢表的行數不同:
MyISAM:select count() from table,MyISAM只要簡單的讀出保存好的行數,注意的是,當count()語句包含 where條件時,兩種表的操作是一樣的
InnoDB : InnoDB 中不保存表的具體行數,也就是說,執行select count(*) from table時,InnoDB要掃描一遍整個表來計算有多少行
(5)外鍵支持:
MyISAM表不支持外鍵,而InnoDB支持
2. MyISAM比Innodb 查詢速度快。
INNODB在做SELECT的時候,要維護的東西比MYISAM引擎多很多;1)數據塊,INNODB要緩存,MYISAM只緩存索引塊, 這中間還有換進換出的減少; 2)innodb尋址要映射到塊,再到行,MYISAM 記錄的直接是文件的OFFSET,定位比INNODB要快3)INNODB還需要維護MVCC一致;雖然你的場景沒有,但他還是需要去檢查和維護
MVCC ( Multi-Version Concurrency Control )多版本併發控制
3. 應用場景
MyISAM適合:
(1)做很多count 的計算;(2)插入不頻繁,查詢非常頻繁;(3)沒有事務。
InnoDB適合:
(1)可靠性要求比較高,或者要求事務;(2)表更新和查詢都相當的頻繁,並且行鎖定的機會比較大的情況。
索引
索引是對數據庫表中一列或多列的值進行排序的一種結構,使用索引可快速訪問數據庫表中的特定信息。合理的創建索引能夠提升查詢語句的執行效率,但降低了新增、刪除操作的速度,同時也會消耗一定的數據庫物理空間。
索引分類
普通索引、唯一索引、主鍵索引、組合索引、全文索引
1.普通索引
是最基本的索引,它沒有任何限制。它有以下幾種創建方式:(1)直接創建索引
CREATE INDEX index_name ON table(column(length))
(2)修改表結構的方式添加索引
ALTER TABLE table_name ADD INDEX index_name ON (column(length))
(3)創建表的時候同時創建索引
CREATE TABLE `table` (
`id` int(11) NOT NULL AUTO_INCREMENT ,
`title` char(255) CHARACTER NOT NULL ,
`content` text CHARACTER NULL ,
`time` int(10) NULL DEFAULT NULL ,
PRIMARY KEY (`id`),
INDEX index_name (title(length))
)
(4)刪除索引
DROP INDEX index_name ON table
2.唯一索引
與前面的普通索引類似,不同的就是:索引列的值必須唯一,但允許有空值。如果是組合索引,則列值的組合必須唯一。它有以下幾種創建方式:
(1)創建唯一索引
CREATE UNIQUE INDEX indexName ON table(column(length))
(2)修改表結構
ALTER TABLE table_name ADD UNIQUE indexName ON (column(length))
(3)創建表的時候直接指定
CREATE TABLE `table` (
`id` int(11) NOT NULL AUTO_INCREMENT ,
`title` char(255) CHARACTER NOT NULL ,
`content` text CHARACTER NULL ,
`time` int(10) NULL DEFAULT NULL ,
UNIQUE indexName (title(length))
);
3.主鍵索引
是一種特殊的唯一索引,一個表只能有一個主鍵,不允許有空值。一般是在建表的時候同時創建主鍵索引:
CREATE TABLE `table` (
`id` int(11) NOT NULL AUTO_INCREMENT ,
`title` char(255) NOT NULL ,
PRIMARY KEY (`id`)
);
4.組合索引
指多個字段上創建的索引,只有在查詢條件中使用了創建索引時的第一個字段,索引纔會被使用。使用組合索引時遵循最左前綴集合
複合索引還有一個優點,它通過被稱爲“最左前綴”(leftmost prefixing)的概念體現出來的。假設向一個表的多個字段(例如fristname、lastname、address)創建複合索引(索引名爲fname_lname_address).當where查詢條件是以下各種字段的組合是,MySQL將使用fname_lname_address索引。其他情況將無法使用fname_lname_address索引。可以理解:一個複合索引(firstname、lastname、address)等效於(firstname,lastname,address)、(firstname,lastname)以及(firstname)三個索引。基於最做前綴原則,應儘量避免創建重複的索引,例如,創建了fname_lname_address索引後,就無需再first_name子段上單獨創建一個索引
ALTER TABLE `table` ADD INDEX name_city_age (name,city,age);
5.全文索引
主要用來查找文本中的關鍵字,而不是直接與索引中的值相比較。fulltext索引跟其它索引大不相同,它更像是一個搜索引擎,而不是簡單的where語句的參數匹配。fulltext索引配合match against操作使用,而不是一般的where語句加like。它可以在create table,alter table ,create index使用,不過目前只有char、varchar,text 列上可以創建全文索引。值得一提的是,在數據量較大時候,現將數據放入一個沒有全局索引的表中,然後再用CREATE index創建fulltext索引,要比先爲一張表建立fulltext然後再將數據寫入的速度快很多。
(1)創建表的適合添加全文索引
CREATE TABLE `table` (
`id` int(11) NOT NULL AUTO_INCREMENT ,
`title` char(255) CHARACTER NOT NULL ,
`content` text CHARACTER NULL ,
`time` int(10) NULL DEFAULT NULL ,
PRIMARY KEY (`id`),
FULLTEXT (content)
);
(2)修改表結構添加全文索引
ALTER TABLE article ADD FULLTEXT index_content(content)
(3)直接創建索引
CREATE FULLTEXT INDEX index_content ON article(content)
聚集索引和非聚集索引
使用B+樹實現
索引優缺點
優點:
通過創建唯一性索引,可以保證數據庫表中每一行數據的唯一性。
可以大大加快數據的檢索速度,這也是創建索引的最主要的原因。
可以加速表和表之間的連接,特別是在實現數據的參考完整性方面特別有意義。
在使用分組和排序子句進行數據檢索時,同樣可以顯著減少查詢中分組和排序的時間。
通過使用索引,可以在查詢的過程中,使用優化隱藏器,提高系統的性能。
缺點:
創建索引和維護索引要耗費時間,這種時間隨着數據量的增加而增加。
索引需要佔物理空間,除了數據表佔數據空間之外,每一個索引還要佔一定的物理空間,如果要建立聚簇索引,那麼需要的空間就會更大。
當對錶中的數據進行增加、刪除和修改的時候,索引也要動態的維護,這樣就降低了數據的維護速度。
索引創建原則
適合條件:
在經常需要搜索的列上,可以加快搜索的速度;
在作爲主鍵的列上,強制該列的唯一性和組織表中數據的排列結構;
在經常用在連接的列上,這些列主要是一些外鍵,可以加快連接的速度;
在經常需要根據範圍進行搜索的列上創建索引,因爲索引已經排序,其指定的範圍是連續的;
在經常需要排序的列上創建索引,因爲索引已經排序,這樣查詢可以利用索引的排序,加快排序查詢時間;
在經常使用在WHERE子句中的列上面創建索引,加快條件的判斷速度。
不適條件:
在查詢中很少使用或者參考的列不應該創建索引。既然這些列很少使用到,因此有索引或者無索引,並不能提高查詢速度。相反,由於增加了索引,反而降低了系統的維護速度和增大了空間需求。
只有很少數據值的列也不應該增加索引。由於這些列的取值很少,例如人事表的性別列,在查詢的結果中,結果集的數據行佔了表中數據行的很大比例,即需要在表中搜索的數據行的比例很大。增加索引,並不能明顯加快檢索速度。
對於那些定義爲text, image和bit數據類型的列不應該增加索引。這些列的數據量要麼相當大,要麼取值很少。
當修改性能遠遠大於檢索性能時,不應該創建索引。修改性能和檢索性能是互相矛盾的。當增加索引時,會提高檢索性能,但是會降低修改性能。當減少 索引時,會提高修改性能,降低檢索性能。因此,當修改性能遠遠大於檢索性能時,不應該創建索引。
MySQL優化
選擇合適的引擎
MyISAM 索引順序訪問方法,支持全文索引,非事務安全,不支持外鍵,會加表級鎖
三個文件: FRM 存放表結構 MYD 存放數據 MYI 存放索引
InnoDB 事務型存儲引擎,加行鎖,支持回滾,崩潰恢復,ACID事務控制,表和索引放在一個表空間裏頭,表空間多個文件。
例: update tableset age=3 where name like "%jeff%"; //會鎖表
正確使用索引
給合適的列表建立索引,給where子句,連接子句建立索引,而不是select選擇列表
索引值應該不相同,唯一值時效果最好,大量重複效果很差
使用短索引,指定前綴長度
char(50)
的前20,30值唯一例:文件名
;索引緩存一定(小)時,存的索引多,消耗IO更小,能提高查找速度最左前綴n列索引,最左列的值匹配,更快。
like查詢,索引會失效,儘量少用like。百萬、千萬數據時,用like Sphinx開源方案結合MySQL
不能濫用索引
1.索引佔用空間 2.更新數據,索引必須更新,時間長,儘量不要用在長期不用的字段上建立索引 3.SQL執行一個查詢語句,增加查詢優化的時間
避免使用
SELECT *
返回結果過多,降低查詢的速度
過多的返回結果,會增大服務器返回給APP端的數據傳輸量。例:
網絡傳輸速度面,弱網絡環境下,容易造成請求失效
字段儘量設置爲NOT NULL
"" 和 NULL {"name":"myf"} {"name":""} {"hobby":空array} NULL佔空間 例:安卓需要判斷""還是NULL Java和OC都是強類型,會造成APP閃退
範式
1NF: 字段是最小的的單元不可再分
2NF:滿足1NF,表中的字段必須完全依賴於全部主鍵而非部分主鍵
3NF:滿足2NF,非主鍵外的所有字段必須互不依賴
巴斯-科德範式(BCNF):在3NF基礎上,任何非主屬性不能對主鍵子集依賴(在3NF基礎上消除對主碼子集的依賴)
4NF
第一範式(1NF):確保每一列的原子性
如果每一列都是不可再分的最小數據單元,則滿足第一範式。
id 地址 1 中國廣東 2 中國雲南 上面的表地址字段其實可以繼續分:
id 國家 省份 1 中國 廣東 2 中國 雲南 但是具體地址到底要不要拆分 還要看具體情形,比如看看將來會不會按國家或者省市進行分類彙總或者排序,如果需要,最好就拆,如果不需要而僅僅起字符串的作用,可以不拆,操作起來更方便。
第二範式:非鍵字段必須依賴於鍵字段
如果一個關係滿足1NF,並且除了主鍵以外的其它列,都依賴與該主鍵,則滿足二範式(2NF),第二範式要求每個表只描述一件事。
例如:
字段 例子 訂單編號 001 產品編號 a011 訂購日期 2017-4-8 價格 ¥30 而實際上,產品編號與訂單編號並沒有明確的關係,訂購日期與訂單編號有關係,因爲一旦訂單編號確定下來了,訂購日期也確定了,價格與訂單編號也沒有直接關係,而與產品有關,所以上面的表實際上可以拆分:
訂單表:
訂單編號 001 日期 2017-4-8 產品表:
產品編號 a011 價格 ¥30 第三範式:在1NF基礎上,除了主鍵以外的其它列都不傳遞依賴於主鍵列,或者說: 任何非主屬性不依賴於其它非主屬性
(在2NF基礎上消除傳遞依賴)
例如:
字段 例子 訂單編號 001 訂購日期 2017-4-8 顧客編號 a01 顧客姓名 howard 上面的滿足第一和第二範式,但是不滿足第三範式,原因如下:
通過顧客編號可以確定顧客姓名,通過顧客姓名可以確定顧客編號,即在這個訂單表裏,這兩個字段存在傳遞依賴,只需要一個就夠了。
又如:
主鍵 學號 姓名 成績 1 111 howard 90 2 222 tom 90 上面的表,學號和姓名存在傳遞依賴,因爲(學號,姓名)->成績,學號->成績,姓名->成績。所以學號和姓名有一個冗餘了,只需要保留一個。
事務
所謂事務,是指用戶的一個數據庫操作序列,這些操作要麼全做要麼全不做,是一個不可分割的工作。事物具有四個特性:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)和持續性(Durability)。這四種特性簡稱未ACID特性。
事務ACID特性
原子性:整個事務中的所有操作,要麼全部完成,要麼全部不完成,不可能停滯在中間某個環節。事務在執行過程中發生錯誤,會被回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。
一致性:在事務開始之前和事務結束以後,數據庫的完整性約束沒有被破壞。
隔離性:隔離狀態執行事務,使它們好像是系統在給定時間內執行的唯一操作。如果有兩個事務,運行在相同的時間內,執行相同的功能,事務的隔離性將確保每一事務在系統中認爲只有該事務在使用系統。這種屬性有時稱爲串行化,爲了防止事務操作間的混淆,必須串行化或序列化請求,使得在同一時間僅有一個請求用於同一數據。
持久性:在事務完成以後,該事務所對數據庫所作的更改便持久的保存在數據庫之中,並不會被回滾。
事務併發性問題
當多個線程都開啓事務操作數據庫中的數據時,數據庫系統要能進行隔離操作,以保證各個線程獲取數據的準確性,在介紹數據庫提供的各種隔離級別之前,如果不考慮事務的隔離性,會發生的幾種問題:
髒讀
髒讀是指在一個事務處理過程裏讀取了另一個未提交的事務中的數據。
當一個事務正在多次修改某個數據,而在這個事務中這多次的修改都還未提交,這時一個併發的事務來訪問該數據,就會造成兩個事務得到的數據不一致。例如:用戶A向用戶B轉賬100元,對應SQL命令如下
update account set money=money+100 where name=’B’; (此時A通知B)
update account set money=money - 100 where name=’A’;
當只執行第一條SQL時,A通知B查看賬戶,B發現確實錢已到賬(此時即發生了髒讀),而之後無論第二條SQL是否執行,只要該事務不提交,則所有操作都將回滾,那麼當B以後再次查看賬戶時就會發現錢其實並沒有轉。
不可重複讀
不可重複讀是指在對於數據庫中的某個數據,一個事務範圍內多次查詢卻返回了不同的數據值,這是由於在查詢間隔,被另一個事務修改並提交了。
例如事務T1在讀取某一數據,而事務T2立馬修改了這個數據並且提交事務給數據庫,事務T1再次讀取該數據就得到了不同的結果,發送了不可重複讀。
不可重複讀和髒讀的區別是,髒讀是某一事務讀取了另一個事務未提交的髒數據,而不可重複讀則是讀取了前一事務提交的數據。
在某些情況下,不可重複讀並不是問題,比如我們多次查詢某個數據當然以最後查詢得到的結果爲主。但在另一些情況下就有可能發生問題,例如對於同一個數據A和B依次查詢就可能不同,A和B就可能打起來了……
虛讀(幻讀)
幻讀是事務非獨立執行時發生的一種現象。例如事務T1對一個表中所有的行的某個數據項做了從“1”修改爲“2”的操作,這時事務T2又對這個表中插入了一行數據項,而這個數據項的數值還是爲“1”並且提交給數據庫。而操作事務T1的用戶如果再查看剛剛修改的數據,會發現還有一行沒有修改,其實這行是從事務T2中添加的,就好像產生幻覺一樣,這就是發生了幻讀。
幻讀和不可重複讀都是讀取了另一條已經提交的事務(這點就髒讀不同),所不同的是不可重複讀查詢的都是同一個數據項,而幻讀針對的是一批數據整體(比如數據的個數)。
小結:不可重複讀的和幻讀很容易混淆,不可重複讀側重於修改,幻讀側重於新增或刪除。解決不可重複讀的問題只需鎖住滿足條件的行,解決幻讀需要鎖表
事務四種隔離級別
未提交讀
事務中的修改,即使沒有提交,對其他事務也是可見的。
提交讀
一個事務讀取已經提交的事務所做的修改。即,一個事務所做的修改在提交前對其他事務是不可見的。
可重複讀
保證在同一個事務中多次讀取多樣的數據的結果是一樣的。
可串行化
強制事務串行執行。
事務隔離級別 | 髒讀 | 不可重複讀 | 幻讀 |
---|---|---|---|
未提交讀(read-uncommitted) | 是 | 是 | 是 |
提交讀(read-committed) | 否 | 是 | 是 |
可重複讀(repeatable-read) | 否 | 否 | 是 |
序列化(serializable) | 否 | 否 | 否 |
*mysql默認的事務隔離級別爲repeatable-read
存儲過程
SQL語句執行的時候要先編譯,然後被執行。在大型數據庫中,爲了提高效率,將爲了完成特定功能的SQL語句集進行編譯優化後,存儲在數據庫服務器中,用戶通過特定存儲過程的名字來調用執行。
#創建存儲過程常用語法如下: creat procedure sp_name @[參數名][類型] as begin …… end #調用存儲過程語法:CALL sp_name[參數名] # 刪除存儲過程語法:drop procedure sp_name
使用存儲過程可以增強SQL語言的功能和靈活性,由於可以用流程控制語句編寫存儲過程,有很強的靈活性,所以可以完成複雜的判斷和運算,並且可以保證數據的安全性和完整性,同時存儲過程可以使沒有權限的用戶在控制之下間接地存取數據庫,保證了數據的安全。
但存儲過程不等於函數,兩者雖然本質上沒有區別,但具體而言有以下幾個方面的區別:
1. 存儲過程一般是作爲一個獨立的部分來執行的,而函數可以作爲查詢語句的一個部分來調用。由於函數可以返回一個對象,因此它可以在查詢語句中位於From關鍵字後面。 2. 一般而言,存儲過程的功能較複雜,而函數實現的功能針對性比較強。 3. 函數需要用括號包住輸入的參數,且返回一個值或表對象,存儲過程可以返回多個參數。 4. 函數可以嵌入在SQL中使用,可以在select中調用,存儲過程不可以。 5. 函數不能直接操作實體表,只能操作內建表。 6. 存儲過程在創建時即在服務器上進行編譯,執行速度更快。
視圖
視圖:是從一個或多個表導出的虛擬的表,其內容由查詢定義。具有普通表的結構,但是不實現數據存儲。
對視圖的修改:單表視圖一般用於查詢和修改,會改變基本表的數據,多表視圖一般用於查詢,不會改變基本表的數據。
--創建視圖-- create or replace view v_student as select * from student; --從視圖中檢索數據-- select * from v_student; --刪除視圖-- drop view v_student;
作用:
簡化了操作,把經常使用的數據定義爲視圖。
我們在使用查詢時,在很多時候我們要使用聚合函數,同時還要 顯示其它字段的信息,可能還會需要關聯到其它表,這時寫的語句可能會很長,如果這個動作頻繁發生的話,我們可以創建視圖,這以後,我們只需要select * from view就可以了,這樣很方便。
安全性,用戶只能查詢和修改能看到的數據。
因爲視圖是虛擬的,物理上是不存在的,只是存儲了數據的集合,我們可以將基表中重要的字段信息,可以不通過視圖給用戶,視圖是動態的數據的集合,數據是隨着基表的更新而更新。同時,用戶對視圖不可以隨意的更改和刪除,可以保證數據的安全性。
邏輯上的獨立性,屏蔽了真實表的結構帶來的影響。
視圖可以使應用程序和數據庫表在一定程度上獨立。如果沒有視圖,應用一定是建立在表上的。有了視圖之後,程序可以建立在視圖之上,從而程序與數據庫表被視圖分割開來。
缺點:
性能差
數據庫必須把視圖查詢轉化成對基本表的查詢,如果這個視圖是由一個複雜的多表查詢所定義,那麼,即使是視圖的一個簡單查詢,數據庫也要把它變成一個複雜的結合體,需要花費一定的時間。
修改限制
當用戶試圖修改視圖的某些信息時,數據庫必須把它轉化爲對基本表的某些信息的修改,對於簡單的視圖來說,這是很方便的,但是,對於比較複雜的試圖,可能是不可修改的。
觸發器
觸發器是一種特殊的存儲過程,它由事件觸發,而不是程序調用或手工啓動。當數據庫有特殊的操作時,對這些操作由數據庫中的事件來觸發,自動完成這些SQL語句。使用觸發器可以用來保證數據的有效性和完整性,完成比約束更復雜的數據約束。
根據SQL語句不同,觸發器可分爲兩類:DML觸發器和DLL觸發器。
DML觸發器是當數據庫服務器發生數據操作語言事件執行的存儲過程,有After和Instead of兩種觸發器。After觸發器被激活觸發是在記錄改變之後進行的一種觸發器。Instead Of觸發器是記錄變更之前,去執行觸發器本身定位的操作,而不是執行原來SQL語句裏的操作。DLL觸發器是在響應數據定義語言事件執行的存儲過程。
數據庫鎖
數據庫鎖定機制簡單來說,就是數據庫爲了保證數據的一致性,而使各種共享資源在被併發訪問變得有序所設計的一種規則。對於任何一種數據庫來說都需要有相應的鎖定機制,所以MySQL自然也不能例外。MySQL數據庫由於其自身架構的特點,存在多種數據存儲引擎,每種存儲引擎所針對的應用場景特點都不太一樣,爲了滿足各自特定應用場景的需求,每種存儲引擎的鎖定機制都是爲各自所面對的特定場景而優化設計,所以各存儲引擎的鎖定機制也有較大區別。MySQL各存儲引擎使用了三種類型(級別)的鎖定機制:表級鎖定,行級鎖定和頁級鎖定。
數據庫日誌
日誌文件記錄所有對數據庫數據的修改,主要是保護數據庫防止故障,以及恢復數據時使用。特點如下:
1. 每一個數據庫至少包含兩個日誌文件組。每個日誌文件組至少包含兩個日誌文件成員。 2. 日誌文件組以循環方式進行寫操作。
每一個日誌文件對應一個物理文件。
通過日誌文件來記錄數據庫事物可以最大限度保證數據庫的一致性與安全性,但一旦數據庫中日誌滿了,就只能執行查詢等操作,不能執行更改、備份等操作。其原因是任何寫操作都要記錄日誌,也就是說基本上處於不能使用的狀態。
待續。。。