Mysql、索引

索引

數據庫中的查詢操作非常普遍,索引就是提升查找速度的一種手段

索引的類型
從數據結構角度分

1.B+索引:
傳統(tǒng)意義上的索引,最常用最普遍的索引
2.hash索引:
hash索引是一種自適應的索引,數據庫會根據表的使用情況自動生成hash索引,人為無法干預
3.全文索引:
用于實現關鍵詞搜索,但它只能根據空格分詞,因此不支持中文,可以使用lucene實現搜索功能
4.RTree索引:
在mysql很少使用,僅支持geometry數據類型;相對于BTREE,RTREE的優(yōu)勢在于范圍

物理存儲角度

數據庫以頁為存儲單位,一個頁有8K(8192byte),一頁存放N條記錄

在B+樹中分為數據頁和索引頁
B+樹的高一般為2-4層,因為查找某一鍵值的記錄只需要2-4次I/O,效率較高

image.png

1.聚集索引(也叫聚簇索引)
2.非聚集索引
好文:
[https://www.cnblogs.com/s-b-b/p/8334593.html]
不管是聚集索引還是非聚集索引他們的結構都是B+樹,他們的唯一區(qū)別是
聚集索引的數據頁存放的是完整的記錄,也就是說,聚集索引決定了表的物理存儲順序
非聚集索引的數據頁中存放的是指向記錄的地址信息,他真正的數據已經在聚集索引中存儲了
 1、聚集索引一個表只能有一個,而非聚集索引一個表可以存在多個
 2、聚集索引存儲記錄是物理上連續(xù)存在,而非聚集索引是邏輯上的連續(xù),物理存儲并不連續(xù)

在聚集索引中,表中行的物理順序與鍵值的邏輯(索引)順序相同,一個表只能包含一個聚集索引,聚集索引比非聚集索引有更快的訪問速度
索引是在存儲引擎層實現的,而不是在服務器層實現的,所以不同存儲引擎具有不同的索引類型和實現。
術語“聚簇”表示數據行和相鄰的鍵值緊密地存儲在一起,InnoDB 的聚簇索引的數據行存放在 B+Tree 的葉子頁中。
因為無法把數據行存放在兩個不同的地方,所以一個表只能有一個聚簇索引。

優(yōu)點
  1. 可以把相關數據保存在一起,減少 I/O 操作;
  2. 因為數據保存在 B+Tree 中,因此數據訪問更快。
    缺點
  3. 聚簇索引最大限度提高了 I/O 密集型應用的性能,但是如果數據全部放在內存,就沒必要用聚簇索引。
  4. 插入速度嚴重依賴于插入順序,按主鍵的順序插入是最快的。
  5. 更新操作代價很高,因為每個被更新的行都會移動到新的位置。
  6. 當插入到某個已滿的頁中,存儲引擎會將該頁分裂成兩個頁面來容納該行,頁分裂會導致表占用更多的磁盤空間。
  7. 如果行比較稀疏,或者由于頁分裂導致數據存儲不連續(xù)時,聚簇索引可能導致全表掃描速度變慢。
邏輯角度

1.普通索引:索引值不唯一
2.唯一索引:唯一索引是不允許任意兩行具有相同索引值的索引,當現有數據庫中存在重復鍵值的時候,大多數數據庫不允許將唯一索引和數據庫表相關聯(lián),當現有數據中存在重復的鍵值時,大多數數據庫不允許將新創(chuàng)建的唯一索引與表一起保存。數據庫還可能防止添加將在表中創(chuàng)建重復鍵值的新數據。例如,如果在employee表中職員的姓(lname)上創(chuàng)建了唯一索引,則任何兩個員工都不能同姓。
3.主鍵索引:數據庫中經常有一列或幾列的組合,其值能唯一標識表中的每一行,該列稱為主鍵。在數據庫關系圖中表為主鍵自動創(chuàng)建主鍵索引,主鍵索引是唯一索引的特定類型,該索引要求主鍵中的每個值都唯一。當在查詢中使用主鍵索引時,它還允許對數據的快速訪問。
4.空間索引

主鍵和唯一索引的區(qū)別:
1.一個表可以有多個唯一索引,而主鍵只能有一個
2.主鍵可以作為其它表的外鍵
3.主鍵不可以為null,而唯一索引可以為null
主鍵就是聚焦索引”這是極端錯誤的,是對聚焦索引的一種浪費。
主鍵并不一定是聚集索引,只是在SQL SERVER中,未明確指出的情況下,默認將主鍵定義為聚集,而ORACLE中則默認是非聚集

其它索引

1.聯(lián)合索引:又叫復合索引,Mysql從左到右使用索引中的字段,一個查詢可以只使用索引的一部分,但必須是最左側的部分。例如索引是key index (a,b,c). 可以支持a | a,b| a,b,c 3種組合進行查找,但不支持 b,c進行查找 .當最左側字段是常量引用時,索引就十分有效。符合最左原則
聯(lián)合索引實現:每個節(jié)點含有多個關鍵字,排序時按照多個關鍵字的順序進行排序。而這個順序就是你創(chuàng)建索引時候的順序
如果你經常要用到多個字段的多條件查詢,可以考慮建立聯(lián)合索引,建立了一個聯(lián)合索引就相當于建立了多個索引
聯(lián)合索引sql會先過濾出last_name符合條件的記錄,在其基礎上再過濾first_name符合條件的記錄。那如果我們分別在last_name和first_name上創(chuàng)建兩個列索引,mysql的處理方式就不一樣了,它會選擇一個最嚴格的索引來進行檢索,可以理解為檢索能力最強的那個索引來檢索,另外一個利用不上了,這樣效果就不如多列索引了。雖然此時有了兩個單列索引,但 MySQL 只能用到其中的那個它認為似乎是最有效率的單列索引。如果經常使用單獨一列作為查詢條件,那么應該使用單列索引。(如有兩個單列索引a、b,查詢的時候只用a或只用b)。
多列建索引比對每個列分別建索引更有優(yōu)勢,因為索引建立得越多就越占磁盤空間,在更新數據的時候速度會更慢。另外建立多列索引時,順序也是需要注意的,應該將嚴格的索引放在前面,這樣篩選的力度會更大,效率更高
2.覆蓋索引:只需要通過輔助索引就可以獲取查詢的信息,而無需再通過聚集索引查詢具體的記錄信息
由于覆蓋索引不包含整行的記錄,因此它的大小遠小于聚集索引
比較適合做一些統(tǒng)計操作

索引的創(chuàng)建

在表上創(chuàng)建一個簡單的索引,允許使用重復的值

CREATE INDEX index_name
ON table_name (column_name)

在表上創(chuàng)建一個唯一的索引。唯一的索引意味著兩個行不能擁有相同的索引值。

CREATE UNIQUE INDEX index_name
ON table_name (column_name)

假如您希望索引不止一個列,您可以在括號中列出這些列的名稱,用逗號隔開:

CREATE INDEX PersonIndex
ON Person (LastName, FirstName)

創(chuàng)建索引還可以用alter實現
InnoDB按照主鍵進行聚集,如果沒有定義主鍵,InnoDB會試著使用唯一的非空索引來代替。如果沒有這種索引,InnoDB就會定義隱藏的主鍵(6個字節(jié))然后在上面進行聚集。mysql不能手動創(chuàng)建聚集索引。
主鍵索引是一種特殊的唯一索引,不允許有空值。一般是在建表的時候同時創(chuàng)建主鍵索引

索引的實現

一般來說,索引本身也很大,不可能全部存儲在內存中,因此索引往往以索引文件的形式存儲的磁盤上。這樣的話,索引查找過程中就要產生磁盤I/O消耗,相對于內存存取,I/O存取的消耗要高幾個數量級,而B+Tree的高度低(多叉樹),可以減少I/O次數
InnoDB(聚簇索引)的數據文件本身就是索引文件(索引和數據存放在一個文件idb)。從上文知道,MyISAM(非聚簇索引)索引文件(MYI)和數據文件(MYD)是分離的,索引文件僅保存數據記錄的地址。
mysql中每個表都有一個聚簇索引(clustered index ),除此之外的表上的每個非聚簇索引都是二級索引(普通索引、唯一索引),又叫輔助索引(secondary indexes)。

實現區(qū)別

MyISAM引擎使用B+Tree作為索引結構,葉結點的data域存放的是數據記錄的地址。MyISAM的索引方式也叫做“非聚集”的。
MyISAM左圖為主索引,右圖為輔助索引(二級索引),兩者在結構上沒什么區(qū)別,都是B+樹。


image.png

雖然InnoDB也使用B+Tree作為索引結構,但具體實現方式卻與MyISAM截然不同。


image.png

InnoDB左圖為主索引、右圖為輔助索引,輔助索引結構也是B+樹
第一個重大區(qū)別是InnoDB的數據文件本身就是索引文件。從上文知道,MyISAM索引文件和數據文件是分離的,索引文件僅保存數據記錄的地址。而在InnoDB中,表數據文件本身就是按B+Tree組織的一個索引結構,這棵樹的葉結點data域保存了完整的數據記錄。這個索引的key是數據表的主鍵,因此InnoDB表數據文件本身就是主索引。
第二個與MyISAM索引的不同是InnoDB的輔助索引data域存儲相應記錄主鍵的值而不是地址。換句話說,InnoDB的所有輔助索引都引用主鍵作為data域。

這里以英文字符的ASCII碼作為比較準則(排序)。聚集索引這種實現方式使得按主鍵的搜索十分高效,但是輔助索引搜索需要檢索兩遍索引:首先檢索輔助索引獲得主鍵,然后用主鍵到主索引中檢索獲得記錄。
由于實際的數據頁只能按照一顆B+樹進行排序,因此每張表只能有一個聚集索引。

SQL語句的執(zhí)行順尋

from--where--group by--having--select--order by

Mysql中查看索引

使用“執(zhí)行過程”EXPLAIN,查看索引使用情況,查詢的覆蓋行數等
EXPLAIN SELECT * FROM user WHERE id = 10


image.png

B樹和紅黑樹

B樹主要是保證只有少數的磁盤訪問(io次數少),解決數據結構不在主存中的數據存儲問題。高度低。某一個節(jié)點可以看做一個磁盤塊,里面含有指向下一個磁盤塊的指針。


image.png

關鍵嗎就是上圖磁盤塊中的數字

B樹從最后一層開始插入,涉及到節(jié)點的分裂
一棵含n個結點的B樹的高度也為O(logn),但可能比一棵紅黑樹的高度小許多,應為它的分支因子比較大。所以,B樹可以在O(logn)時間內,實現各種如插入(insert),刪除(delete)等動態(tài)集合操作。
“階”定義為一個節(jié)點的子節(jié)點數目的最大值(非根節(jié)點關鍵字個數m/2向上取整-m-1個)

B+樹
image.png

image.png

只有葉節(jié)點存數據,非葉節(jié)點都只是下層節(jié)點最大值的復寫。葉子節(jié)點間多了指針,使得范圍查找變得高效(如上圖查找20到65)

紅黑樹:
image.png

性質1. 節(jié)點是紅色或黑色。
性質2. 根是黑色。
性質3. 所有葉子都是黑色(葉子是NIL節(jié)點,空節(jié)點)。
性質4. 每個紅色節(jié)點的兩個子節(jié)點都是黑色。
性質5. 從任一節(jié)點到其每個葉子的所有簡單路徑 都包含相同數目的黑色節(jié)點。

在進行紅黑樹的構造的時候,為了滿足第5點,則必須每次插入的節(jié)點顏色預設為紅色,插入后,有可能會導致4不滿足,然后進行節(jié)點調整。所以如果是構造出來的,一般來說,不會有節(jié)點全黑的紅黑樹
查找、插入、刪除等操作的時間復雜度為O(logn), 且最多旋轉三次
紅黑是用非嚴格的平衡來換取增刪節(jié)點時候旋轉次數的降低,任何不平衡都會在三次旋轉之內解決,而AVL是嚴格平衡樹,因此在增加或者刪除節(jié)點的時候,根據不同情況,旋轉的次數比紅黑樹要多。所以紅黑樹的插入效率更高?。?!
不能有連續(xù)2個的紅節(jié)點,紅黑樹也是二叉查找樹
紅黑樹的平衡性:最差情況,一棵子樹全是黑色,一棵子樹一紅一黑····,高度最多差一倍(保證黑色數量相同)
紅黑樹插入時,插入節(jié)點的叔叔是黑節(jié)點:也是類似于avl樹中的單旋轉,雙旋轉,并改變著色;插入節(jié)點的叔叔是紅節(jié)點:直接重新著色,并再繼續(xù)向上調整
紅黑樹某一結點,如果只有一個兒子(如左),那么該結點為黑結點且兒子為紅結點,若該結點為紅結點,則朝右結點(沒有)方向沒有黑結點,朝左結點方向有一個黑結點,導致不平衡


image.png

刪除一個黑色葉結點時需要較復雜的調整,(刪除非葉結點情況,可以從葉結點找一個跟該結點替換,從而變成刪除葉結點的情況)

數據庫引擎

InnoDB和MyISAM區(qū)別

Oracle收購sun(sun之前收購了MySQL),發(fā)布的首個版本5.5,默認使用了InnoDB作為存儲引擎,而之前的版本使用MyISAM作為默認。
MyISAM 和 InnoDB的適用場景
MyISAM適合:讀多寫少(1)做很多count 的計算;(2)插入不頻繁,查詢非常頻繁;(3)沒有事務。
InnoDB適合:寫多讀少(1)可靠性要求比較高,或者要求事務;(2)表更新和查詢都相當的頻繁,并且表鎖定的機會比較大的情況。

為什么MyISAM會比Innodb 的查詢速度快

INNODB在做SELECT的時候,要維護的東西比MYISAM引擎多很多;
1)數據塊,INNODB要緩存,MYISAM只緩存索引塊,這中間還有換進換出的減少;
2)innodb尋址要映射到塊,再到行,MYISAM 記錄的直接是文件的OFFSET,定位比INNODB要快
3)INNODB還需要維護MVCC一致;雖然你的場景沒有,但他還是需要去檢查和維護MVCC ( Multi-Version Concurrency Control )多版本并發(fā)控制(讀不加鎖,讀寫不沖突。)
(具體看下面Mysql中InnoDB的MVCC)

