一般狀況下,當訪問某張表的時候,讀取者首先必須獲取該表的鎖,若是有寫入操做到達,那麼寫入者一直等待讀取者完成操做(查詢開始以後就不能中斷,所以容許讀取者完成操做)。當讀取者完成對錶的操做的時候,鎖就會被解除。若是寫入者正在等待的時候,另外一個讀取操做到達了,該讀取操做也會被阻塞(block),由於默認的調度策略是寫入者優先於讀取者。當第一個讀取者完成操做並解放鎖後,寫入者開始操做,而且直到該寫入者完成操做,第二個讀取者纔開始操做。mysql
經過LOCK TABLES和UNLOCK TABLES語句能夠顯式地獲取或釋放鎖,可是在一般狀況下,服務器的鎖管理器會自動地在須要的時候獲取鎖,在再也不須要的時候釋放鎖。獲取的鎖的類型依賴於客戶端是寫入仍是讀取操做。sql
對某張表進行寫入操做的客戶端必須擁有獨佔的(排他的)訪問權的鎖。操做在進行的過程當中,該數據表處於不一致的(inconsistent)狀態,由於數據記錄在刪除、添加或修改的時候,數據表上的索引也可能須要更新以相互匹配。容許兩個客戶端同時寫入一張數據表是不利的,由於這樣的操做會很快使數據表中的信息成爲一堆無用的垃圾。同時容許客戶端讀取變化之中的數據表也不正確,由於正在讀取的位置中的數據可能正在變化(修改),讀取的結果可能並非真實的。所以對某張表執行讀取操做的客戶端也必須獲取一個鎖,防止在讀取的過程當中,其它的客戶端寫入或改變表。可是這個鎖不須要獨佔的訪問權。由於讀取操做不會改變數據,所以沒有理由讓某個讀取者阻止其它的讀取者訪問這張表。故讀取鎖可容許其它的客戶端在同一時刻讀取這張表。數據庫
雖然經過鎖機制,能夠實現多線程同時對某個表進行操做,但當某個線程做更新操做時,首先要得到獨佔的訪問權。在更新的過程當中,全部其它想要訪問這個表的線程必需要等到其更新完成爲止。此時就會致使鎖競爭的問題,從而致使用戶等待時間的延長。 緩存
要提升MySQL的更新/插入效率,應首先考慮下降鎖的競爭,減小寫操做的等待時間。 服務器
1.同時插入多行記錄時,宜使用多個值表的INSERT 語句多線程
若是能夠同時從同一客戶插入不少行時,宜使用多個值表的INSERT 語句。多個值表的 INSERT 語句 ,能夠大大縮減客戶端與數據庫之間的鏈接、語法分析等消耗,使得效率比分開執行的單個 INSERT 語句快不少。性能
如批量插入:線程
INSERT INTO tb (fa, fb, fc) VALUES ('1', '12', '13'), ('2', '22', '23'), ('3', '32', '33'), 索引
多值的 INSERT語句還能夠經過調整 bulk_insert_buffer_size 參數來提升數據插入的效率,這個參數設置的是 bulk insert 的緩存大小,默認是 8M 。注意,這隻能對myisam表使用。隊列
2.考慮使用replace 語句代替insert語句
根據應用狀況可使用replace 語句代替insert/update語句。例如:若是一個表在一個字段上創建了惟一索引,當向這個表中使用已經存在的鍵值插入一條記錄,將會拋出一個主鍵衝突的錯誤。若是咱們想用新記錄的值來覆蓋原來的記錄值時,就可使用REPLACE語句。
使用REPLACE插入記錄時,若是記錄不重複(或往表裏插新記錄),REPLACE功能與INSERT同樣,若是存在重複記錄,REPLACE就使用新記錄的值來替換原來的記錄值。使用REPLACE的最大好處就是能夠將DELETE和INSERT合二爲一,造成一個原子操做。這樣就能夠沒必要考慮同時使用DELETE和INSERT時添加事務等複雜操做了。
在使用REPLACE時,表中必須有惟一有一個PRIMARY KEY或UNIQUE索引,不然,使用一個REPLACE語句沒有意義。
mysql replace語句:
用法1:replace into:
replace into table (id,name) values('1','aa'),('2','bb')
此語句的做用是向表table中插入兩條記錄。若是主鍵id爲1或2不存在就至關於插入語句:
insert into table (id,name) values('1','aa'),('2','bb')
若是存在相同的值則不會插入數據。
用法2:replace(object, search, replace)
做用是把object中出現search的所有替換爲replace,例:
select replace(‘abc’, ‘b’, ‘x’);
例:把表table中的name字段中的aa替換爲bb
update table set name=replace(name,'aa','bb')
注意:UPDATE和REPLACE的區別:
1)UPDATE在沒有匹配記錄時什麼都不作,而REPLACE在有重複記錄時更新,在沒有重複記錄時插入。
2)UPDATE能夠選擇性地更新記錄的一部分字段。而REPLACE在發現有重複記錄時就將這條記錄完全刪除,再插入新的記錄。也就是說,將全部的字段都更新了。
3.在插入大量數據以前,能夠先將表鎖定(Lock Tables)
爲了提升數據插入的效率,能夠考慮在插入以前先將表鎖定。這主要是由於直到全部的INSERT語句都完成以後,索引緩存一次性刷新到磁盤中。一般狀況下,有多少次INSERT語句就會有多少次索引緩存刷新到磁盤中的開銷。爲此在數據插入以前,將數據表進行鎖定,就能夠大幅度的提升數據插入的效率。固然,若是你能夠用一個插入語句實現全部行的插入,則無需使用顯式鎖定語句。(針對非事務性表)
所以若是一個表的更新頻率比較高時,那麼可使用Lock Tables選項來提升更新速度。
對於事務性表,要想更快地進行表插入,可使用START TRANSACTION和COMMIT語句代替LOCK TABLES來提升更新速度。
4.能夠對myisam表並行插入Concurrent_insert系統變量能夠被設置用於修改concurrent-insert處理。
該變量默認設置爲1。若是concurrent_insert被設置爲0,並行插入就被禁用。若是該變量被設置爲2,在表的末端能夠並行插入,即使該表的某些行已經被刪除。
5.使用插入延遲
若是客戶無需等待插入完成的時候(即用戶對插入數據的即時性要求可能並非很高),此時就能夠考慮採用插入延遲特性。Delayed 的含義是讓insert 語句立刻執行並返回,而數據被放在內存的隊列中等待被插入,並無真正的寫入磁盤;這比每條語句都分別插入要快的多。
使用插入延遲的另外一個好處就是從多個客戶插入的狀況會被綁定並記錄在同一個block中。
默認狀況下,在MySQL數據庫中,更新操做比Select查詢有更高的優先級。MySQL的默認的調度策略可用總結以下:
• 寫入操做優先於讀取操做。
• 對一張數據表的寫入操做同一時刻只能發生一次,寫入請求按照它們到達的次序來處理。
• 對一張數據表的多個讀取操做能夠同時地進行。
MySQL容許改變語句調度的優先級,它可使來自多個客戶端的查詢更好地協做,這樣單個客戶端就不會因爲鎖定而等待很長時間。改變優先級還能夠確保特定類型的查詢被處理得更快。經過如下三種方式來修改它的調度策略:
• LOW_PRIORITY關鍵字應用於DELETE、INSERT、LOAD DATA、REPLACE和UPDATE。這個屬性能夠將某個特定的語句的優先級下降。如能夠調低某個特定的更新語句或者插入語句的優先級。不過須要注意的是,這個屬性只有對特定的語句有用。即其做用域只針對某個特定的語句,而不會對全局形成影響。
例:UPDATE [LOW_PRIORITY] tbl_name SET col_name1=expr1,col_name2=expr2,...
mysql中update用low_priority讓update不鎖定表
• HIGH_PRIORITY關鍵字應用於SELECT和INSERT語句。這個屬性能夠用來提升某個特定的Select查詢語句的優先級。LOW_PRIORITY恰好相反,在全部其餘用戶對錶的讀寫完成後才進行插入。這裏須要注意,跟上面這個屬性同樣,這個做用域也只限於特定的查詢語句。而不會對沒有加這個參數的其餘查詢語句產生影響。也就是說,其餘查詢語句若是沒有加這個屬性,那麼其優先級別仍然低於更新進程。
• DELAYED關鍵字應用於INSERT和REPLACE語句。
LOW_PRIORITY和HIGH_PRIORITY調節符影響那些使用數據表鎖的存儲引擎(例如MyISAM和MEMORY)。DELAYED調節符做用於MyISAM和MEMORY數據表。
一般狀況下,某張數據表正在被讀取的時候,若是有寫入操做到達,那麼寫入者一直等待讀取者完成操做(查詢開始以後就不能中斷,所以容許讀取者完成操做)。若是寫入者正在等待的時候,另外一個讀取操做到達了,該讀取操做也會被阻塞(block),由於默認的調度策略是寫入者優先於讀取者。當第一個讀取者完成操做的時候,寫入者開始操做,而且直到該寫入者完成操做,第二個讀取者纔開始操做。
若是寫入操做是一個LOW_PRIORITY(低優先級)請求,那麼系統就不會認爲它的優先級高於讀取操做。在這種狀況下,若是寫入者在等待的時候,第二個讀取者到達了,那麼就容許第二個讀取者插到寫入者以前。只有在沒有其它的讀取者的時候,才容許寫入者開始操做。理論上,這種調度修改暗示着,可能存在LOW_PRIORITY寫入操做永遠被阻塞的狀況。若是前面的讀取操做在進行的過程當中一直有其它的讀取操做到達,那麼新的請求都會插入到LOW_PRIORITY寫入操做以前。
SELECT查詢的HIGH_PRIORITY(高優先級)關鍵字也相似。它容許SELECT插入正在等待的寫入操做以前,即便在正常狀況下寫入操做的優先級更高。另一種影響是,高優先級的SELECT在正常的SELECT語句以前執行,由於這些語句會被寫入操做阻塞。
若是但願某一鏈接支持LOW_PRIORITY選項來處理,那麼經過Set LOW_PRIORIT_UPDATES=1來設置鏈接變量,經過這個設置能夠制定具體鏈接中的全部更新進程都是用比較低的優先級。但注意這個選項只針對特定的鏈接有用。對於其餘的鏈接,就不適用。
若是但願全部支持LOW_PRIORITY選項的語句都默認地按照低優先級來處理,那麼請使用--low-priority-updates選項來啓動服務器。採用這個選項啓動數據庫時,系統會給數據庫中全部的更新語句比較低的優先級。經過使用INSERT HIGH_PRIORITY來把INSERT語句提升到正常的寫入優先級,能夠消除該選項對單個INSERT語句的影響。
6.使用LOAD DATA INFILE從文本下載數據將比使用插入語句快20倍。
Load Date Infile是從一個文件中導入數據。若是採用這種方式的話,用戶須要預先準備一個固定格式的文件。若是插入的數據量比較多,例如軟件運行環境配置時可能會導入大量預配置數據時,此時使用Load Date Infile的方式可以取得比較好的性能。
執行LOAD DATA INFILE,數據插入到表中,因爲無需更新表索引,所以這將很是快。
7.將大表分爲多個小表來下降鎖競爭
一些大表或頻繁更新的表中,因爲表的訪問量較大,所以鎖競爭也比較嚴重。此時,能夠人爲地將表合理分爲多個小表,使表訪問分散到多張表上,相互之間不會產生干擾時,就會下降表上鎖的競爭,從而提升了訪問效率。而當須要訪問完整數據時,能夠經過視圖進行整合成一張表。
在實際應用中,會趕上即有更新操做又有插入操做又有查詢操做時,要根據特定的狀況,綜合應用上述方法來提升訪問效率。