mysql 原理及配置優化
假設我們用文字儲存的資料和資料庫裡一樣的資料結構並且遵循三正規化,那資料庫相比文字儲存有什麼大的優勢呢。
有了這個疑問後我們來簡單探究下mysql資料庫的原理,簡單瞭解原理後我們在學習下配置的簡單優化。
我們先看下mysql的結構圖
1.最上層是一些客戶端和連線服務,包含本地sock通訊和大多數基於客戶端/服務端工具實現的類似於tcp/ip的通訊。主要完成一些類似於連線處理、授權認證、及相關的安全方案。在該層上引入了執行緒池的概念,為通過認證安全接入的客戶端提供執行緒。同樣在該層上可以實現基於SSL的安全連結。伺服器也會為安全接入的每個客戶端驗證它所具有的操作許可權。
2.第二層架構主要完成大多少的核心服務功能,如SQL介面,並完成快取的查詢,SQL的分析和優化及部分內建函式的執行。所有跨儲存引擎的功能也在這一層實現,如過程、函式等。在該層,伺服器會解析查詢並建立相應的內部解析樹,並對其完成相應的優化如確定查詢表的順序,是否利用索引等,最後生成相應的執行操作。如果是select語句,伺服器還會查詢內部的快取。如果快取空間足夠大,這樣在解決大量讀操作的環境中能夠很好的提升系統的效能。
3.儲存引擎層,儲存引擎真正的負責了MySQL中資料的儲存和提取,伺服器通過API與儲存引擎進行通訊。不同的儲存引擎具有的功能不同,這樣我們可以根據自己的實際需要進行選取。
如果你看著很複雜的話,我們再來個簡單點的圖。如果你看上面的描述理解了一些在看下面的圖,你可能更好理解些。
這上面的三層就相比文字儲存的大概三個優點,其實還有最重要的,那就是事物和鎖,涉及併發。
比如: 當資料庫中有多個操作需要修改同一資料時,不可避免的會產生資料的髒讀。這時就需要資料庫具有良好的併發控制能力,這一切在MySQL中都是由伺服器和儲存引擎來實現的。
解決併發問題最有效的方案是引入了鎖的機制,鎖在功能上分為共享鎖(shared lock)和排它鎖(exclusive lock)即通常說的讀鎖和寫鎖。當一個select語句在執行時可以施加讀鎖,這樣就可以允許其它的select操作進行,因為在這個過程中資料資訊是不會被改變的這樣就能夠提高資料庫的執行效率。當需要對資料更新時,就需要施加寫鎖了,不在允許其它的操作進行,以免產生資料的髒讀和幻讀。
注意: 資料庫裡會出現一種死鎖的情況,就是我佔著讀鎖,然而寫鎖要我讀鎖裡的資源去寫入東西,但是我讀鎖要讀出寫鎖佔著的資源,這樣就互相佔著對方的資源而不放形成死鎖了。InnoDB引擎解決死鎖的方案是將持有最少排它鎖的事務進行回滾。
鎖有粒度大小,有表級鎖(table lock)和行級鎖(row lock),分別在資料操作的過程中完成行的鎖定和表的鎖定。
表鎖是MySQL中基本的鎖策略,並且是開銷最小的策略。當用戶在對一張表進行寫操作之前,首先獲得寫鎖,於是,它阻塞了其他連結的讀取和寫入操作,只有寫鎖接觸的時候,其他連結才能獲得讀鎖。
不僅如此,MySQL還設定了鎖的優先順序,在操作列隊中MySQL可能會把寫入操作插入到讀取操作之前。
行級鎖可以最大程度的支援併發處理(同時也帶來了最大的鎖開銷)。行級鎖只在儲存引擎中實現。行級鎖比表鎖更加精確,他把鎖的物件精確到了物件的某一行,但也就意味著需要建立更多的鎖。
注:理論上鎖定的資源越小,鎖定範圍越精確,那麼併發效能就會越高。但是事實上,建立一個數據鎖也會造成系統的開銷,如果系統通過大量的時間來管理鎖,而不是存取資料,系統的效能反而會降低。
事務
事務其實就是一個獨立的工作單元。如果資料庫引擎能夠完成事務中的每一項操作,那麼全組的SQL語句都會被執行,如果任何一條語句因為崩潰或者其他原因無法執行,那麼所有語句都不執行。並且回滾到快照。
MySQL大多數事務型的儲存引擎都不是簡單的行級鎖,基於效能的考慮,他們一般都同時實現了多版本併發控制(MVCC)(這個版本控制有點像SVN那樣,和hibernate中的樂觀鎖差不多機制)。它是通過儲存資料中某個時間點的快照來實現的,這樣就保證了每個事務看到的資料都是一致的。
mysql 的配置優化。
從MySQL 5.5版本開始,InnoDB就是預設的儲存引擎並且它比任何其他儲存引擎的使用都要多得多。
innodb_buffer_pool_size
緩衝池是資料和索引快取的地方:這個值越大越好,這能保證你在大多數的讀取操作時使用的是記憶體而不是硬碟。一般設定為實體記憶體的80%
max_connections
MySQL的最大連線數,增加該值增加mysqld 要求的檔案描述符的數量。如果伺服器的併發連線請求量比較大,建議調高此值,以增加並行連線數量,當然這建立在機器能支撐的情況下,因為如果連線數越多,介於MySQL會為每個連線提供連線緩衝區,就會開銷越多的記憶體,所以要適當調整該值,不能盲目提高設值。
show variables like ‘max_connections’ 最大連線數
show status like ‘max_used_connections’響應的連線數
max_used_connections / max_connections * 100% (理想值≈ 85%)
query_cache_size
使用查詢緩衝,MySQL將查詢結果存放在緩衝區中,今後對於同樣的SELECT語句(區分大小寫),將直接從緩衝區中讀取結果。
通過檢查狀態值Qcache_*,可以知道query_cache_size設定是否合理(上述狀態值可以使用SHOW STATUS LIKE ‘Qcache%’獲得)。
query_cache_type指定是否使用查詢緩衝,可以設定為0、1、2,該變數是SESSION級的變數。
query_cache_type設為1即可。在設 置了這個屬性後,MySQL在執行任何SELECT語句之前,都會在它的緩衝區中查詢是否在相同的SELECT語句被執行過,如果有,並且執行結果沒有過 期,那麼就直接取查詢結果返回給客戶端。但在寫SQL語句時注意,MySQL的查詢緩衝是區分大小寫的,大小寫不一樣它會重新去資料庫查。
雖然不設定查詢緩衝,有時可能帶來效能上的損失,但有一些SQL語句需要實時地查詢資料,或者並不經常使用(可能一天就執行一兩次)。這樣就需要把 緩衝關了。當然,這可以通過設定query_cache_type的值來關閉查詢緩衝,但這就將查詢緩衝永久地關閉了。
在MySQL 5.0中提供了一種可以臨時關閉查詢緩衝的方法:
(1) SELECT SQL_NO_CACHE field1, field2 FROM TABLE1
以上的SQL語句由於使用了SQL_NO_CACHE,因此,不管這條SQL語句是否被執行過,伺服器都不會在緩衝區中查詢,每次都會執行它。
我們還可以將my.ini中的query_cache_type設成2,這樣只有在使用了SQL_CACHE後,才使用查詢緩衝。
(2) SELECT SQL_CALHE * FROM TABLE1
mysql> show global status like ‘qcache%‘;
mysql> show variables like ‘query_cache%‘;
查詢快取利用率= (query_cache_size – Qcache_free_memory) / query_cache_size * 100%
查詢快取利用率在25%以下的話說明query_cache_size設定的過大,可適當減小;查詢快取利用率在80%以上而且Qcache_lowmem_prunes > 50的話說明query_cache_size可能有點小,要不就是碎片太多。
查詢快取命中率= (Qcache_hits – Qcache_inserts) / Qcache_hits * 100%
命中率很差的話,可能寫操作比較頻繁吧
show status like ‘Slow_queries’//慢查詢的次數 (預設是10秒中就當做是慢查詢,如下圖所示)
查詢mysql的慢查詢時間
Show variables like ‘long_query_time’;
修改mysql 慢查詢時間
set long_query_time=2//如果查詢時間超過2秒就算作是慢查詢
mysql支援把慢查詢語句記錄到日誌檔案中。程式設計師需要修改my.ini的配置檔案,預設情況下,慢查詢記錄是不開啟的。
開啟慢查詢記錄的步驟:
開啟 my.ini ,找到 [mysqld] 在其下面新增
long_query_time = 2
log-slow-queries = D:/mysql/logs/slow.log #設定把日誌寫在那裡,可以為空,系統會給一個預設的檔案。
我們可以從日誌中看出哪些查詢語句查詢超過了,你設定的時間。
然後可以分析你的查詢語句。主要是用explain分析查詢。
使用 EXPLAIN 關鍵字可以模擬優化器執行SQL查詢語句,從而知道MySQL是如何處理你的SQL語句的。這可以幫你分析你的查詢語句或是表結構的效能瓶頸。
執行緒快取
執行緒快取儲存了和當前連線無關的執行緒,這些執行緒可以供新連線使用。當要求一個新的連線時,如果執行緒快取中的連線能夠被使用時,新的連線就不會被建立,而使用執行緒快取中的連線。當連線關閉時,又會將該執行緒放回到執行緒快取中(前提是執行緒快取中有可用的空間)。
引數thread_cache_size用於控制執行緒快取的大小,預設值為0,表示沒有執行緒快取,這個引數為動態引數可以隨時更改,如下:
mysql> show variables like ‘thread_cache_size’;
+——————-+——-+
| Variable_name | Value |
+——————-+——-+
| thread_cache_size | 0 |
+——————-+——-+
通過 Threads_cached 和 Threads_created 狀態變數來監控已快取的執行緒數和已建立的執行緒數。當系統有大量的連線時,根據Threads_created或Threads_connected狀態變數的值來適當調整執行緒快取的大小,以減少執行緒建立的開銷。
MySQL執行緒快取原理與連線池原理相似。
innodb_log_buffer_size: 這項配置決定了為尚未執行的事務分配的快取。
其實還有很多配置檔案裡的其他屬性,但是我們要學會用 show 去定位和檢視影響我們資料的到底是什麼原因,並且每次改的話最好只改一個配置項,這樣才能知道我們改的影響有多大。