兩種類型最主要的差別就是Innodb 支持事務處理與外鍵和行級鎖

1.存儲結構
每個MyISAM在磁盤上存儲成三個文件。第一個文件的名字以表的名字開始,擴展名指出文件類型。.frm文件存儲表定義;數據文件的擴展名為.MYD (MYData);索引文件的擴展名是.MYI (MYIndex)。
InnoDB:.ibd的文件,存儲與該表相關的數據、索引、表的內部數據字典(表緩存)信息;.frm表結構文件。
2.數據導出:
MyISAM只要發(fā)給他們對應那表的frm.MYD,MYI的文件,讓他們自己在對應版本的數據庫啟動就行,而Innodb就需要導出xxx.sql了,因為光給別人文件,受字典數據文件的影響,對方是無法使用的。
3.、MyISAM的索引和數據是分開的,并且索引是有壓縮的,內存使用率就對應提高了不少,能加載更多索引。而Innodb是索引和數據是緊密捆綁的,沒有使用壓縮從而會造成Innodb占用空間較大
4.MyISAM存儲空間幾乎沒有限制,最多可到64PB,InnoDB最多64TB
5.InnoDB支持事務(每條sql都是事務,默認配置事務自動提交)和外鍵,MyISAM不支持
6.對于AUTO_INCREMENT類型的字段,InnoDB中必須包含只有該字段的索引,但是在MyISAM表中,可以和其他字段一起建立聯(lián)合索引。
7.MyISAM:只支持表級鎖,select,update,delete,insert語句都會給表自動加鎖
InnoDB:支持行級鎖,但是InnoDB的行鎖,只是在WHERE的主鍵(唯一索引)是有效的,非主鍵的WHERE都會鎖全表的。對索引加鎖,而不是對數據行加鎖,只有當查詢條件能使用索引的時候才會使用行級鎖
兩者鎖讀的時候共享鎖、寫的時候排它鎖(可以一起讀,不能一起寫或讀寫)
8.全文索引(通過關鍵字匹配來查詢)
MyISAM:支持 FULLTEXT類型的全文索引
InnoDB:不支持FULLTEXT類型的全文索引,但是innodb可以使用sphinx插件支持全文索引,并且效果更好。(從5.6開始支持,但不支持中文索引)
9.表的具體行數
MyISAM:保存有表的總行數,如果select count() from table;會直接取出出該值。
InnoDB:沒有保存表的總行數,如果使用select count(
) from table;就會遍歷整個表,消耗相當大,但是在加了wehre條件后,myisam和innodb處理的方式都一樣。
10.CURD操作
MyISAM:如果執(zhí)行大量的SELECT,MyISAM是更好的選擇。
InnoDB:如果你的數據執(zhí)行大量的INSERT或UPDATE,出于性能方面的考慮,應該使用InnoDB表。DELETE 從性能上InnoDB更優(yōu),但DELETE FROM table時,InnoDB不會重新建立表,而是一行一行的刪除

