1. 程式人生 > >針對MyISAM鎖表的解決方案(也可應用於表鎖定)

針對MyISAM鎖表的解決方案(也可應用於表鎖定)

最近伺服器上經常出現mysql程序佔CPU100%的情況,使用show processlist命令後,看到出現了很多狀態為LOCKED的sql。使用show status like ‘table%’檢查Table_locks_immediate和Table_locks_waited,發現Table_locks_waited偏 大。出問題的表是MyISAM,分析大概是MyISAM的鎖表導致。
MyISAM適合於讀頻率遠大於寫頻率這一情況。而我目前的應用可能會出現在某一時段讀寫頻率相當。大致如下:

一個客戶端發出需要長時間執行的SELECT
其他客戶端在同一個表上發出INSERT或者UPDATE,這個客戶將等待SELECT完成
另一個客戶在同一個表上發出另一個SELECT;因UPDATE或INSERT比SELECT有更高有優先順序,該SELECT將等待UPDATE或INSERT完成,也將等待第一個SELECT完成

也就是說對MyISAM表的讀操作,不會阻塞其他使用者對同一表的讀請求,但會阻塞對同一表的寫請求;對 MyISAM表的寫操作,則會阻塞其他使用者對同一表的讀和寫操作;MyISAM表的讀操作與寫操作之間,以及寫操作之間是序列的

解決方案大概有如下幾種:

MyISAM儲存引擎有一個系統變數concurrent_insert,專門用以控制其併發插入的行為,其值分別可以為0、1或2。
0 不允許併發操作
1 如果MyISAM表中沒有空洞(即表的中間沒有被刪除的行),MyISAM允許在一個程序讀表的同時,另一個程序從表尾插入記錄。這也是MySQL的預設設定。
2 無論MyISAM表中有沒有空洞,都允許在表尾併發插入記錄
使用–low-priority-updates啟用mysqld。這將給所有更新(修改)一個表的語句以比SELECT語句低的優先順序。在這種情況下,在先前情形的最後的SELECT語句將在INSERT語句前執行。
為max_write_lock_count設定一個低值,使得在一定數量的WRITE鎖定後,給出READ鎖定
使用LOW_PRIORITY屬性給於一個特定的INSERT,UPDATE或DELETE較低的優先順序
使用HIGH_PRIORITY屬性給於一個特定的SELECT
使用INSERT DELAYED語句

附加:
mysql的myisam解決併發讀寫解決方法MyISAM在讀操作佔主導的情況下是很高效的。可一旦出現大量的讀寫併發,同InnoDB相比,MyISAM的效率就會直線下降,而且,MyISAM和InnoDB的資料儲存方式也有顯著不同:通常,在MyISAM裡,新資料會被附加到資料檔案的結尾,可如果時常做一些 UPDATE,DELETE操作之後,資料檔案就不再是連續的,形象一點來說,就是資料檔案裡出現了很多洞洞,此時再插入新資料時,按預設設定會先看這些洞洞的大小是否可以容納下新資料,如果可以,則直接把新資料儲存到洞洞裡,反之,則把新資料儲存到資料檔案的結尾。之所以這樣做是為了減少資料檔案的大小,降低檔案碎片的產生。但InnoDB裡則不是這樣,在InnoDB裡,由於主鍵是cluster的,所以,資料檔案始終是按照主鍵排序的,如果使用自增ID做主鍵,則新資料始終是位於資料檔案的結尾。

瞭解了這些基礎知識,下面說說MyISAM幾個容易忽視的配置選項:
concurrent_insert:
通常來說,在MyISAM裡讀寫操作是序列的,但當對同一個表進行查詢和插入操作時,為了降低鎖競爭的頻率,根據concurrent_insert的設定,MyISAM是可以並行處理查詢和插入的:

當concurrent_insert=0時,不允許併發插入功能。
當concurrent_insert=1時,允許對沒有洞洞的表使用併發插入,新資料位於資料檔案結尾(預設)。
當concurrent_insert=2時,不管表有沒有洞洞,都允許在資料檔案結尾併發插入。

這樣看來,把concurrent_insert設定為2是很划算的,至於由此產生的檔案碎片,可以定期使用OPTIMIZE TABLE語法優化。
max_write_lock_count:
預設情況下,寫操作的優先順序要高於讀操作的優先順序,即便是先發送的讀請求,後傳送的寫請求,此時也會優先處理寫請求,然後再處理讀請求。這就造成一個問題:一旦我發出若干個寫請求,就會堵塞所有的讀請求,直到寫請求全都處理完,才有機會處理讀請求。此時可以考慮使用>有了這樣的設定,當系統處理一個寫操作後,就會暫停寫操作,給讀操作執行的機會。
low-priority-updates:
我們還可以更乾脆點,直接降低寫操作的優先順序,給讀操作更高的優先順序。
low-priority-updates=1
綜合來看,concurrent_insert=2是絕對推薦的,至於max_write_lock_count=1和low-priority- updates=1,則視情況而定,如果可以降低寫操作的優先順序,則使用low-priority-updates=1,否則使用 max_write_lock_count=1。