1. 程式人生 > >Mysql的優化和鎖機制及引擎方面的知識點

Mysql的優化和鎖機制及引擎方面的知識點

以下文章基本屬於章節翻譯及技術方面的大牛給我的資料,我彙總之後的發表。不喜輕噴

mysql處理批量的資料時如何提高其查詢速度的方法

1、應儘量避免在 where 子句中使用 != 或 <> 操作符,否則將引擎放棄使用索引而進行全表掃描。
2、對查詢進行優化,應儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。
3、應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:

select id from t where num is null 

可以在num上設定預設值0,確保表中num列沒有null值,然後這樣查詢:

select id from t where num=0

**4、**儘量避免在 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

5、下面的查詢也將導致全表掃描:(不能前置百分號)

select id from t where name like ‘%c%’ 

若要提高效率,可以考慮全文檢索。

6、in 和 not in 也要慎用,否則會導致全表掃描,如:

select id from t where num in(1,2,3) 

對於連續的數值,能用 between 就不要用 in 了:

select id from t where num between 1 and 3

7、如果在 where 子句中使用引數,也會導致全表掃描。因為SQL只有在執行時才會解析區域性變數,但優化程式不能將訪問計劃的選擇推遲到執行時;它必須在編譯時進行選擇。然而,如果在編譯時建立訪問計劃,變數的值還是未知的,因而無法作為索引選擇的輸入項。如下面語句將進行全表掃描:

select id from t where 
[email protected]

可以改為強制查詢使用索引:

select id from t with(index(索引名)) where [email protected]

8、應儘量避免在 where 子句中對欄位進行表示式操作,這將導致引擎放棄使用索引而進行全表掃描。如:

select id from t where num/2=100 

應改為:

select id from t where num=100*2

9、應儘量避免在where子句中對欄位進行函式操作,這將導致引擎放棄使用索引而進行全表掃描。如:

select id from t where substring(name,1,3)=’abc’–name以abc開頭的id 
select id from t where datediff(day,createdate,’2005-11-30′)=0–’2005-11-30′生成的id 

應改為:

select id from t where name like ‘abc%’ 
select id from t where createdate>=’2005-11-30′ and createdate<’2005-12-1′

10、不要在 where 子句中的“=”左邊進行函式、算術運算或其他表示式運算,否則系統將可能無法正確使用索引。
11、在使用索引欄位作為條件時,如果該索引是複合索引,那麼必須使用到該索引中的第一個欄位作為條件時才能保證系統使用該索引,否則該索引將不會被使 用,並且應儘可能的讓欄位順序與索引順序相一致。
12、不要寫一些沒有意義的查詢,如需要生成一個空表結構:

select col1,col2 into #t from t where 1=0 

這類程式碼不會返回任何結果集,但是會消耗系統資源的,應改成這樣:

create table #t(…)

13、很多時候用 exists 代替 in 是一個好的選擇:

select num from a where num in(select num from b) 

用下面的語句替換:

select num from a where exists(select 1 from b where num=a.num)