image.png

Mysql其它引擎

Blackhole引擎,它會丟棄所有插入的數據,不做任何保存。但會記錄日志。
CSV引擎,可以將CSV文件作為MySQL表來處理,可以作為一種數據交換機制。
Memory引擎,數據存在內存中,訪問速度快,重啟后數據會丟失。
Merge引擎,是MyISAM的變種,由多個MyISAM表合并而來的虛擬表。

事務的四大特性

1、原子性(Atomicity):事務中的全部操作在數據庫中是不可分割的,要么全部完成,要么均不執(zhí)行。
2、一致性(Consistency):幾個并行執(zhí)行的事務,其執(zhí)行結果必須與按某一順序串行執(zhí)行的結果相一致。事務必須是使數據庫從一個一致性狀態(tài)變到另一個一致性狀態(tài)。多個賬戶錢的總和不變
3、隔離性(Isolation):事務的執(zhí)行不受其他事務的干擾,事務執(zhí)行的中間結果對其他事務必須是透明的。(即事務隔離級別)(轉錢時,從其他用戶角度看)
4、持久性(Durability):對于任意已提交事務,系統(tǒng)必須保證該事務對數據庫的改變不被丟失,即使數據庫出現故障。

事務的一致性

1.強一致性:讀操作可以立即讀到提交的更新操作。
2.弱一致性:提交的更新操作,不一定立即會被讀操作讀到,此種情況會存在一個不一致窗口,指的是讀操作可以讀到最新值的一段時間。
3.最終一致性:事務更新一份數據,最終一致性保證在沒有其他事務更新同樣的值的話,最終所有的事務都會讀到之前事務更新的最新值。如果沒有錯誤發(fā)生,不一致窗口的大小依賴于:通信延遲,系統(tǒng)負載等。
其他一致性變體還有:
單調一致性:如果一個進程已經讀到一個值,那么后續(xù)不會讀到更早的值。
會話一致性:保證客戶端和服務器交互的會話過程中,讀操作可以讀到更新操作后的最新值。

