Java相關內容:數據庫

要想進階成Java中級開發工程師,有一些東西總是繞不過去的,Java的知識體系裏,像IO/NIO/AIO,多線程,JVM,網絡編程,數據庫,框架等必須有一定了解才行。最近在準備面試,所以對這些東西也做個記錄。本篇記錄的是數據庫相關。

 

數據庫基本內容簡單回顧(以下問題基於Mysql)

 

1.0 什麼是三範式?

1.列不可再分;

2.行需要唯一區分; (一般就是說要設置主鍵)

3.非主屬性只依賴於主屬性,而不能依賴於其它非主屬性。 (就是找非主鍵字段只能通過主鍵來關聯,而不是啊三啊四)

 

1.1 事務

1.1.1 事務四大特性

• 事務四大特性(ACID)

原子性(Atomic) :指事務中的操作要麼都發生,要麼都不發生。  (如轉帳扣款加款的兩條語句,要麼執行,要麼不執行)

一致性(Consistency):指如果在執行事務之前數據庫是一致的,那麼在執行事務之後數據庫也還是一致的。(即不會出現修改丟失、髒讀、不可重複讀、幻讀等情況)

隔離性(Isolation):多個事務併發訪問時,事務之間是隔離的,一個事務不影響其它事務的運行效果。 (此處有隔離級別的說法)

持久性(Durability):事務提交後,對數據的修改時永久的。及時系統發生故障,也能在不會丟失對數據的修改。一般通過執行前寫入日誌的方式保證持久性,即使系統崩潰,也能在重啓的過程中,通過日誌恢復崩潰時處於執行狀態的事物。z

 

1.1.2 事務隔離級別

• 事務的併發?事務隔離級別,每個級別會引發什麼問題,MySQL默認是哪個級別?

讀未提交(Read Uncommitted):最低的隔離級別,什麼都不需要做,一個事務可以讀到另一個事務未提交的結果。即可能出現髒讀,不可重複讀,幻讀。

讀提交(Read Committed):只有在事務提交後,其更新結果纔會被其他事務看見。可以解決髒讀問題。但是還有不可重複讀和幻讀問題。

可重複讀(Repeated Read):在一個事務中,對於同一份數據的讀取結果總是相同的,無論是否有其他事務對這份數據進行操作,以及這個事務是否提交。可以解決髒讀、不可重複讀,但是無法解決幻讀問題。這是Mysql中默認的隔離級別。

串行化(Serialization):事務串行化執行,隔離級別最高,讀寫分開,犧牲了系統的併發性。可以解決併發事務的所有問題。

- 髒讀:又稱無效數據的讀出,是指在數據庫訪問中,事務T1將某一值修改,然後事務T2讀取該值,此後T1因爲某種原因撤銷對該值的修改,這就導致了T2所讀取到的數據是無效的。
- 不可重複讀:是指在數據庫訪問中,一個事務範圍內兩個相同的查詢卻返回了不同數據。這是由於查詢時系統中其他事務修改的提交而引起的。比如事務T1讀取某一數據,事務T2讀取並修改了該數據,T1爲了對讀取值進行檢驗而再次讀取該數據,便得到了不同的結果。不可重複度因爲當執行SELECT 操作時沒有獲得讀鎖(read locks)或者SELECT操作執行完後馬上釋放了讀鎖。
- 幻讀:是指當事務不是獨立執行時發生的一種現象,例如第一個事務對一個表中的數據進行了修改,比如這種修改涉及到表中的“全部數據行”。同時,第二個事務也修改這個表中的數據,這種修改是向表中插入“一行新數據”。那麼,以後就會發生操作第一個事務的用戶發現表中還有沒有修改的數據行,就好象發生了幻覺一樣。幻讀主要由於另一個事務插入導致。

1.2 存儲引擎

• MySQL常見的三種存儲引擎(InnoDB、MyISAM、MEMORY)的區別?

MySQL中的存儲引擎有很多種,可以通過“SHOW ENGINES”語句來查看。下面重點關注InnoDB、MyISAM、MEMORY這三種

1.2.1 引擎區別

不同的存儲引擎決定了MySQL數據庫中的表可以用不同的方式來存儲。我們可以根據數據的特點來選擇不同的存儲引擎。

INNODB