14、並不是所有索引對查詢都有效,SQL是根據表中資料來進行查詢優化的,當索引列有大量資料重複時,SQL查詢可能不會去利用索引,如一表中有欄位 sex,male、female幾乎各一半,那麼即使在sex上建了索引也對查詢效率起不了作用。
15、索引並不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。
16.應儘可能的避免更新 clustered 索引資料列,因為 clustered 索引資料列的順序就是表記錄的物理儲存順序,一旦該列值改變將導致整個表記錄的順序的調整,會耗費相當大的資源。若應用系統需要頻繁更新 clustered 索引資料列,那麼需要考慮是否應將該索引建為 clustered 索引。
17、儘量使用數字型欄位,若只含數值資訊的欄位儘量不要設計為字元型,這會降低查詢和連線的效能,並會增加儲存開銷。這是因為引擎在處理查詢和連線時會逐個比較字串中每一個字元,而對於數字型而言只需要比較一次就夠了。
18、儘可能的使用 varchar/nvarchar 代替 char/nchar ,因為首先變長欄位儲存空間小,可以節省儲存空間,其次對於查詢來說,在一個相對較小的欄位內搜尋效率顯然要高些。
19、任何地方都不要使用 select * from t ,用具體的欄位列表代替“*”,不要返回用不到的任何欄位。
20、儘量使用表變數來代替臨時表。如果表變數包含大量資料,請注意索引非常有限(只有主鍵索引)。
21、避免頻繁建立和刪除臨時表,以減少系統表資源的消耗。
22、臨時表並不是不可使用,適當地使用它們可以使某些例程更有效,
例如,當需要重複引用大型表或常用表中的某個資料集時。但是,對於一次性事件,最好使用匯出表。
23、在新建臨時表時,如果一次性插入資料量很大,那麼可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果資料量不大,為了緩和系統表的資源,應先create table,然後insert。
24、如果使用到了臨時表,在儲存過程的最後務必將所有的臨時表顯式刪除,先 truncate table ,然後 drop table ,這樣可以避免系統表的較長時間鎖定。
25、儘量避免使用遊標,因為遊標的效率較差,如果遊標操作的資料超過1萬行,那麼就應該考慮改寫。
26、使用基於遊標的方法或臨時表方法之前,應先尋找基於集的解決方案來解決問題,基於集的方法通常更有效。
27、與臨時表一樣,遊標並不是不可使用。對小型資料集使用FAST_FORWARD 遊標通常要優於其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的資料時。在結果集中包括“合計”的例程通常要比使用遊標執行的速度快。如果開發時間允許,基於遊標的方法和基於集的方法都可以嘗試一下,看哪一種方法的效果更好。
28、在所有的儲存過程和觸發器的開始處設定 SET NOCOUNT ON ,在結束時設定 SET NOCOUNT OFF 。無需在執行儲存過程和觸發器的每個語句後向客戶端傳送 DONE_IN_PROC 訊息。
29、儘量避免向客戶端返回大資料量,若資料量過大,應該考慮相應需求是否合理。
30、儘量避免大事務操作,提高系統併發能力。
資料庫優化方案
(1)優化索引、SQL語句、分析慢查詢
(2)設計表的時候嚴格根據資料庫的設計正規化來設計資料庫
(3)使用快取,把經常訪問到的資料而且不需要經常變化的資料放在快取中,能節約磁碟1o
(4)優化硬體,採用SSD,使用磁碟佇列技術(RAIDO, RAIDL, RDID5) 等
(5)採用MySQL內部自帶的表分割槽技術,把資料分層不同的檔案,能夠提高磁碟的讀取效率W垂直分表;把一些不經常讀的資料放在一張表裡,節約磁碟I/0
(7)主從分離讀寫;採用主從複製把資料庫的讀操作和寫入操作分離開來
(8)分庫分表分機器(資料量特別大),主要的的原理就是資料路由
(9)選擇合適的表引擎,引數上的優化
(10)進行架構級別的快取,靜態化和分散式
(11)不採用全文索引
(12)採用更快的儲存方式,例如Nosql儲存經常訪問的資料
怎樣解決海量資料的儲存和訪問造成系統設計瓶頸的問題?
(1)水平切分資料庫:可以降低單臺機器的負載,同時最大限度的降低了宕機造成的損失;分庫降低了單點機器的負載;分表,提高了資料操作的效率,
(2)負載均衡策略:可以降低單臺機器的訪問負載,降低宕機的可能性
(3)叢集方案:解決了資料庫宕機帶來的單點資料庫不能訪問的問題
(4)讀寫分離策略:最大限度了提高了應用中讀取資料的速度和併發量

怎樣解決資料庫高併發的問題?
(1)解決資料庫高併發
(2)分表分庫
(3)資料庫索引
(4)redis快取資料庫
(5)讀寫分離
(6)負載均衡叢集;將大量的併發請求分擔到多個灶理節點。由於單個處理節點的故障不影響整個服務,負載均衡摯群同時也實現了高可用性。