事務的隔離級別

1.臟讀:臟讀是指在一個事務處理過程里讀取了另一個未提交的事務中的數據。
當一個事務正在多次修改某個數據,而在這個事務中這多次的修改都還未提交,這時一個并發(fā)的事務來訪問該數據,就會造成兩個事務得到的數據不一致。例如:用戶A向用戶B轉賬100元
  當只執(zhí)行第一條SQL時,A通知B查看賬戶,B發(fā)現確實錢已到賬(此時即發(fā)生了臟讀),而之后無論第二條SQL是否執(zhí)行,只要該事務不提交,則所有操作都將回滾,那么當B以后再次查看賬戶時就會發(fā)現錢其實并沒有轉。
2.不可重復讀:不可重復讀是指在對于數據庫中的某個數據,一個事務范圍內多次查詢卻返回了不同的數據值,這是由于在查詢間隔,被另一個事務修改并提交了。不可重復讀出現的原因就是事務并發(fā)修改記錄,要避免這種情況,最簡單的方法就是對要修改的記錄加鎖,這回導致鎖競爭加劇,影響性能。另一種方法是通過MVCC可以在無鎖的情況下,避免不可重復讀。
例如事務T1在讀取某一數據,而事務T2立馬修改了這個數據并且提交事務給數據庫,事務T1再次讀取該數據就得到了不同的結果,發(fā)送了不可重復讀。
  不可重復讀和臟讀的區(qū)別是,臟讀是某一事務讀取了另一個事務未提交的臟數據,而不可重復讀則是讀取了前一事務提交的數據。
3,虛讀(幻讀)
在同一個事務中,同一個查詢多次返回的結果不一致。事務A新增了一條記錄,事務B在事務A提交前后各執(zhí)行了一次查詢操作,發(fā)現后一次比前一次多了一條記錄。就好像產生幻覺一樣,這就是發(fā)生了幻讀?;米x是由于并發(fā)事務增加記錄導致的,這個不能像不可重復讀通過記錄加鎖解決,因為對于新增的記錄根本無法加鎖。需要將事務串行化,才能避免幻讀。
  幻讀和不可重復讀都是讀取了另一條已經提交的事務(這點就臟讀不同),所不同的是不可重復讀查詢的都是同一個數據項,而幻讀針對的是一批數據整體(比如數據的個數)。

MySQL數據庫的四種隔離級別(從低到高、為解決并發(fā)事務問題):

①Read uncommitted (讀未提交):最低級別,任何情況都無法保證。
②Read committed (讀已提交):只有在事務提交后,其更新結果才會被其他事務看見。可避免臟讀的發(fā)生。

③Repeatable read (可重復讀):在一個事務中,對于同一份數據的讀取結果總是相同的,無論是否有其他事務對這份數據進行操作,以及這個事務是否提交??杀苊馀K讀、不可重復讀的發(fā)生。
④Serializable (串行化):事務串行化執(zhí)行,隔離級別最高,犧牲了系統(tǒng)的并發(fā)性??杀苊馀K讀、不可重復讀、幻讀的發(fā)生。
  在MySQL數據庫中,支持上面四種隔離級別,默認的為Repeatable read (可重復讀);而在Oracle數據庫中,只支持Serializable (串行化)級別和Read committed (讀已提交)這兩種級別,其中默認的為Read committed級別。

為什么Mysql能保證失敗回滾