支持事務,支持外鍵,行鎖,支持主鍵自增。查表總行數時,全表掃描。缺點是讀寫效率較差,佔用的數據空間相對較大。

MYISAM

MyISAM的優勢在於佔用空間小,處理速度快。缺點是不支持事務,不支持外鍵,不支持行鎖。插入數據時,鎖定整個表,查表總行數時,不需要全表掃描。

MEMORY

MEMORY是MySQL中一類特殊的存儲引擎。它使用存儲在內存中的內容來創建表,而且數據全部放在內存中。這些特性與前面的兩個很不同。這樣有利於數據的快速處理,提高整個表的效率。值得注意的是,服務器需要有足夠的內存來維持MEMORY存儲引擎的表的使用。如果不需要了,可以釋放內存,甚至刪除不需要的表。MEMORY默認使用哈希索引。MEMORY用到的很少,因爲它是把數據存到內存中,如果內存出現異常就會影響數據。如果重啓或者關機,所有數據都會消失。因此,基於MEMORY的表的生命週期很短,一般是一次性的。

1.2.2 引擎選擇

InnoDB:支持事務處理,支持外鍵,支持崩潰修復能力和併發控制。如果需要對事務的完整性要求比較高(比如銀行),要求實現併發控制(比如售票),那選擇InnoDB有很大的優勢。如果需要頻繁的更新、刪除操作的數據庫,也可以選擇InnoDB,因爲支持事務的提交(commit)和回滾(rollback)。 

MyISAM:插入數據快,空間和內存使用比較低。如果表主要是用於插入新記錄和讀出記錄,那麼選擇MyISAM能實現處理高效率。如果系統讀多,寫少。對原子性要求低。那麼MyISAM最好的選擇。

MEMORY:所有的數據都在內存中,數據的處理速度快,但是安全性不高。如果需要很快的讀寫速度,對數據的安全性要求較低,可以選擇MEMOEY。它對錶的大小有要求,不能建立太大的表。所以,這類數據庫只使用在相對較小的數據庫表。

注意,同一個數據庫也可以使用多種存儲引擎的表。如果一個表要求比較高的事務處理,可以選擇InnoDB。這個數據庫中可以將查詢要求比較高的表選擇MyISAM存儲。如果該數據庫需要一個用於查詢的臨時表,可以選擇MEMORY存儲引擎。

1.3 mysql鎖

• mysql都有什麼鎖,死鎖判定原理和具體場景,死鎖怎麼解決?• mysql鎖,行鎖,表鎖 ,什麼時候發生鎖,怎麼鎖,原理• 有哪些鎖(樂觀鎖悲觀鎖),select 時怎麼加排它鎖?

1.3.1 mysql鎖類型

MySQL數據庫存在多種數據存儲引擎,每種存儲引擎所針對的應用場景特點都不太一樣,爲了滿足各自特定應用場景的需求,每種存儲引擎的鎖定機制都是爲各自所面對的特定場景而優化設計。MySQL各存儲引擎使用了三種類型(級別)的鎖定機制:表級鎖定,行級鎖定和頁級鎖定。

表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的概率最高,併發度最低。 行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的概率最低,併發度也最高。 頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度一般。

1.3.2 mysql鎖使用

MYISAM鎖

MyISAM存儲引擎,只支持表鎖。MyISAM在執行查詢語句(SELECT)前,會自動給涉及的所有表加讀鎖,在執行更新操作 (UPDATE、DELETE、INSERT等)前,會自動給涉及的表加寫鎖。即MyISAM中讀和寫是串行的。

InnoDB鎖

InnoDB存儲引擎,它支持行鎖,也支持表鎖(Lock table .. read/write),默認情況下是採用行鎖。InnoDB實現了以下兩種類型的行鎖。對於UPDATE、DELETE和INSERT語句,InnoDB會自動給涉及數據集加排他鎖;

  • 共享鎖(s):又稱讀鎖。允許一個事務去讀一行,阻止其他事務獲得相同數據集的排他鎖。若事務T對數據對象A加上S鎖,則事務T可以讀A但不能修改A,其他事務只能再對A加S鎖,而不能加X鎖,直到T釋放A上的S鎖。這保證了其他事務可以讀A,但在T釋放A上的S鎖之前不能對A做任何修改。

  • 排他鎖(X):又稱寫鎖。允許獲取排他鎖的事務更新數據,阻止其他事務取得相同的數據集共享讀鎖和排他寫鎖。若事務T對數據對象A加上X鎖,事務T可以讀A也可以修改A,其他事務不能再對A加任何鎖,直到T釋放A上的鎖。