資料庫怎麼優化查詢效率?
(1)儲存引擎選擇:如果資料表需要事務處理,應該考慮使用lnnoDB,因為它完全符合ACID特性。如果不需要事務處理,使用預設儲存引擎MyISAM是比較明智的
(2)分表分庫,主從。
(3)對查詢進行優化,要儘量避免全表掃描,首先應考慮在where及order by涉及的列上建立索引
(4)應儘量避免在where子句中對欄位進行null值判斷,否則將導致引擎放棄使用索引而進行全表掃描
(5)應儘量避免在where子句中使用!=或><操作符,否則將引擎放棄使用索引而進行全表掃描
(6)應儘量避免在where子句中使用or來連線條化如果一個欄位有索引,一個欄位沒有索引,將導致引擎放棄使用索引而進行全表掃描
(7)Update語句,如果只更改1.2個欄位,不要Update全部欄位,否則頻繁呼叫會引起明顯的效能消耗,同時帶來大量日誌對於多張大資料量(這裡幾百條就算大了)的表JOIN,要先分頁再JOIN,否則邏輯讀會很高,效能很差。

如果每天有5T的使用者資料量需要存入mysql中怎麼優化資料庫?
1、儘量使資料庫一次性寫入Data File
2、減少資料庫的checkpoint操作
3、程式上儘量緩衝資料,進行批量式插入與提交
4、減少系統的10衝突

如何查詢MySQL中查詢慢的SQL語句
(1)slow_query_log這個引數設定為ON,可以捕獲執行時間超過一定數值的SQL語句。
(2)long_quew-time當SQL語句執行時間超過此數值時,就會被記錄到日誌中,建議設定為1或者更短。

資料庫負載均衡
對客戶端來說,整個群集可以視為一臺具有超高效能的獨立伺服器。
(1)實現原理
實現資料庫的負載均衡技術,首先要有一個可以控制連線資料庫的控制端。在這裡,它截斷了資料庫和程式的直接連線,由所有的程式來訪問這個中間層,然後再由中間層來訪問資料庫。這樣,我們就可以具體控制訪問某個資料庫了。然後還可以根據資料庫的當前負載採取有效的均衡策略,來調整每次連線到哪個資料庫。
(2)實現多資料資料同步
對於負載均衡,最重要的就是所有伺服器的資料都是實時同步的。這是一個叢集所必需的,因為,如果資料不實時、不同步,那麼使用者從一臺伺服器讀出的資料,就有別於從另一臺伺服器讀出的資料,這是不能允許的。所以必須實現資料庫的資料同步。這樣,在查詢的時候就可以有多個資源,實現均衡。比較常用的方法是Moebius for SQL Server叢集,Moebrus for SQL Server叢集採用將核心程式駐留在每個機器的資料庫中的辦法,這個核心程式稱為Moebius for SQL Server中介軟體,主要作用是監測資料庫內資料的變化並將變化的資料同步到其他資料庫中。資料同步完成後客戶端才會得到響應,同步過程是併發完成,所以同步到多個數據庫和同步到一個數據庫的時間基本相等;另外同步的過程是在事務的環境下完成的,保證了多份資料在任何時刻資料的一致性。正因為Moebius中介軟體宿主在資料庫中的創新,讓中介軟體不但能知道資料的變化而且知道引起資料變化的SQL語句,根據SQL語句的型別智慧的採取不同的資料同步的策略以保證資料同步成本的最小化。資料條數很少,資料內容也不大,則直接同步資料資料條數很少,但是裡面包含大資料型別,比如文字,二進位制資料等,則先對資料進行壓縮然後再同步,從而減少網路頻寬的佔用和傳輸所用的時間。資料條數很多,此時中介軟體會拿到造成資料變化的SQL語句,然後對SQL語句進行解析,分析其執行計劃和執行成本,並選擇是同步資料還是同步SQL語句到其他的資料庫中。此種情況應用在對錶結構進行調整或者批量更改資料的時候非常有用。
優點
(1)擴充套件性強地增加資料當系統要更高資料庫處理速度時,只要簡單庫伺服器就可以得到擴充套件
(2)可維護性:當某節點發生故障時,系統會自動檢測故障並轉移故障節點的應用,保證資料庫的持續工作。
(3)安全性:因為資料會同步到多臺伺服器上,可以實現資料集的冗餘,通過多份資料來保證安全性。另外它成功地將資料庫放到了內網之中,更好地保護了資料庫的安全性。
(4)易用性:對應用來說完全透明,叢集暴露出來的就是一個IP.
缺點
(1)不能夠按照Web伺服器的處理能力分配負載。
(2)負載均衡器(控制端)故障