進行事務處理的時候,MySQL 在開始事務時會切換到一個延緩操作的狀態(tài),這個狀態(tài)下操作并不都是立即執(zhí)行的(通常情況下語句是立即執(zhí)行的)。而在 commit 時,會將延緩執(zhí)行的操作都執(zhí)行進去,并將狀態(tài)回歸到及時寫入狀態(tài)。同樣的, rollback 時會把延緩寫入的操作拋棄掉,此間申請的鎖釋放掉,并將狀態(tài)回歸到及時寫入狀態(tài)。
執(zhí)行 rollback 的關鍵在于釋放 申請的鎖 和 回歸及時寫入狀態(tài),而并不是放棄未寫入的操作(你關心的點在未寫入的操作,然而執(zhí)行與不執(zhí)行 rollback 都沒有操作寫進去,所有你感覺執(zhí)行或不執(zhí)行都沒什么區(qū)別)。
或者是顯示地使用savepoint,rollback到之前設置的savepoint

數據庫完整性約束

數據庫完整性約束
數據的完整性
約束是用來確保數據的準確性和一致性。數據的完整性就是對數據的準確性和一致性的一種保證。
數據完整性(Data Integrity)是指數據的精確(Accuracy)和可靠性(Reliability)。
分為以下四類:

  1. 實體完整性:規(guī)定表的每一行在表中是惟一的實體。
  2. 域完整性:是指表中的列必須滿足某種特定的數據類型約束,其中約束又包括取值范圍、精度等規(guī)定。
  3. 參照完整性:是指兩個表的主關鍵字和外關鍵字的數據應一致,保證了表之間的數據的一致性,防止了數據丟失或無意義的數據在數據庫中擴散。
  4. 用戶定義的完整性:不同的關系數據庫系統(tǒng)根據其應用環(huán)境的不同,往往還需要一些特殊的約束條件。用戶定義的完整性即是針對某個特定關系數據庫的約束條件,它反映某一具體應用必須滿足的語義要求。
    與表有關的約束
    主鍵約束(PK)primary key constraint 唯一且不為空
    唯一約束(UQ)unique constraint唯一,允許為空,即可以再其中出現null值,但只能出現一次
    默認約束(DF)default constraint默認值
    檢查約束(CK)check constraint范圍以及格式限制
    外鍵約束(FK)foreign key constraint表關系

數據庫調優(yōu):

MySQL調優(yōu)分析explain;show status查看服務器狀態(tài)信息

SQL語句優(yōu)化:

分析:確認程序是否存在查詢不需要的記錄;mysql是否在掃描額外記錄
1、查詢不需要的記錄:使用select語句查詢大量結果,然后再獲取前N行(如新聞網站,取100條記錄,只顯示前面的10條),這時可以使用limit(limit 1,10;從1開始10行)
2、總是使用SELECT ,對I/O、內存消耗較大,不必要時不要這樣。
3、子查詢的性能又比外連接性能慢,盡量用外連接來替換子查詢。
Select
from A where exists (select * from B where id>=3000 and A.uuid=B.uuid);
一種簡單的優(yōu)化就是用innerjoin的方法來代替子查詢,查詢語句改為:
Select* from A inner join B using(uuid) where b.uuid>=3000;
4、盡量少排序,排序操作會消耗較多的CPU資源(可以使用索引)
5、對于連續(xù)的數值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
6、切分查詢,將大查詢切分成小查詢,每個查詢功能一樣,只完成一小部分,如果用一個大的語句一次性完成的話,則可能需要一次鎖住很多數據、耗盡系統(tǒng)資源、阻塞很多小的但重要的查詢。

索引優(yōu)化

1、建立索引加快查詢性能,優(yōu)先在經常搜索的字段上建立索引(where);WHERE子句的查詢條件里使用了比較操作符LIKE前置通配符%(如:LIKE "%ABC"),因為‘%’代表任何字符,%xxx不知道怎么去索引的,所以使用不了索引。只要列中包含有NULL值都將不會被包含在索引中
2、應盡量避免在 where 子句中使用 or 來連接條件,否則將導致引擎放棄使用索引而進行全表掃描,如:
select id from t where num=10 or num=20
可以這樣查詢:
select id from t where num=10
union all
select id from t where num=20
UNION 操作符用于合并兩個或多個 SELECT 語句的結果集。請注意,UNION 內部的 SELECT 語句必須擁有相同數量的列。列也必須擁有相似的數據類型。不是同一個表也可以union只要列數相同,UNION 結果集中的列名總是等于 UNION 中第一個 SELECT 語句中的列名。UNION ALL允許重復
3、in 和 not in 也要慎用,否則會導致全表掃描,如:
select id from t where num in(1,2,3)
4、有函數的參數,不使用索引
select * from user where age + 1 =20;
5、應盡量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描
6、在多個列上建立獨立的單列索引大部分情況下不能提高查詢性能,可以使用復合索引(多列索引),key(name,age,sex)
多列索引有一個特點,即最左前綴(Leftmost Prefixing)。假如有一個多列索引為key(firstname lastname age),當搜索條件是以下各種列的組合和順序時,MySQL將使用該多列索引:
firstname,lastname,age
firstname,lastname
firstname
也就是說,相當于還建立了key(firstname lastname)和key(firstname)。但是只搜lastname用不到索引
7、由于復合索引最左前綴匹配,將搜索次數多的列放到最前列(建立B+樹時從最左字段開始排序,第一個字段相同才排第二個字段,因為查找樹需要一定的順序)
8、盡量選擇小而簡單的數據類型做索引,減少磁盤空間
9、有時候需要索引很長的字符列,這會讓索引變得大且慢。一個方式是使用哈希索引,另一個是使用前綴索引,即索引開始的部分字符串,這樣可以節(jié)約索引空間,提高效率。但這樣會降低索引的選擇性(不重復的索引值/記錄總數)。索引的選擇性越高則查詢效率越高,唯一索引的選擇性是1,性能是最好的。一般情況,某個前綴的選擇性也是足夠高的。