使用方式:
對於普通SELECT語句,InnoDB不會加任何鎖;事務可以通過以下語句顯式給記錄集加共享鎖或排他鎖。
共享鎖(S): SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE
排他鎖(X): SELECT * FROM table_name WHERE ... FOR UPDATE

注意:

  • 行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。這些鎖統稱爲悲觀鎖(Pessimistic Lock)

  • 加過排他鎖x的數據行在其他事務中是不能修改數據的,也不能通過for update和lock in share mode鎖的方式查詢數據,但可以直接通過select …from…查詢數據,因爲普通查詢沒有任何鎖機制。

  • 間隙鎖:當我們用範圍條件而不是相等條件檢索數據,並請求共享或排他鎖時,InnoDB會給符合條件的已有數據記錄的 索引項加鎖;對於鍵值在條件範圍內但並不存在的記錄,叫做“間隙(GAP)”,InnoDB也會對這個“間隙”加鎖,這種鎖機制就是所謂的間隙鎖 (Next-Key鎖)

  • InnoDB的行鎖是基於索引實現的,如果不通過索引訪問數據,InnoDB會使用表鎖。 

 

1.4 索引

• 索引類型?• 索引爲什麼要用B+樹,B+樹/B-樹區別?B+Tree索引/Hash索引區別?• 聚集、非聚集索引區別?

1.4.1 索引分類

Mysql目前主要有以下幾種索引類型:全文索引(FULLTEXT),哈希索引(HASH),B+樹索引(BTREE),空間數據索引(RTREE)。其中:

  • B+樹索引(BTREE)

    是mysql默認的InnoDb引擎使用的索引,也是我們最常見的索引,可以分爲普通索引、唯一索引、組合索引。

    普通索引:僅加速查詢最基本的索引,沒有任何限制,是我們大多數情況下使用到的索引。

    唯一索引:與普通索引類型,不同的是:加速查詢 + 列值唯一(可以有null)

    組合索引:將幾個列作爲一條索引進行檢索,使用最左匹配原則。

CREATE INDEX  index_name on user_info(name);
CREATE UNIQUE INDEX unindex_name on user_info(name);

  • 全文索引(FULLTEXT)

    僅可以適用於MyISAM引擎的數據表;僅可作用於CHAR、VARCHAR、TEXT數據類型的列。它的出現是爲了解決WHERE name LIKE '%word%' 這類針對文本的模糊查詢效率較低的問題。

  • 哈希索引(HASH)

    是Memory引擎上的索引。HASH索引可以一次定位,不需要像樹形索引那樣逐層查找,因此具有極高的效率。但是,這種高效是有條件的,即只在“=”和“in”條件下高效,且不支持範圍查詢、排序及組合索引。另外hash索引中的hash碼的計算可能存在hash衝突。當出現hash衝突的時候,存儲引擎必須遍歷整個鏈表中的所有行指針,逐行比較,直到找到所有的符合條件的行。

  • 空間數據索引(RTREE):

    RTREE在MySQL很少使用,僅支持geometry數據類型,支持該類型的存儲引擎只有MyISAM、BDb、InnoDb、NDb、Archive幾種。相對於BTREE,RTREE的優勢在於範圍查找。

聚合索引、非聚合索引區別:

聚集索引:

​ 當給表上了主鍵,那麼表在磁盤上的存儲結構就由整齊排列的結構轉變成了樹狀結構,也就是「平衡樹」結構,換句話說,就是整個表就變成了一個索引。沒錯, 再說一遍, 整個表變成了一個索引,也就是所謂的「聚集索引」。 這就是爲什麼一個表只能有一個主鍵, 一個表只能有一個「聚集索引」,因爲主鍵的作用就是把「表」的數據格式轉換成「索引(平衡樹)」的格式放置。

非聚集索引:

​ 非聚集索引和聚集索引一樣, 同樣是採用平衡樹作爲索引的數據結構。索引樹結構中各節點的值來自於表中的索引字段, 假如給user表的name字段加上索引 , 那麼索引就是由name字段中的值構成,在數據改變時, DBMS需要一直維護索引結構的正確性。如果給表中多個字段加上索引 , 那麼就會出現多個獨立的索引結構,每個索引(非聚集索引)互相之間不存在關聯。