MySQL各儲存引擎使用了三種類型(級別)的鎖定機制:表級鎖定,行級鎖定和頁級鎖定。
1.表級鎖定(table-level)
表級別的鎖定是MySQL各儲存引擎中最大顆粒度的鎖定機制。該鎖定機制最大的特點是實現邏輯非常簡單,帶來的系統負面影響最小。所以獲取鎖和釋放鎖的速度很快。由於表級鎖一次會將整個表鎖定,所以可以很好的避免困擾我們的死鎖問題。當然,鎖定顆粒度大所帶來最大的負面影響就是出現鎖定資源爭用的概率也會最高,大打折扣。使用表級鎖定的主要是MyISAM,MEMORY,CSV等一些非事務性儲存引擎。
2.行級鎖定(row-level)
行級鎖定最大的特點就是鎖定物件的顆粒度很小,也是目前各大資料庫管理軟體所實現的鎖定顆粒度最小的。由於鎖定顆粒度很小,所以發生鎖定資源爭用的概率也最小,能夠給予應用程式儘可能大的併發處理能力而提高一些需要高併發應用系統的整體效能。雖然能夠在併發處理能力上面有較大的優勢,但是行級鎖定也因此帶來了不少弊端。
由於鎖定資源的顆粒度很小,所以每次獲取鎖和釋放鎖需要做的事情也更多,帶來的消耗自然也就更大了。此外,行級鎖定也最容易發生死鎖。
使用行級鎖定的主要是InnoDB儲存引擎。
3.頁級鎖定(page-level)
頁級鎖定是MySQL中比較獨特的一種鎖定級別,在其他資料庫管理軟體中也並不是太常見。頁級鎖定的特點是鎖定顆粒度介於行級鎖定與表級鎖之間,所以獲取鎖定所需要的資源開銷,以及所能提供的併發處理能力也同樣是介於上面二者之間。另外,頁級鎖定和行級鎖定一樣,會發生死鎖。在資料庫實現資源鎖定的過程中,隨著鎖定資源顆粒度的減小,鎖定相同資料量的資料所需要消耗的記憶體數量是越來越多的,實現演算法也會越來越複雜。不過,隨著鎖定資源顆粒度的減小,應用程式的訪問請求遇到鎖等待的可能性也會隨之降低,系統整體併發度也隨之提升。使用頁級鎖定的主要是BerkeleyDB儲存引擎。

總的來說,MySQL這3種鎖的特性可大致歸納如下:
表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的概率最高,併發度最低;
行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的概率最低,併發度也最高;
頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度一般。
適用:從鎖的角度來說,表級鎖更適合於以查詢為主,只有少量按索引條件更新資料的應用,如Web應用;
而行級鎖則更適合於有大量按索引條件併發更新少量不同資料,同時又有併發查詢的應用,如一些線上事務處理(OLTP)系統