數據庫表結構優(yōu)化

選擇合適的數據類型
數據類型越小越好:盡量使用可以正確存儲數據的最小數據類型(tinyint,占用更少的磁盤、內存、cpu緩存);tinyint占1字節(jié),int占4字節(jié)
簡單就好:如整型比字符操作代價更低(用整型存儲ip地址)
避免NULL:最好指定列為NOT NULL,因為NULL更難優(yōu)化,使用的索引更復雜
不要設計太多列:減少不必要的列
適度冗余,減少join關聯(lián)查詢
適當拆分,水平拆分、垂直拆分
選擇合適的字符編碼:如果我們可以確定不需要存放多種語言,就沒必要非得使用UTF8或者其他UNICODE字符類型,這回造成大量的存儲空間浪費

MySQL配置文件優(yōu)化

mysql的配置文件名為my.cnf(window為my.ini),不同情況下配置文件參數設置也不相同,應該根據具體場景調優(yōu)。
InnoDB中最重要的選項是:
innodb_buffer_pool_size:緩存用戶表(實際數據row)及索引數據的最主要緩存空間,對 Innodb 整體性能影響也最大,默認為8MB,建議設為內存的70%~80%(MyISAM只緩存索引)
innodb_log_file_size:日志文件大小,默認為48MB,應該調大,至少有幾百MB

硬件優(yōu)化:

CPU的選擇
最好的選擇是核心數多并且主頻高的。但是有時考慮成本問題,可以參考以下情況:
如果不是密集型的查詢,優(yōu)先選頻率高的,而不是數量多的
如果是密集型的、高并發(fā)的查詢,比如秒殺等活動,優(yōu)先選更多的cpu
因為一條sql語句只能在一個cpu上執(zhí)行
內存的選擇
內存并不是容量越大,性能提升越明顯。如果內存大小已經超過了總數據量的大小,那么即使再增加內存,系能提升也不會特別明顯。
內存頻率選擇cpu支持的最高的頻率,品牌、型號、規(guī)格等要一致。
磁盤配置和選擇
各種磁盤性能比較:
PCIe > SSD > Raid10 > 磁盤 > 網絡存儲
各種磁盤的特點和應用:
傳統(tǒng)硬盤:需要考慮存儲容量、傳輸速度、訪問時間、主軸轉速、物理尺寸等參數
raid增加傳統(tǒng)硬盤性能:主服務器建議用raid10,從服務器可以raid0(raid0:數據等量放置在2塊磁盤中,raid1:讓同一份數據完整保存在兩塊磁盤)
SSD或者PCIe卡(FusionIO):缺點比傳統(tǒng)硬盤更容易壞
SSD應用場景:適用于存在大量隨機I/O場景(SSD隨機I/O快)、適用于解決單線程負載的I/O瓶頸(用在從服務器上,適用于讀的場景,頻繁寫會減少使用壽命)
網絡存儲場景(NAS、SAN):數據庫備份
操作系統(tǒng)
合理配置操作系統(tǒng)參數,選擇合適的文件系統(tǒng)
加緩存redis
先讀寫分離、再垂直拆分、再水平拆分
分庫:根據業(yè)務邏輯垂直拆分
分表:
縱向分表(常見為忙閑分表)
單數據表字段過多,可將頻繁更新的整數數據與非頻繁更新的字符串數據切分 ? 范例 user表 ,個人簡介,地址,QQ號,聯(lián)系方式,頭像 這些字段為字符 串類型,更新請求少; 最后登錄時間,在線時常,訪問次數,信件數這些字段為整數型字段,更新頻繁,可以將后面這些更新頻繁的字段獨立拆出一張數據表,表內容變少,索引結構變少,讀寫請求變快。
橫向切表
等分切表,如哈希切表或其他基于對某數字取余的切表(USERID奇數、偶數)。等分切表的優(yōu)點是負 載很方便的分布到不同服務器;缺點是當容量繼續(xù)增加時無法方便的擴容,需要重新進行數據的切分或轉表。而且一些關鍵主鍵不易處理。
遞增切表,比如每1kw用戶開一個新表,優(yōu)點是可以適應數據的自增趨勢; 缺點是往往新數據負載高,壓力分配不平均。

索引的好處:

創(chuàng)建索引可以大大提高數據庫系統(tǒng)的查詢性能、將隨機I/O變?yōu)轫樞騃/O(磁盤順序)。

  • 大大減少了服務器需要掃描的數據量;
  • 幫助服務器避免進行排序和創(chuàng)建臨時表;
  • 將隨機 I/O 變?yōu)轫樞?I/O。
  • 提高了查詢的速度

索引的代價

建立索引需要付出的代價 建立索引的目的是加快對表中記錄的查找或排序。但是為表設置索引是要付出代價的:這個代價有幾個個方面
a) 索引需要占物理空間 除了數據表占數據空間之外,每一個索引還要占一定的物理空間,如果要建立聚簇索引,那么需要的空間就會更大。
b) 創(chuàng)建索引和維護索引要耗費時間 這種時間隨著數據量的增加而增加。
c) 降低維護速度 當對表中的數據進行增加、刪除和修改的時候,索引也要動態(tài)的維護,這樣就降低了數據的維護速度,同樣降低了效率。

判斷是否應該建索引的條件

1、較頻繁的作為查詢條件的字段應該創(chuàng)建索引

2、唯一性太差的字段不適合單獨創(chuàng)建索引,即使頻繁作為查詢條件

3、增、刪、改操作較多的數據庫字段不適合建索引(加了索引后update會增加耗時)

4、表記錄比較少,例如一兩千條甚至只有幾百條記錄的表,沒必要建索引,讓查詢做全表掃描就好了。