二者區別在於, 通過聚集索引可以查到需要查找的數據, 而通過非聚集索引可以查到記錄對應的主鍵值 , 再使用主鍵的值通過聚集索引查找到需要的數據。

 

1.4.2 索引創建與使用

什麼時候應該創建索引:

  1. 表的主鍵、外鍵必須有索引;

  2. 數據量較大的表應該有索引;

  3. 經常用做連接查詢的字段,需要有索引;

  4. 經常出現在Where子句中的字段,應該建立索引;

  5. 經常用到排序的列上,因爲索引已經排序。(單order by)

  6. 經常用在範圍內搜索的列上創建索引,因爲索引已經排序了,其指定的範圍是連續的。(between)

order by:mysql查詢只使用一個索引,因此如果where子句中已經使用了索引的話,那麼order by中的列是不會使用索引的。
group by :也會用上索引

什麼時候會用不上索引:

  1. 如果條件中有or,即使其中有條件帶索引也不會使用索引(or可以用union代替);

  2. 對於多列索引,不是使用的第一部分,則不會使用索引(即不符合最左前綴);且複合索引中只要有一列含有NULL值,那麼這一列對於此複合索引就是無效的;

  3. like查詢是以%開頭時不會使用索引(MyISAM的全文索引可以%word%);

  4. 如果列類型是字符串,那一定要在條件中將數據使用引號引用起來,否則不使用索引。

  5. 索引列參與計算也不會使用索引。

  6. NOT IN 、<>、!= 操作也不會使用索引,但<,<=,=,>,>=,BETWEEN,IN是可以用到索引的

通過USE INDEX、IGNORE INDEX、FORCE INDEX可以使用、忽略、強制使用索引

1.4.3 索引原理

​ 索引的目的在於提高查詢效率,原理是通過不斷的縮小想要獲得數據的範圍來篩選出最終想要的結果,同時把隨機的事件變成順序的事件,也就是我們總是通過同一種查找方式來鎖定數據。但是由於通過磁盤IO讀取數據耗費的時間比較多,所以我們希望每次查找數據時把磁盤IO次數控制在一個很小的數量級,最好是常數數量級。那麼我們就想到如果一個高度可控的多路搜索樹是否能滿足需求呢?就這樣,b+樹應運而生。

​ 如上圖,是一顆b+樹,關於b+樹這裏只說一些重點,淺藍色的塊我們稱之爲一個磁盤塊,可以看到每個磁盤塊包含幾個數據項(深藍色所示)和指針(黃色所示),如磁盤塊1包含數據項17和35,包含指針P1、P2、P3,P1表示小於17的磁盤塊,P2表示在17和35之間的磁盤塊,P3表示大於35的磁盤塊。真實的數據存在於葉子節點即3、5、9、10、13、15、28、29、36、60、75、79、90、99。非葉子節點不存儲真實的數據,只存儲指引搜索方向的數據項,如17、35並不真實存在於數據表中。

b+樹的查找過程

​ 如圖所示,如果要查找數據項29,那麼首先會把磁盤塊1由磁盤加載到內存,此時發生一次IO,在內存中用二分查找確定29在17和35之間,鎖定磁盤塊1的P2指針,內存時間因爲非常短(相比磁盤的IO)可以忽略不計,通過磁盤塊1的P2指針的磁盤地址把磁盤塊3由磁盤加載到內存,發生第二次IO,29在26和30之間,鎖定磁盤塊3的P2指針,通過指針加載磁盤塊8到內存,發生第三次IO,同時內存中做二分查找找到29,結束查詢,總計三次IO。真實的情況是,3層的b+樹可以表示上百萬的數據,如果上百萬的數據查找只需要三次IO,性能提高將是巨大的,如果沒有索引,每個數據項都要發生一次IO,那麼總共需要百萬次的IO,顯然成本非常非常高。