死鎖
通常來說,死鎖都是應用設計的問題,通過調整業務流程、資料庫物件設計、事務大小,以及訪問資料庫的SQL語句,
絕大部分死鎖都可以避免。下面就通過例項來介紹幾種避免死鎖的常用方法:
(1)在應用中,如果不同的程式會併發存取多個表,應儘量約定以相同的順序來訪問表,這樣可以大大降低產生死鎖的機會。
(2)在程式以批量方式處理資料的時候,如果事先對資料排序,保證每個執行緒按固定的順序來處理記錄,也可以大大降低出現死鎖的可能。
(3)在事務中,如果要更新記錄,應該直接申請足夠級別的鎖,而不應先申請共享鎖,更新時再申請排斥鎖,因為當用戶申請排斥鎖時,其他事務可能又已經獲得了相同記錄的共享鎖,從而造成鎖衝突,甚至死鎖。
(4)在REPEATABLE-READ隔離級別下,如果兩個執行緒同時對相同條件記錄用SELECT…FOR UPDATE加排斥鎖,在沒有符合該條件記錄情況下,兩個執行緒都會加鎖成功。程式發現記錄尚不存在,就試圖插入一條新記錄,
如果兩個執行緒都這麼做,就會出現死鎖。這種情況下,將隔離級別改成READ COMMITTED,就可避免問題。
(5)當隔離級別為READ COMMITTED時,如果兩個執行緒都先執行SELECT…FOR UPDATE,判斷是否存在符合條件的記錄,如果沒有,就插入記錄。此時,只有一個執行緒能插入成功,另一個執行緒會出現鎖等待,
當第1個執行緒提交後,第2個執行緒會因主鍵重複而出錯,但雖然這個執行緒出錯了,卻會獲得一個排斥鎖。
這時如果有第3個執行緒又來申請排斥鎖,也會出現死鎖。
對於這種情況,可以直接做插入操作,然後再捕獲主鍵重異常,或者在遇到主鍵重錯誤時,總是執行ROLLBACK釋放獲得的排斥鎖。

在MySQL資料庫中,常用的引擎主要就是2個:Innodb和MyIASM。
首先:
1.簡單介紹這兩種引擎,以及該如何去選擇
2.這兩種引擎所使用的資料結構是什麼。
a.Innodb引擎,Innodb引擎提供了對資料庫ACID事務的支援。並且還提供了行級鎖和外來鍵的約束。
它的設計的目標就是處理大資料容量的資料庫系統。它本身實際上是基於Mysql後臺的完整的系統。
Mysql執行的時候,Innodb會在記憶體中建立緩衝池,用於緩衝資料和索引。
但是,該引擎是不支援全文搜尋的。同時,啟動也比較的慢,它是不會儲存表的行數的。
當進行Select count(“”) from table“”指令的時候,需要進行掃描全表。
所以當需要使用資料庫的事務時,該引擎就是首選。由於鎖的粒度小,寫操作是不會鎖定全表的。
所以在併發度較高的場景下使用會提升效率的。
b.MyIASM引擎,它是MySql的預設引擎,但不提供事務的支援,
也不支援行級鎖和外來鍵。因此當執行Insert插入和Update更新語句時,
即執行寫操作的時候需要鎖定這個表。所以會導致效率會降低。
不過和Innodb不同的是,MyIASM引擎是儲存了表的行數,
於是當進行Select count(“”) from table“”語句時,可以直接的讀取已經儲存的值而不需要進行掃描全表。
所以,如果表的讀操作遠遠多於寫操作時,並且不需要事務的支援的。可以將MyIASM作為資料庫引擎的首先。
補充2點:
**c.**大容量的資料集時趨向於選擇Innodb。因為它支援事務處理和故障的恢復。
Innodb可以利用資料日誌來進行資料的恢復。主鍵的查詢在Innodb也是比較快的。
**d.**大批量的插入語句時(這裡是INSERT語句)在MyIASM引擎中執行的比較的快,
但是UPDATE語句在Innodb下執行的會比較的快,尤其是在併發量大的時候。
2.兩種引擎所使用的索引的資料結構是什麼?
答案:都是B+樹!
MyIASM引擎,B+樹的資料結構中儲存的內容實際上是實際資料的地址值。
也就是說它的索引和實際資料是分開的,只不過使用索引指向了實際資料。這種索引的模式被稱為非聚集索引。
Innodb引擎的索引的資料結構也是B+樹,只不過資料結構中儲存的都是實際的資料,這種索引有被稱為聚集索引。

以上文章基本屬於章節翻譯及技術方面的大牛給我的資料,我彙總之後發表。不喜輕噴