5、性別字段(只有男、女)不適合建索引,性別字段的選擇性低,使用索引查找還不如遍歷表的效率高。最多只能少檢索一半,但索引的額外開銷更大,得不償失

數據庫的悲觀鎖和樂觀鎖

一、悲觀鎖
1、排它鎖,當事務在操作數據時把這部分數據進行鎖定,直到操作完畢后再解鎖,其他事務操作才可操作該部分數據。這將防止其他進程讀取或修改表中的數據。
2、實現:大多數情況下依靠數據庫的鎖機制實現
二、樂觀鎖
1、如果有人在你之前更新了,你的更新應當是被拒絕的,可以讓用戶重新操作。
2、實現:大多數基于數據版本(Version)記錄機制實現
具體可通過給表加一個版本號或時間戳字段實現,當讀取數據時,將version字段的值一同讀出,數據每更新一次,對此version值加一。當我們提交更新的時候,判斷當前版本信息與第一次取出來的版本值大小,如果數據庫表當前版本號與第一次取出來的version值相等,則予以更新,否則認為是過期數據,拒絕更新,讓用戶重新操作。
并發(fā)量很高的話,建議使用悲觀鎖,否則的話就使用樂觀鎖

Mysql頁鎖:

頁級:引擎 BDB。
表級:引擎 MyISAM , 理解為鎖住整個表,可以同時讀,寫不行
行級:引擎 INNODB , 單獨的一行記錄加鎖
表級,直接鎖定整張表,在你鎖定期間,其它進程無法對該表進行寫操作。如果你是寫鎖,則其它進程則讀也不允許
行級,僅對指定的記錄進行加鎖,這樣其它進程還是可以對同一個表中的其它記錄進行操作。
頁級,表級鎖速度快,但沖突多,行級沖突少,但速度慢。所以取了折衷的頁級,一次鎖定相鄰的一組記錄。

Mysql意向鎖:

①在MySQL中有表鎖,
LOCK TABLE my_tabl_name READ; 用讀鎖鎖表,會阻塞其他事務修改表數據。
LOCK TABLE my_table_name WRITe; 用寫鎖鎖表,會阻塞其他事務讀和寫。
②Innodb引擎又支持行鎖,行鎖分為
共享鎖(讀鎖),一個事務對一行的共享只讀鎖。
排它鎖,一個事務對一行的排他讀寫鎖。
③這兩中類型的鎖共存的問題
考慮這個例子:
事務A鎖住了表中的一行,讓這一行只能讀,不能寫。
之后,事務B申請整個表的寫鎖。
如果事務B申請成功,那么理論上它就能修改表中的任意一行,這與A持有的行鎖是沖突的。
數據庫需要避免這種沖突,就是說要讓B的申請被阻塞,直到A釋放了行鎖。
數據庫要怎么判斷這個沖突呢?
step1:判斷表是否已被其他事務用表鎖鎖表
step2:判斷表中的每一行是否已被行鎖鎖住。
注意step2,這樣的判斷方法效率實在不高,因為需要遍歷整個表。
于是就有了意向鎖。
在意向鎖存在的情況下,事務A必須先申請表的意向共享鎖,成功后再申請一行的行鎖。
在意向鎖存在的情況下,上面的判斷可以改成
step1:不變
step2:發(fā)現表上有意向共享鎖,說明表中有些行被共享行鎖鎖住了,因此,事務B申請表的寫鎖會被阻塞。
意向鎖是為了提高封鎖子系統(tǒng)的效率。
注意:申請意向鎖的動作是數據庫完成的,就是說,事務A申請一行的行鎖的時候,數據庫會自動先開始申請表的意向鎖,不需要我們程序員使用代碼來申請。

MySQL中InnoDB的MVCC

MVCC的原理與copyonwrite類似,全稱是Multi-Version Concurrent Control,即多版本并發(fā)控制。MVCC允許數據具有多個版本,這個版本可以是時間戳或者是全局遞增的事務ID,在同一個時間點,不同的事務看到的數據是不同的。
由于在update操作提交之前,不能影響已有數據的一致性,所以不會改變舊的數據,update操作會被拆分成insert + delete。需要標記刪除舊的數據,insert新的數據。只有update提交之后,才會影響后續(xù)的讀操作。而對于讀操作而且,只能讀到在其之前的所有的寫操作,正在執(zhí)行中的寫操作對其是不可見的。(讀不加鎖,讀寫不沖突)
innodb會為每一行添加兩個字段,分別表示該行創(chuàng)建的版本和刪除的版本,填入的是事務的版本號,這個版本號隨著事務的創(chuàng)建不斷遞增。在repeated read的隔離級別下,具體各種數據庫操作的實現:
select:滿足以下兩個條件能夠查詢成功:(1)該行的創(chuàng)建版本號小于等于當前版本號,用于保證在select操作之前所有的操作已經執(zhí)行落地。(2)該行的刪除版本號大于當前版本或者為空。刪除版本號大于當前版本意味著有一個并發(fā)事務將該行刪除了。
insert:將新插入的行的創(chuàng)建版本號設置為當前系統(tǒng)的版本號。
delete:將要刪除的行的刪除版本號設置為當前系統(tǒng)的版本號。
update:不執(zhí)行原地update(相當于寫操作),而是轉換成insert + delete。將舊行的刪除版本號設置為當前版本號,并將新行insert同時設置創(chuàng)建版本號為當前版本號。
其中,寫操作(insert、delete和update)執(zhí)行時,需要將系統(tǒng)版本號遞增。
由于舊數據并不真正的刪除,所以必須對這些數據進行清理,innodb會開啟一個后臺線程執(zhí)行清理工作,具體的規(guī)則是將刪除版本號小于當前系統(tǒng)版本的行刪除,這個過程叫做purge。
通過MVCC很好的實現了事務的隔離性,可以達到repeated read級別,要實現serializable還必須加鎖。