b+樹性質

  1. 通過上面的分析,我們知道IO次數取決於b+樹的高度h,假設當前數據表的數據爲N,每個磁盤塊的數據項的數量是m,則有h=㏒(m+1)N,當數據量N一定的情況下,m越大,h越小;而m = 磁盤塊的大小 / 數據項的大小,磁盤塊的大小也就是一個數據頁的大小,是固定的,如果數據項佔的空間越小,數據項的數量越多,樹的高度越低。這就是爲什麼每個數據項,即索引字段要儘量的小,比如int佔4字節,要比bigint8字節少一半。這也是爲什麼b+樹要求把真實的數據放到葉子節點而不是內層節點,一旦放到內層節點,磁盤塊的數據項會大幅度下降,導致樹增高。當數據項等於1時將會退化成線性表。

  2. 當b+樹的數據項是複合的數據結構,比如(name,age,sex)的時候,b+數是按照從左到右的順序來建立搜索樹的,比如當(張三,20,F)這樣的數據來檢索的時候,b+樹會優先比較name來確定下一步的所搜方向,如果name相同再依次比較age和sex,最後得到檢索的數據;但當(20,F)這樣的沒有name的數據來的時候,b+樹就不知道下一步該查哪個節點,因爲建立搜索樹的時候name就是第一個比較因子,必須要先根據name來搜索才能知道下一步去哪裏查詢。比如當(張三,F)這樣的數據來檢索時,b+樹可以用name來指定搜索方向,但下一個字段age的缺失,所以只能把名字等於張三的數據都找到,然後再匹配性別是F的數據了, 這個是非常重要的性質,即索引的最左匹配特性。

1.4.4 b+樹、b樹

二者的特點如下:

b樹:

  1. 關鍵字集合分佈在整顆樹中;

  2. 任何一個關鍵字出現且只出現在一個結點中;

  3. 搜索有可能在非葉子結點結束;

  4. 其搜索性能等價於在關鍵字全集內做一次二分查找;;

b+樹:

b+樹,是b樹的一種變體,查詢性能更好。m階的b+樹的特徵:

  1. 有n棵子樹的非葉子結點中含有n個關鍵字(b樹是n-1個),這些關鍵字不保存數據,只用來索引,所有數據都保存在葉子節點(b樹是每個關鍵字都保存數據)。

  2. 所有的葉子結點中包含了全部關鍵字的信息,及指向含這些關鍵字記錄的指針,且葉子結點本身依關鍵字的大小自小而大順序鏈接。

  3. 所有的非葉子結點可以看成是索引部分,結點中僅含其子樹中的最大(或最小)關鍵字。

  4. 通常在b+樹上有兩個頭指針,一個指向根結點,一個指向關鍵字最小的葉子結點。

  5. 同一個數字會在不同節點中重複出現。

b+樹對比b樹的查詢優勢:

  1. b+樹的中間節點不保存數據,所以磁盤頁能容納更多節點元素,更“矮胖”;

  2. b+樹查詢必須查找到葉子節點,b樹只要匹配到即可不用管元素位置,因此b+樹查找更穩定(並不慢);

  3. 對於範圍查找來說,b+樹只需遍歷葉子節點鏈表即可,b樹卻需要重複地中序遍歷;(基於範圍查詢是很普遍的)

關於二分查找和二叉樹的理解:
(1)二分查找:即折半查找,優點是比較次數少,查找速度快,平均性能好;其缺點是要求待查表爲有序表,且插入刪除困難
(2)二叉查找樹,它或者是一棵空樹,或者若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;
若它的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值; 它的左、右子樹也分別爲二叉排序樹。
(3)平衡二叉樹:避免數據全部在一端時的情況,強制轉成平衡的。

1.5 sql優化

• MySQL慢查詢怎麼解決?使用explain優化sql和索引?• 查詢語句不同元素(where、jion、limit、group by、having等等)執行先後順序

1.5.1 explain介紹

explain後得到的結果主要有:id、select_type、table、type、possible_keys、key、key_len、rows、Extra。

需要強調rows是explain的核心指標,絕大部分rows小的語句執行一定很快。所以優化語句基本上都是在優化rows。

另一個explain的重要指標是type,一般要求達到range以上,最好能達到ref。