MVCC和樂觀鎖區(qū)別

在數據庫中,并發(fā)控制是指在多個用戶/進程/線程同時對數據庫進行操作時,如何保證事務的一致性和隔離性的,同時最大程度地并發(fā)。
當多個用戶/進程/線程同時對數據庫進行操作時,會出現3種沖突情形:
讀-讀,不存在任何問題讀-寫,有隔離性問題,可能遇到臟讀(會讀到未提交的數據) ,幻影讀等。寫-寫,可能丟失更新要解決沖突,一種辦法是是鎖,即基于鎖的并發(fā)控制,比如2PL,這種方式開銷比較高,而且無法避免死鎖。
多版本并發(fā)控制(MVCC)是一種用來解決讀-寫沖突的無鎖并發(fā)控制,也就是為事務分配單向增長的時間戳,為每個修改保存一個版本,版本與事務時間戳關聯(lián),讀操作只讀該事務開始前的數據庫的快照。 這樣在讀操作不用阻塞寫操作,寫操作不用阻塞讀操作的同時,避免了臟讀和不可重復讀

樂觀并發(fā)控制(OCC)是一種用來解決寫-寫沖突的無鎖并發(fā)控制,認為事務間爭用沒有那么多,所以先進行修改,在提交事務前,檢查一下事務開始后,有沒有新提交改變,如果沒有就提交,如果有就放棄并重試。樂觀并發(fā)控制類似自旋鎖。樂觀并發(fā)控制適用于低數據爭用,寫沖突比較少的環(huán)境。多版本并發(fā)控制可以結合基于鎖的并發(fā)控制來解決寫-寫沖突,即MVCC+2PL,也可以結合樂觀并發(fā)控制來解決寫-寫沖突。

Mysql5.7的新特性

MySQL 5.7版本提供了更為簡單SSL安全訪問配置,并且默認連接就采用SSL的加密方式
MySQL數據庫從5.7.8版本開始,也提供了對JSON的支持。
generated column是MySQL 5.7引入的新特性,所謂generated column,就是數據庫中這一列由其他列計算而得。
不支持子查詢中排序

范式

第一范式1NF的定義為:符合1NF的關系中的每個屬性都不可再分,1NF是所有關系型數據庫的最基本要。
2NF在1NF的基礎之上,消除了非主屬性對于碼的部分函數依賴。
碼:設 K 為某表中的一個屬性或屬性組,若除 K 之外的所有屬性都完全函數依賴于 K(這個“完全”不要漏了),那么我們稱 K 為候選碼,簡稱為碼。在實際中我們通??梢岳斫鉃椋杭偃绠?K 確定的情況下,該表除 K 之外的所有屬性的值也就隨之確定,那么 K 就是碼。一張表中可以有超過一個碼。
部分函數依賴:依賴于碼的一部分(其中的某幾個)
非主屬性:包含在任何一個碼中的屬性成為主屬性。
3NF在2NF的基礎之上,消除了非主屬性對于碼的傳遞函數依賴。
BCNF范式:在 3NF 的基礎上消除主屬性對于碼的部分與傳遞函數依賴
(https://www.zhihu.com/question/24696366)

反范式是通過增加冗余數據或數據分組來提高數據庫讀性能的過程。在某些情況下, 反范式有助于掩蓋關系型數據庫軟件的低效。關系型的范式數據庫即使做過優(yōu)化, 也常常會帶來沉重的訪問負載。

JDBC的參數

image.png

數據庫系統(tǒng)設計步驟

數據庫設計的過程(六個階段)
  1.需求分析階段
   準確了解與分析用戶需求(包括數據與處理)
   是整個設計過程的基礎,是最困難、最耗費時間的一步
  2.概念結構設計階段
   是整個數據庫設計的關鍵
   通過對用戶需求進行綜合、歸納與抽象,形成一個獨立于具體DBMS的概念模型(DBMS數據庫管理系統(tǒng),如MySQL)
  3.邏輯結構設計階段
   將概念結構轉換為某個DBMS所支持的數據模型,對其進行優(yōu)化
  4.數據庫物理設計階段
   為邏輯數據模型選取一個最適合應用環(huán)境的物理結構(包括存儲結構和存取方法)
  5.數據庫實施階段
   運用DBMS提供的數據語言、工具及宿主語言,根據邏輯設計和物理設計的結果
   建立數據庫,編制與調試應用程序,組織數據入庫,并進行試運行
  6.數據庫運行和維護階段
   數據庫應用系統(tǒng)經過試運行后即可投入正式運行。
   在數據庫系統(tǒng)運行過程中必須不斷地對其進行評價、調整與修改

數據庫各級模式的形成過程
  1.需求分析階段:綜合各個用戶的應用需求
2.概念設計階段:形成獨立于機器特點,獨立于各個DBMS產品的概念模式(E-R圖,實體-聯(lián)系圖)


image.png

 3.邏輯設計階段:首先將E-R圖轉換成具體的數據庫產品支持的數據模型,如關系模型,形成數據庫邏輯模式;然后根據用戶處理的要求、安全性的考慮,在基本表的基礎上再建立必要的視圖(View),形成數據的外模式(將E-R轉換成表,根據范式設計表,表結構設計盡量簡單、?。?br>   4.物理設計階段:根據DBMS特點和處理的需要,進行物理存儲安排,建立索引,形成數據庫內模式

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,533評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 98,055評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,365評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,561評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,346評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,889評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,978評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,118評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 48,637評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,558評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,739評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,246評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 43,980評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,619評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,347評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,702評論 2 370

推薦閱讀更多精彩內容