其它重點列的簡單解釋如下:

  • select_type:表示 SELECT 的類型,常見的取值有

    • SIMPLE:簡單表,即不使用表連接或者子查詢、• PRIMARY:主查詢,即外層的查詢、​• UNION:UNION 中的第二個或者後面的查詢語句、​• SUBQUERY:子查詢中的第一個 SELECT。

  • table:輸出結果集的表。

  • rows:掃描行的數量。

  • type:表示表的連接類型,性能由好到差的連接類型爲

    • system(表中僅有一行,即常量表)• const(單表中最多有一個匹配行,例如 primary key 或者 unique index)• eq_ref(對於前面的每一行,在此表中只查詢一條記錄,簡單來說,就是多表連接中使用 primary key 或者 unique index)• ref(與 eq_ref 類似,區別在於不是使用 primary key 或者 unique index,而是使用普通的索引)• ref_or_null(與 ref 類似,區別在於條件中包含對 NULL 的查詢)• index_merge(索引合併優化)• unique_subquery(in的後面是一個查詢主鍵字段的子查詢)• index_subquery(與 unique_subquery 類似,區別在於 in 的後面是查詢非唯一索引字段的子查詢)• range (單表中的範圍查詢)• index(對於前面的每一行,都通過查詢索引來得到數據)• all(對於前面的每一行,都通過全表掃描來得到數據)

  • possible_keys:表示查詢時,可能使用的索引。

  • key:表示實際使用的索引。

  • key_len:索引字段的長度。

  • Extra:執行情況的說明和描述。

1.5.2 慢查詢優化

  1. 先運行看看是否真的很慢,注意設置SQL_NO_CACHE

  2. where條件單表查,鎖定最小返回記錄表。這句話的意思是把查詢語句的where都應用到表中返回的記錄數最小的表開始查起,單表每個字段分別查詢,看哪個字段的區分度最高。

  3. explain查看執行計劃,是否與1預期一致(從鎖定記錄較少的表開始查詢)

  4. order by limit 形式的sql語句讓排序的表優先查

  5. 瞭解業務方使用場景

  6. 加索引時參照建索引的幾大原則

  7. 觀察結果,不符合預期繼續從1分析

可以參考:https://tech.meituan.com/2014/06/30/mysql-index.html

1.6 數據庫崩潰恢復

• 數據庫崩潰時事務的恢復機制(REDO日誌和UNDO日誌)?

InnoDB擁有內部恢復機制,假如數據庫崩潰了,InnoDB通過從最後一個時間戳開始運行日誌文件,來嘗試修復數據庫。大多數情況下會修復成功,而且整個過程是透明的。即InnoDB實現了一套完善的崩潰恢復機制,保證在任何狀態下(包括在崩潰恢復狀態下)數據庫掛了,都能正常恢復,這個是與文件系統最大的差別。

崩潰恢復:用戶修改了數據,並且收到了成功的消息,然而對數據庫來說,可能這個時候修改後的數據還沒有落盤,如果這時候數據庫掛了,重啓後,數據庫需要從日誌中把這些修改後的數據給撈出來,重新寫入磁盤,保證用戶的數據不丟。這個從日誌中撈數據的過程就是崩潰恢復的主要任務,也可以成爲數據庫前滾。當然,在崩潰恢復中還需要回滾沒有提交的事務,提交沒有提交成功的事務。由於回滾操作需要undo日誌的支持,undo日誌的完整性和可靠性需要redo日誌來保證,所以崩潰恢復先做redo前滾,然後做undo回滾

- redo日誌:現代數據庫都需要寫redo日誌,例如修改一條數據,首先寫redo日誌,然後再寫數據。在寫完redo日誌後,就直接給客戶端返回成功。
- undo日誌:數據庫還提供類似撤銷的功能,當你發現修改錯一些數據時,可以使用rollback指令回滾之前的操作。這個功能需要undo日誌來支持。
- innodb_fast_shutdown:這個默認值=1,表示在MySQL關閉的時候,僅僅把日誌和數據刷盤。= 0。這個表示在MySQL關閉的時候,執行slow shutdown,不但包括日誌的刷盤,數據頁的刷盤,還包括數據的清理(purge),ibuf的合併,buffer pool dump以及lazy table drop操作。 = 2時表示關閉的時候,僅僅日誌刷盤,其他什麼都不做,就好像MySQL crash了一樣。 這個參數值越大,MySQL關閉的速度越快,但是啓動速度越慢,相當於把關閉時候需要做的工作挪到了崩潰恢復上。

恢復方法:

一旦確定MySQL因爲InnoDB表損壞無法啓動時,就可以按照以下5步進行修復:
1.編輯/etc/my.cnf文件,加入如下行:
innodb_force_recovery = 4
2.這時就可以重新啓動數據庫了,在innodb_force_recovery配置的作用,所有的插入與更新操作將被忽略;
3.導出所有的數據表;
4.關閉數據庫並刪除所有數據表文件及目錄,再運行 mysql_install_db來創建MySQL默認數據表;
5.在/etc/my.cnf中刪除innodb_force_recovery這一行,再啓動MySQL(這時MySQL正常啓動);
6.從第3步備份的文件中恢復所有的數據。

innodb_force_recovery可以設置爲1-6,大的數字包含前面所有數字的影響。當設置參數值大於0後,可以對錶進行select,create,drop操作,但insert,update或者delete這類操作是不允許的。 
1(SRV_FORCE_IGNORE_CORRUPT):忽略檢查到的corrupt頁。
2(SRV_FORCE_NO_BACKGROUND):阻止主線程的運行,如主線程需要執行full purge操作,會導致crash。
3(SRV_FORCE_NO_TRX_UNDO):不執行事務回滾操作。
4(SRV_FORCE_NO_IBUF_MERGE):不執行插入緩衝的合併操作。
5(SRV_FORCE_NO_UNDO_LOG_SCAN):不查看重做日誌,InnoDB存儲引擎會將未提交的事務視爲已提交。
6(SRV_FORCE_NO_LOG_REDO):不執行前滾的操作。

 

1.7 主從複製

• 數據庫的讀寫分離如何實現?• 主從複製,主從複製分析的 7 個問題、主從複製

原理:

複製過程中一個服務器充當主服務器,而一個或多個其它服務器充當從服務器。mysql複製基於主服務器在二進制日誌(binlog)中跟蹤所有對數據庫的更改(更新、刪除等等)。因此,要進行復制,必須在主服務器上啓用二進制日誌。每個從服務器從主服務器接收主服務器已經記錄到的二進制日誌,獲取日誌信息更新。通過設置在Master上的binlog,使其處於打開狀態;Slave通過一個I/O線程從Master上讀取binlog,然後傳輸到Slave的中繼日誌(relaylog)中,然後使用SQL線程讀取中繼日誌,並應用到自身數據庫中,從而實現主從數據同步功能。

即mysql主從複製需要三個線程:
1. 主:binlog線程——記錄下所有改變了數據庫數據的語句,放進master上的binlog中;
2. 從:io線程——在使用start slave 之後,負責從master上拉取 binlog 內容,放進 自己的relay log中;
3. 從:sql執行線程——執行relay log中的語句;

 

1.8 讀寫分離

方式1:通過MyCAT 實現讀寫分離

方式2:通過MaxScale實現讀寫分離 

 

1.9 分庫分表

• 數據庫優化,最左原則啊,水平分表,垂直分表

基礎概念

  • 分表,能夠解決單表數據量過大帶來的查詢效率下降的問題;

  • 分庫,面對高併發的讀寫訪問,當數據庫master服務器無法承載寫操作壓力時,不管如何擴展slave服務器,此時都沒有意義。此時,則需要通過數據分庫策略,提高數據庫併發訪問能力。

  • 優點,分庫、分表技術優化了數據存儲方式,有效減小數據庫服務器的負擔、縮短查詢響應時間。

  • 數據分庫、分表存儲場景條件

    • 關係型數據庫

    • 主從架構(master-slave)

    • 單表數據量在百萬、千萬級別

    • 數據庫面臨極高的併發訪問

  • 分庫、分表實現策略

    • 關鍵字取模,實現對數據訪問進行路由

 

1.10 union/union all?

UNION在進行錶鏈接後會篩選掉重複的記錄,

UNION ALL只是簡單的將兩個結果合併後就返回,

從效率上說,UNION ALL 要比UNION快很多,所以,如果可以確認合併的兩個結果集中不包含重複的數據的話,那麼就使用UNION ALL。

-- mysql實現full join:
select * from t1 left join t2 on t1.id = t2.id
union 
select * from t1 right join t2 on t1.id = t2.id;

 

還有就是寫SQL了

#補充今日去面試的sql面試題,有興趣的可以試試


1. 有tb_student表,數據如下:
name    course        score
張三    語文        71
李四    語文        81
王五    數學        90
李四    數學        85
王五    語文        75
張三    數學        72
(1) 寫一條sql按學生的總成績,從高到低排名
(2) 寫一條sql查詢所有課程都大於80的學生名字

2. 有tb_score表,數據如下
name    course        score
張三       語文            71
王五       數學            75
張三       語文            71
(1) 寫sql去除表中信息相同的冗餘數據


#常用MYSQL內置方法:

-- 零、將查詢結果連接:CONCAT
SELECT CONCAT(CURDATE(), ',', CURDATE());

-- 一、將查詢結果合併: UNION, UNION ALL (允許重複)
SELECT DATE_SUB(CURDATE(), INTERVAL 3 DAY)
UNION ALL
SELECT DATE_ADD(NOW(), INTERVAL 3 DAY);

-- 二.格式化時間: DATE_FORMAT
SELECT DATE_FORMAT(CURDATE(), '%Y-%m-%d');
SELECT DATE_FORMAT(now(), '%Y-%m-%d %H:%i:%S');

-- 三.時間加減: DATE_SUB, DATE_ADD

-- 2.1當前日期減三個天,三月,三年
SELECT DATE_SUB(CURDATE(), INTERVAL 3 DAY)
UNION ALL
SELECT DATE_SUB(CURDATE(), INTERVAL 3 MONTH)
UNION ALL
SELECT DATE_SUB(CURDATE(), INTERVAL 3 YEAR);

-- 2.2 當前時間加三個天,三月,三年
SELECT DATE_ADD(NOW(), INTERVAL 3 DAY)
UNION ALL
SELECT DATE_ADD(NOW(), INTERVAL 3 MONTH)
UNION ALL
SELECT DATE_ADD(NOW(), INTERVAL 3 YEAR);

-- 2.3 兩個時間相差多少秒,分,時,日,月,年
select TIMESTAMPDIFF(WEEK,'2018-07-30','2018-09-14')
UNION ALL
select TIMESTAMPDIFF(DAY,'2018-07-30','2018-09-14')
UNION ALL
select TIMESTAMPDIFF(MONTH,'2018-07-30','2018-09-14')


-- 三、將查詢結果用逗號相連: GROUP_CONCAT
SELECT GROUP_CONCAT(column1) FROM tbl

-- 四、

-- >將查詢結果合併後用逗號相連:
SELECT
  GROUP_CONCAT(tmpConcatName) AS concatName
FROM
  (
    SELECT
      DATE_SUB(CURDATE(), INTERVAL 3 DAY) AS tmpConcatName
    UNION ALL
    SELECT
      DATE_ADD(NOW(), INTERVAL 3 DAY)
  ) AS tmpTbl

-- >將查詢結果格式化併合並後用逗號相連:
SELECT
  GROUP_CONCAT(tmpConcatName) AS concatName
FROM
  (
    SELECT
      DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 3 DAY), '%Y-%m-%d' ) AS tmpConcatName
    UNION ALL
    SELECT
      DATE_FORMAT(DATE_ADD(CURDATE(), INTERVAL 3 DAY), '%Y-%m-%d' ) AS tmpConcatName
  ) AS tmpTbl


-- 五、字符串操作
select LOWER('RGFRG')--大寫字母變爲小寫字母
select UPPER('ggfgrt')--小寫字母變爲大寫字母
select LTRIM()--去掉左側字符空格
select RTRIM()--去掉字符串右側空格
select LEFT(Title,5)from News--從某列中左側起截取多少長度的字符串
select RIGHT(Title,5)from News--從某列中右側起截取多上長度的字符串
select SUBSTRING(Title,3,5) from News--從某一列中第幾個字符開始截取幾個字符
select REVERSE (Title) from News --翻轉某一列
select CHARINDEX('中國',Title)from News --查詢目標內容在指定區域有沒有出現以及出現位置
select REPLACE(Title,'中國','美國')from News--替換字符串。例搜索關鍵字並明顯標註
select STUFF(Title,3,4,'chine') from News
-- 六、其他函數
select CEILING (RAND()*10)--隨機生成-1之間的數字,可以以乘以的方式增大隨機數範圍
select LEN('chine')--取字符串長度
select GETDATE()--獲取當前時間
select YEAR(sbirthday)from student--取時間年份
select month(sbirthday)from student--取日期時間月份
select day(sbirthday)from student3--取時間天
select datepart(yy,sbirthday)from student4-- yy,mm,dd分別代表年月日
select CAST ('123'as int)--轉換字符串

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章